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