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.List;
007import java.util.Map;
008
009import org.openstreetmap.josm.data.osm.Tag;
010import org.openstreetmap.josm.data.osm.search.SearchCompiler;
011import org.openstreetmap.josm.data.osm.search.SearchParseError;
012import org.openstreetmap.josm.data.osm.search.SearchSetting;
013import org.openstreetmap.josm.data.preferences.ListProperty;
014import org.openstreetmap.josm.gui.util.LruCache;
015import org.openstreetmap.josm.tools.Logging;
016
017/**
018 * Manages list of recently used tags that will be displayed in the {@link PropertiesDialog}.
019 */
020class RecentTagCollection {
021
022    private final Map<Tag, Void> recentTags;
023    private SearchCompiler.Match tagsToIgnore;
024
025    RecentTagCollection(final int capacity) {
026        recentTags = new LruCache<>(capacity);
027        tagsToIgnore = SearchCompiler.Never.INSTANCE;
028    }
029
030    public void loadFromPreference(ListProperty property) {
031        recentTags.clear();
032        List<String> list = property.get();
033        Iterator<String> it = list.iterator();
034        while (it.hasNext()) {
035            String key = it.next();
036            if (it.hasNext()) {
037                String value = it.next();
038                add(new Tag(key, value));
039            } else {
040                Logging.error("Invalid or incomplete list property: " + list);
041                break;
042            }
043        }
044    }
045
046    public void saveToPreference(ListProperty property) {
047        List<String> c = new ArrayList<>(recentTags.size() * 2);
048        for (Tag t : recentTags.keySet()) {
049            c.add(t.getKey());
050            c.add(t.getValue());
051        }
052        property.put(c);
053    }
054
055    public void add(Tag tag) {
056        if (!tagsToIgnore.match(tag)) {
057            recentTags.put(tag, null);
058        }
059    }
060
061    public boolean isEmpty() {
062        return recentTags.isEmpty();
063    }
064
065    public List<Tag> toList() {
066        return new ArrayList<>(recentTags.keySet());
067    }
068
069    public void setTagsToIgnore(SearchCompiler.Match tagsToIgnore) {
070        this.tagsToIgnore = tagsToIgnore;
071        recentTags.keySet().removeIf(tagsToIgnore::match);
072    }
073
074    public void setTagsToIgnore(SearchSetting tagsToIgnore) throws SearchParseError {
075        setTagsToIgnore(tagsToIgnore.text.isEmpty() ? SearchCompiler.Never.INSTANCE : SearchCompiler.compile(tagsToIgnore));
076    }
077
078    public SearchSetting ignoreTag(Tag tagToIgnore, SearchSetting settingToUpdate) throws SearchParseError {
079        final String forTag = SearchCompiler.buildSearchStringForTag(tagToIgnore.getKey(), tagToIgnore.getValue());
080        settingToUpdate.text = settingToUpdate.text.isEmpty()
081                ? forTag
082                : settingToUpdate.text + " OR " + forTag;
083        setTagsToIgnore(settingToUpdate);
084        return settingToUpdate;
085    }
086}