001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.tagging.presets;
003
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.HashMap;
007import java.util.Map;
008
009import javax.swing.JMenu;
010import javax.swing.JMenuItem;
011import javax.swing.JSeparator;
012
013import org.openstreetmap.josm.Main;
014import org.openstreetmap.josm.data.osm.OsmPrimitive;
015import org.openstreetmap.josm.gui.MenuScroller;
016import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
017import org.openstreetmap.josm.tools.SubclassFilteredCollection;
018
019/**
020 * Class holding Tagging Presets and allowing to manage them.
021 * @since 7100
022 */
023public final class TaggingPresets {
024
025    /** The collection of tagging presets */
026    private static final Collection<TaggingPreset> taggingPresets = new ArrayList<>();
027
028    /** The collection of listeners */
029    private static final Collection<TaggingPresetListener> listeners = new ArrayList<>();
030
031    private TaggingPresets() {
032        // Hide constructor for utility classes
033    }
034
035    /**
036     * Initializes tagging presets from preferences.
037     */
038    public static void readFromPreferences() {
039        taggingPresets.clear();
040        taggingPresets.addAll(TaggingPresetReader.readFromPreferences(false, false));
041    }
042
043    /**
044     * Initialize the tagging presets (load and may display error)
045     */
046    public static void initialize() {
047        readFromPreferences();
048        for (TaggingPreset tp: taggingPresets) {
049            if (!(tp instanceof TaggingPresetSeparator)) {
050                Main.toolbar.register(tp);
051            }
052        }
053        if (taggingPresets.isEmpty()) {
054            Main.main.menu.presetsMenu.setVisible(false);
055        } else {
056            AutoCompletionManager.cachePresets(taggingPresets);
057            Map<TaggingPresetMenu, JMenu> submenus = new HashMap<>();
058            for (final TaggingPreset p : taggingPresets) {
059                JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
060                if (m == null && p.group != null) {
061                    Main.error("No tagging preset submenu for " + p.group);
062                } else if (m == null) {
063                    Main.error("No tagging preset menu. Tagging preset " + p + " won't be available there");
064                } else if (p instanceof TaggingPresetSeparator) {
065                    m.add(new JSeparator());
066                } else if (p instanceof TaggingPresetMenu) {
067                    JMenu submenu = new JMenu(p);
068                    submenu.setText(p.getLocaleName());
069                    ((TaggingPresetMenu) p).menu = submenu;
070                    submenus.put((TaggingPresetMenu) p, submenu);
071                    m.add(submenu);
072                } else {
073                    JMenuItem mi = new JMenuItem(p);
074                    mi.setText(p.getLocaleName());
075                    m.add(mi);
076                }
077            }
078            for (JMenu submenu : submenus.values()) {
079                if (submenu.getItemCount() >= Main.pref.getInteger("taggingpreset.min-elements-for-scroller", 15)) {
080                    MenuScroller.setScrollerFor(submenu);
081                }
082            }
083        }
084        if (Main.pref.getBoolean("taggingpreset.sortmenu")) {
085            TaggingPresetMenu.sortMenu(Main.main.menu.presetsMenu);
086        }
087    }
088
089    /**
090     * Replies a new collection containing all tagging presets.
091     * @return a new collection containing all tagging presets. Empty if presets are not initialized (never null)
092     */
093    public static Collection<TaggingPreset> getTaggingPresets() {
094        return new ArrayList<>(taggingPresets);
095    }
096
097    /**
098     * Replies a new collection of all presets matching the parameters.
099     *
100     * @param t the preset types to include
101     * @param tags the tags to perform matching on, see {@link TaggingPresetItem#matches(Map)}
102     * @param onlyShowable whether only {@link TaggingPreset#isShowable() showable} presets should be returned
103     * @return a new collection of all presets matching the parameters.
104     * @see TaggingPreset#matches(Collection, Map, boolean)
105     * @since 9266
106     */
107    public static Collection<TaggingPreset> getMatchingPresets(final Collection<TaggingPresetType> t,
108                                                               final Map<String, String> tags, final boolean onlyShowable) {
109        return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.matches(t, tags, onlyShowable));
110    }
111
112    /**
113     * Replies a new collection of all presets matching the given preset.
114     *
115     * @param primitive the primitive
116     * @return a new collection of all presets matching the given preset.
117     * @see TaggingPreset#test(OsmPrimitive)
118     * @since 9265
119     */
120    public static Collection<TaggingPreset> getMatchingPresets(final OsmPrimitive primitive) {
121        return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.test(primitive));
122    }
123
124    /**
125     * Adds a list of tagging presets to the current list.
126     * @param presets The tagging presets to add
127     */
128    public static void addTaggingPresets(Collection<TaggingPreset> presets) {
129        if (presets != null) {
130            if (taggingPresets.addAll(presets)) {
131                for (TaggingPresetListener listener : listeners) {
132                    listener.taggingPresetsModified();
133                }
134            }
135        }
136    }
137
138    /**
139     * Adds a tagging preset listener.
140     * @param listener The listener to add
141     */
142    public static void addListener(TaggingPresetListener listener) {
143        if (listener != null) {
144            listeners.add(listener);
145        }
146    }
147
148    /**
149     * Removes a tagging preset listener.
150     * @param listener The listener to remove
151     */
152    public static void removeListener(TaggingPresetListener listener) {
153        if (listener != null) {
154            listeners.remove(listener);
155        }
156    }
157}