| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.gui.tagging.presets;
|
|---|
| 3 |
|
|---|
| 4 | import java.util.ArrayList;
|
|---|
| 5 | import java.util.Collection;
|
|---|
| 6 | import java.util.Collections;
|
|---|
| 7 | import java.util.HashMap;
|
|---|
| 8 | import java.util.HashSet;
|
|---|
| 9 | import java.util.Map;
|
|---|
| 10 | import java.util.Set;
|
|---|
| 11 |
|
|---|
| 12 | import javax.swing.JMenu;
|
|---|
| 13 | import javax.swing.JMenuItem;
|
|---|
| 14 | import javax.swing.JSeparator;
|
|---|
| 15 |
|
|---|
| 16 | import org.openstreetmap.josm.Main;
|
|---|
| 17 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
|---|
| 18 | import org.openstreetmap.josm.gui.MainApplication;
|
|---|
| 19 | import org.openstreetmap.josm.gui.MenuScroller;
|
|---|
| 20 | import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
|
|---|
| 21 | import org.openstreetmap.josm.gui.tagging.presets.items.KeyedItem;
|
|---|
| 22 | import org.openstreetmap.josm.gui.tagging.presets.items.Roles;
|
|---|
| 23 | import org.openstreetmap.josm.gui.tagging.presets.items.Roles.Role;
|
|---|
| 24 | import org.openstreetmap.josm.tools.Logging;
|
|---|
| 25 | import org.openstreetmap.josm.tools.MultiMap;
|
|---|
| 26 | import org.openstreetmap.josm.tools.SubclassFilteredCollection;
|
|---|
| 27 |
|
|---|
| 28 | /**
|
|---|
| 29 | * Class holding Tagging Presets and allowing to manage them.
|
|---|
| 30 | * @since 7100
|
|---|
| 31 | */
|
|---|
| 32 | public final class TaggingPresets {
|
|---|
| 33 |
|
|---|
| 34 | /** The collection of tagging presets */
|
|---|
| 35 | private static final Collection<TaggingPreset> taggingPresets = new ArrayList<>();
|
|---|
| 36 |
|
|---|
| 37 | /** cache for key/value pairs found in the preset */
|
|---|
| 38 | private static final MultiMap<String, String> PRESET_TAG_CACHE = new MultiMap<>();
|
|---|
| 39 | /** cache for roles found in the preset */
|
|---|
| 40 | private static final Set<String> PRESET_ROLE_CACHE = new HashSet<>();
|
|---|
| 41 |
|
|---|
| 42 | /** The collection of listeners */
|
|---|
| 43 | private static final Collection<TaggingPresetListener> listeners = new ArrayList<>();
|
|---|
| 44 |
|
|---|
| 45 | private TaggingPresets() {
|
|---|
| 46 | // Hide constructor for utility classes
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | /**
|
|---|
| 50 | * Initializes tagging presets from preferences.
|
|---|
| 51 | */
|
|---|
| 52 | public static void readFromPreferences() {
|
|---|
| 53 | taggingPresets.clear();
|
|---|
| 54 | taggingPresets.addAll(TaggingPresetReader.readFromPreferences(false, false));
|
|---|
| 55 | cachePresets(taggingPresets);
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | /**
|
|---|
| 59 | * Initialize the tagging presets (load and may display error)
|
|---|
| 60 | */
|
|---|
| 61 | public static void initialize() {
|
|---|
| 62 | readFromPreferences();
|
|---|
| 63 | for (TaggingPreset tp: taggingPresets) {
|
|---|
| 64 | if (!(tp instanceof TaggingPresetSeparator)) {
|
|---|
| 65 | MainApplication.getToolbar().register(tp);
|
|---|
| 66 | }
|
|---|
| 67 | }
|
|---|
| 68 | if (taggingPresets.isEmpty()) {
|
|---|
| 69 | MainApplication.getMenu().presetsMenu.setVisible(false);
|
|---|
| 70 | } else {
|
|---|
| 71 | Map<TaggingPresetMenu, JMenu> submenus = new HashMap<>();
|
|---|
| 72 | for (final TaggingPreset p : taggingPresets) {
|
|---|
| 73 | JMenu m = p.group != null ? submenus.get(p.group) : MainApplication.getMenu().presetsMenu;
|
|---|
| 74 | if (m == null && p.group != null) {
|
|---|
| 75 | Logging.error("No tagging preset submenu for " + p.group);
|
|---|
| 76 | } else if (m == null) {
|
|---|
| 77 | Logging.error("No tagging preset menu. Tagging preset " + p + " won't be available there");
|
|---|
| 78 | } else if (p instanceof TaggingPresetSeparator) {
|
|---|
| 79 | m.add(new JSeparator());
|
|---|
| 80 | } else if (p instanceof TaggingPresetMenu) {
|
|---|
| 81 | JMenu submenu = new JMenu(p);
|
|---|
| 82 | submenu.setText(p.getLocaleName());
|
|---|
| 83 | ((TaggingPresetMenu) p).menu = submenu;
|
|---|
| 84 | submenus.put((TaggingPresetMenu) p, submenu);
|
|---|
| 85 | m.add(submenu);
|
|---|
| 86 | } else {
|
|---|
| 87 | JMenuItem mi = new JMenuItem(p);
|
|---|
| 88 | mi.setText(p.getLocaleName());
|
|---|
| 89 | m.add(mi);
|
|---|
| 90 | }
|
|---|
| 91 | }
|
|---|
| 92 | for (JMenu submenu : submenus.values()) {
|
|---|
| 93 | if (submenu.getItemCount() >= Main.pref.getInt("taggingpreset.min-elements-for-scroller", 15)) {
|
|---|
| 94 | MenuScroller.setScrollerFor(submenu);
|
|---|
| 95 | }
|
|---|
| 96 | }
|
|---|
| 97 | }
|
|---|
| 98 | if (Main.pref.getBoolean("taggingpreset.sortmenu")) {
|
|---|
| 99 | TaggingPresetMenu.sortMenu(MainApplication.getMenu().presetsMenu);
|
|---|
| 100 | }
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | /**
|
|---|
| 104 | * Initialize the cache for presets. This is done only once.
|
|---|
| 105 | * @param presets Tagging presets to cache
|
|---|
| 106 | */
|
|---|
| 107 | public static void cachePresets(Collection<TaggingPreset> presets) {
|
|---|
| 108 | for (final TaggingPreset p : presets) {
|
|---|
| 109 | for (TaggingPresetItem item : p.data) {
|
|---|
| 110 | cachePresetItem(p, item);
|
|---|
| 111 | }
|
|---|
| 112 | }
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | private static void cachePresetItem(TaggingPreset p, TaggingPresetItem item) {
|
|---|
| 116 | if (item instanceof KeyedItem) {
|
|---|
| 117 | KeyedItem ki = (KeyedItem) item;
|
|---|
| 118 | if (ki.key != null && ki.getValues() != null) {
|
|---|
| 119 | PRESET_TAG_CACHE.putAll(ki.key, ki.getValues());
|
|---|
| 120 | }
|
|---|
| 121 | } else if (item instanceof Roles) {
|
|---|
| 122 | Roles r = (Roles) item;
|
|---|
| 123 | for (Role i : r.roles) {
|
|---|
| 124 | if (i.key != null) {
|
|---|
| 125 | PRESET_ROLE_CACHE.add(i.key);
|
|---|
| 126 | }
|
|---|
| 127 | }
|
|---|
| 128 | } else if (item instanceof CheckGroup) {
|
|---|
| 129 | for (KeyedItem check : ((CheckGroup) item).checks) {
|
|---|
| 130 | cachePresetItem(p, check);
|
|---|
| 131 | }
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | /**
|
|---|
| 136 | * Replies a new collection containing all tagging presets.
|
|---|
| 137 | * @return a new collection containing all tagging presets. Empty if presets are not initialized (never null)
|
|---|
| 138 | */
|
|---|
| 139 | public static Collection<TaggingPreset> getTaggingPresets() {
|
|---|
| 140 | return Collections.unmodifiableCollection(taggingPresets);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | /**
|
|---|
| 144 | * Replies a set of all roles in the tagging presets.
|
|---|
| 145 | * @return a set of all roles in the tagging presets.
|
|---|
| 146 | */
|
|---|
| 147 | public static Set<String> getPresetRoles() {
|
|---|
| 148 | return Collections.unmodifiableSet(PRESET_ROLE_CACHE);
|
|---|
| 149 | }
|
|---|
| 150 |
|
|---|
| 151 | /**
|
|---|
| 152 | * Replies a set of all keys in the tagging presets.
|
|---|
| 153 | * @return a set of all keys in the tagging presets.
|
|---|
| 154 | */
|
|---|
| 155 | public static Set<String> getPresetKeys() {
|
|---|
| 156 | return Collections.unmodifiableSet(PRESET_TAG_CACHE.keySet());
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | /**
|
|---|
| 160 | * Return set of values for a key in the tagging presets
|
|---|
| 161 | * @param key the key
|
|---|
| 162 | * @return set of values for a key in the tagging presets or null if none is found
|
|---|
| 163 | */
|
|---|
| 164 | public static Set<String> getPresetValues(String key) {
|
|---|
| 165 | Set<String> values = PRESET_TAG_CACHE.get(key);
|
|---|
| 166 | if (values != null)
|
|---|
| 167 | return Collections.unmodifiableSet(values);
|
|---|
| 168 | return null;
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | /**
|
|---|
| 172 | * Replies a new collection of all presets matching the parameters.
|
|---|
| 173 | *
|
|---|
| 174 | * @param t the preset types to include
|
|---|
| 175 | * @param tags the tags to perform matching on, see {@link TaggingPresetItem#matches(Map)}
|
|---|
| 176 | * @param onlyShowable whether only {@link TaggingPreset#isShowable() showable} presets should be returned
|
|---|
| 177 | * @return a new collection of all presets matching the parameters.
|
|---|
| 178 | * @see TaggingPreset#matches(Collection, Map, boolean)
|
|---|
| 179 | * @since 9266
|
|---|
| 180 | */
|
|---|
| 181 | public static Collection<TaggingPreset> getMatchingPresets(final Collection<TaggingPresetType> t,
|
|---|
| 182 | final Map<String, String> tags, final boolean onlyShowable) {
|
|---|
| 183 | return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.matches(t, tags, onlyShowable));
|
|---|
| 184 | }
|
|---|
| 185 |
|
|---|
| 186 | /**
|
|---|
| 187 | * Replies a new collection of all presets matching the given preset.
|
|---|
| 188 | *
|
|---|
| 189 | * @param primitive the primitive
|
|---|
| 190 | * @return a new collection of all presets matching the given preset.
|
|---|
| 191 | * @see TaggingPreset#test(OsmPrimitive)
|
|---|
| 192 | * @since 9265
|
|---|
| 193 | */
|
|---|
| 194 | public static Collection<TaggingPreset> getMatchingPresets(final OsmPrimitive primitive) {
|
|---|
| 195 | return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.test(primitive));
|
|---|
| 196 | }
|
|---|
| 197 |
|
|---|
| 198 | /**
|
|---|
| 199 | * Adds a list of tagging presets to the current list.
|
|---|
| 200 | * @param presets The tagging presets to add
|
|---|
| 201 | */
|
|---|
| 202 | public static void addTaggingPresets(Collection<TaggingPreset> presets) {
|
|---|
| 203 | if (presets != null && taggingPresets.addAll(presets)) {
|
|---|
| 204 | for (TaggingPresetListener listener : listeners) {
|
|---|
| 205 | listener.taggingPresetsModified();
|
|---|
| 206 | }
|
|---|
| 207 | }
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 | /**
|
|---|
| 211 | * Adds a tagging preset listener.
|
|---|
| 212 | * @param listener The listener to add
|
|---|
| 213 | */
|
|---|
| 214 | public static void addListener(TaggingPresetListener listener) {
|
|---|
| 215 | if (listener != null) {
|
|---|
| 216 | listeners.add(listener);
|
|---|
| 217 | }
|
|---|
| 218 | }
|
|---|
| 219 |
|
|---|
| 220 | /**
|
|---|
| 221 | * Removes a tagging preset listener.
|
|---|
| 222 | * @param listener The listener to remove
|
|---|
| 223 | */
|
|---|
| 224 | public static void removeListener(TaggingPresetListener listener) {
|
|---|
| 225 | if (listener != null) {
|
|---|
| 226 | listeners.remove(listener);
|
|---|
| 227 | }
|
|---|
| 228 | }
|
|---|
| 229 | }
|
|---|