001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.properties; 003 004import java.util.ArrayList; 005import java.util.Iterator; 006import java.util.LinkedHashMap; 007import java.util.List; 008import java.util.Map; 009 010import org.openstreetmap.josm.actions.search.SearchAction; 011import org.openstreetmap.josm.actions.search.SearchCompiler; 012import org.openstreetmap.josm.data.osm.Tag; 013import org.openstreetmap.josm.data.preferences.CollectionProperty; 014 015class RecentTagCollection { 016 017 /** 018 * LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html) 019 */ 020 static final class LruCache extends LinkedHashMap<Tag, Void> { 021 private final int capacity; 022 023 LruCache(int capacity) { 024 super(capacity + 1, 1.1f, true); 025 this.capacity = capacity; 026 } 027 028 @Override 029 protected boolean removeEldestEntry(Map.Entry<Tag, Void> eldest) { 030 return size() > capacity; 031 } 032 } 033 034 private final Map<Tag, Void> recentTags; 035 private SearchCompiler.Match tagsToIgnore; 036 037 RecentTagCollection(final int capacity) { 038 recentTags = new LruCache(capacity); 039 tagsToIgnore = SearchCompiler.Never.INSTANCE; 040 } 041 042 public void loadFromPreference(CollectionProperty property) { 043 recentTags.clear(); 044 Iterator<String> it = property.get().iterator(); 045 while (it.hasNext()) { 046 String key = it.next(); 047 String value = it.next(); 048 add(new Tag(key, value)); 049 } 050 } 051 052 public void saveToPreference(CollectionProperty property) { 053 List<String> c = new ArrayList<>(recentTags.size() * 2); 054 for (Tag t : recentTags.keySet()) { 055 c.add(t.getKey()); 056 c.add(t.getValue()); 057 } 058 property.put(c); 059 } 060 061 public void add(Tag tag) { 062 if (!tagsToIgnore.match(tag)) { 063 recentTags.put(tag, null); 064 } 065 } 066 067 public boolean isEmpty() { 068 return recentTags.isEmpty(); 069 } 070 071 public List<Tag> toList() { 072 return new ArrayList<>(recentTags.keySet()); 073 } 074 075 public void setTagsToIgnore(SearchCompiler.Match tagsToIgnore) { 076 this.tagsToIgnore = tagsToIgnore; 077 recentTags.keySet().removeIf(tagsToIgnore::match); 078 } 079 080 public void setTagsToIgnore(SearchAction.SearchSetting tagsToIgnore) throws SearchCompiler.ParseError { 081 setTagsToIgnore(tagsToIgnore.text.isEmpty() ? SearchCompiler.Never.INSTANCE : SearchCompiler.compile(tagsToIgnore)); 082 } 083 084 public SearchAction.SearchSetting ignoreTag(Tag tagToIgnore, SearchAction.SearchSetting settingToUpdate) throws SearchCompiler.ParseError { 085 final String forTag = SearchCompiler.buildSearchStringForTag(tagToIgnore.getKey(), tagToIgnore.getValue()); 086 settingToUpdate.text = settingToUpdate.text.isEmpty() 087 ? forTag 088 : settingToUpdate.text + " OR " + forTag; 089 setTagsToIgnore(settingToUpdate); 090 return settingToUpdate; 091 } 092}