source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresets.java

Last change on this file was 18867, checked in by taylor.smock, 6 months ago

See #16567: Update to JUnit 5

This adds the @TaggingPresets annotation used by r18866 (see #23196). The
annotation tries to only initialize the presets when the current preset list does
not have the same hashCode as the default preset list. In order for this to work,
TaggingPresets#getTaggingPresets had to return a List (the method contract
has not changed), which calculates the hashCode in a deterministic manner.

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.tagging.presets;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14
15import javax.swing.JMenu;
16import javax.swing.JMenuItem;
17import javax.swing.JSeparator;
18
19import org.openstreetmap.josm.actions.PreferencesAction;
20import org.openstreetmap.josm.data.osm.IPrimitive;
21import org.openstreetmap.josm.data.preferences.BooleanProperty;
22import org.openstreetmap.josm.data.preferences.IntegerProperty;
23import org.openstreetmap.josm.data.preferences.ListProperty;
24import org.openstreetmap.josm.gui.MainApplication;
25import org.openstreetmap.josm.gui.MainMenu;
26import org.openstreetmap.josm.gui.MenuScroller;
27import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
28import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
29import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
30import org.openstreetmap.josm.gui.tagging.presets.items.KeyedItem;
31import org.openstreetmap.josm.gui.tagging.presets.items.Roles;
32import org.openstreetmap.josm.gui.tagging.presets.items.Roles.Role;
33import org.openstreetmap.josm.tools.Logging;
34import org.openstreetmap.josm.tools.MultiMap;
35import org.openstreetmap.josm.tools.SubclassFilteredCollection;
36
37/**
38 * Class holding Tagging Presets and allowing to manage them.
39 * @since 7100
40 */
41public final class TaggingPresets {
42
43 /** The collection of tagging presets */
44 private static final List<TaggingPreset> TAGGING_PRESETS = new ArrayList<>();
45
46 /** cache for key/value pairs found in the preset */
47 private static final MultiMap<String, String> PRESET_TAG_CACHE = new MultiMap<>();
48 /** cache for roles found in the preset */
49 private static final Set<String> PRESET_ROLE_CACHE = new HashSet<>();
50
51 /** The collection of listeners */
52 private static final Collection<TaggingPresetListener> listeners = new ArrayList<>();
53 /**
54 * Sort presets menu alphabetically
55 */
56 public static final BooleanProperty SORT_MENU = new BooleanProperty("taggingpreset.sortvalues", true);
57 /**
58 * Custom icon sources
59 */
60 public static final ListProperty ICON_SOURCES = new ListProperty("taggingpreset.icon.sources", null);
61 private static final IntegerProperty MIN_ELEMENTS_FOR_SCROLLER = new IntegerProperty("taggingpreset.min-elements-for-scroller", 15);
62
63 private TaggingPresets() {
64 // Hide constructor for utility classes
65 }
66
67 /**
68 * Initializes tagging presets from preferences.
69 */
70 public static void readFromPreferences() {
71 TAGGING_PRESETS.clear();
72 TAGGING_PRESETS.addAll(TaggingPresetReader.readFromPreferences(false, false));
73 cachePresets(TAGGING_PRESETS);
74 }
75
76 /**
77 * Initialize the tagging presets (load and may display error)
78 */
79 public static void initialize() {
80 MainMenu mainMenu = MainApplication.getMenu();
81 JMenu presetsMenu = mainMenu.presetsMenu;
82 if (presetsMenu.getComponentCount() == 0) {
83 MainMenu.add(presetsMenu, mainMenu.presetSearchAction);
84 MainMenu.add(presetsMenu, mainMenu.presetSearchPrimitiveAction);
85 MainMenu.add(presetsMenu, PreferencesAction.forPreferenceTab(tr("Preset preferences..."),
86 tr("Click to open the tagging presets tab in the preferences"), TaggingPresetPreference.class));
87 presetsMenu.addSeparator();
88 }
89
90 readFromPreferences();
91 final List<TaggingPreset> activeLayerChangeListeners = new ArrayList<>(TAGGING_PRESETS.size());
92 for (TaggingPreset tp: TAGGING_PRESETS) {
93 if (!(tp instanceof TaggingPresetSeparator)) {
94 MainApplication.getToolbar().register(tp);
95 activeLayerChangeListeners.add(tp);
96 }
97 }
98 MainApplication.getLayerManager().addActiveLayerChangeListeners(activeLayerChangeListeners);
99 if (TAGGING_PRESETS.isEmpty()) {
100 presetsMenu.setVisible(false);
101 } else {
102 Map<TaggingPresetMenu, JMenu> submenus = new HashMap<>();
103 for (final TaggingPreset p : TAGGING_PRESETS) {
104 JMenu m = p.group != null ? submenus.get(p.group) : presetsMenu;
105 if (m == null && p.group != null) {
106 Logging.error("No tagging preset submenu for " + p.group);
107 } else if (m == null) {
108 Logging.error("No tagging preset menu. Tagging preset " + p + " won't be available there");
109 } else if (p instanceof TaggingPresetSeparator) {
110 m.add(new JSeparator());
111 } else if (p instanceof TaggingPresetMenu) {
112 JMenu submenu = new JMenu(p);
113 submenu.setText(p.getLocaleName());
114 ((TaggingPresetMenu) p).menu = submenu;
115 submenus.put((TaggingPresetMenu) p, submenu);
116 m.add(submenu);
117 } else {
118 JMenuItem mi = new JMenuItem(p);
119 mi.setText(p.getLocaleName());
120 m.add(mi);
121 }
122 }
123 for (JMenu submenu : submenus.values()) {
124 if (submenu.getItemCount() >= MIN_ELEMENTS_FOR_SCROLLER.get()) {
125 MenuScroller.setScrollerFor(submenu);
126 }
127 }
128 }
129 if (Boolean.TRUE.equals(SORT_MENU.get())) {
130 TaggingPresetMenu.sortMenu(presetsMenu);
131 }
132 listeners.forEach(TaggingPresetListener::taggingPresetsModified);
133 }
134
135 // Cannot implement Destroyable since this is static
136 /**
137 * Call to deconstruct the TaggingPresets menus and other information so that it
138 * can be rebuilt later.
139 *
140 * @since 15582
141 */
142 public static void destroy() {
143 ToolbarPreferences toolBar = MainApplication.getToolbar();
144 for (TaggingPreset tp: TAGGING_PRESETS) {
145 toolBar.unregister(tp);
146 if (!(tp instanceof TaggingPresetSeparator)) {
147 MainApplication.getLayerManager().removeActiveLayerChangeListener(tp);
148 }
149 }
150 TAGGING_PRESETS.clear();
151 PRESET_TAG_CACHE.clear();
152 PRESET_ROLE_CACHE.clear();
153 MainApplication.getMenu().presetsMenu.removeAll();
154 }
155
156 /**
157 * Initialize the cache for presets. This is done only once.
158 * @param presets Tagging presets to cache
159 */
160 public static void cachePresets(Collection<TaggingPreset> presets) {
161 for (final TaggingPreset p : presets) {
162 for (TaggingPresetItem item : p.data) {
163 cachePresetItem(p, item);
164 }
165 }
166 }
167
168 private static void cachePresetItem(TaggingPreset p, TaggingPresetItem item) {
169 if (item instanceof KeyedItem) {
170 KeyedItem ki = (KeyedItem) item;
171 if (ki.key != null && ki.getValues() != null) {
172 PRESET_TAG_CACHE.putAll(ki.key, ki.getValues());
173 }
174 } else if (item instanceof Roles) {
175 Roles r = (Roles) item;
176 for (Role i : r.roles) {
177 if (i.key != null) {
178 PRESET_ROLE_CACHE.add(i.key);
179 }
180 }
181 } else if (item instanceof CheckGroup) {
182 for (KeyedItem check : ((CheckGroup) item).checks) {
183 cachePresetItem(p, check);
184 }
185 }
186 }
187
188 /**
189 * Replies a new collection containing all tagging presets.
190 * @return a new collection containing all tagging presets. Empty if presets are not initialized (never null)
191 */
192 public static Collection<TaggingPreset> getTaggingPresets() {
193 return Collections.unmodifiableList(TAGGING_PRESETS);
194 }
195
196 /**
197 * Replies a set of all roles in the tagging presets.
198 * @return a set of all roles in the tagging presets.
199 */
200 public static Set<String> getPresetRoles() {
201 return Collections.unmodifiableSet(PRESET_ROLE_CACHE);
202 }
203
204 /**
205 * Replies a set of all keys in the tagging presets.
206 * @return a set of all keys in the tagging presets.
207 */
208 public static Set<String> getPresetKeys() {
209 return Collections.unmodifiableSet(PRESET_TAG_CACHE.keySet());
210 }
211
212 /**
213 * Return set of values for a key in the tagging presets
214 * @param key the key
215 * @return set of values for a key in the tagging presets
216 */
217 public static Set<String> getPresetValues(String key) {
218 Set<String> values = PRESET_TAG_CACHE.get(key);
219 if (values != null)
220 return Collections.unmodifiableSet(values);
221 return Collections.emptySet();
222 }
223
224 /**
225 * Determines if the given key is in the loaded presets.
226 * @param key key
227 * @return {@code true} if the given key in the loaded presets
228 * @since 18281
229 */
230 public static boolean isKeyInPresets(String key) {
231 return PRESET_TAG_CACHE.get(key) != null;
232 }
233
234 /**
235 * Replies a new collection of all presets matching the parameters.
236 *
237 * @param t the preset types to include
238 * @param tags the tags to perform matching on, see {@link TaggingPresetItem#matches(Map)}
239 * @param onlyShowable whether only {@link TaggingPreset#isShowable() showable} presets should be returned
240 * @return a new collection of all presets matching the parameters.
241 * @see TaggingPreset#matches(Collection, Map, boolean)
242 * @since 9266
243 */
244 public static Collection<TaggingPreset> getMatchingPresets(final Collection<TaggingPresetType> t,
245 final Map<String, String> tags, final boolean onlyShowable) {
246 return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.matches(t, tags, onlyShowable));
247 }
248
249 /**
250 * Replies a new collection of all presets matching the given preset.
251 *
252 * @param primitive the primitive
253 * @return a new collection of all presets matching the given preset.
254 * @see TaggingPreset#test(IPrimitive)
255 * @since 13623 (signature)
256 */
257 public static Collection<TaggingPreset> getMatchingPresets(final IPrimitive primitive) {
258 return SubclassFilteredCollection.filter(getTaggingPresets(), preset -> preset.test(primitive));
259 }
260
261 /**
262 * Adds a list of tagging presets to the current list.
263 * @param presets The tagging presets to add
264 */
265 public static void addTaggingPresets(Collection<TaggingPreset> presets) {
266 if (presets != null && TAGGING_PRESETS.addAll(presets)) {
267 listeners.forEach(TaggingPresetListener::taggingPresetsModified);
268 }
269 }
270
271 /**
272 * Adds a tagging preset listener.
273 * @param listener The listener to add
274 */
275 public static void addListener(TaggingPresetListener listener) {
276 if (listener != null) {
277 listeners.add(listener);
278 }
279 }
280
281 /**
282 * Removes a tagging preset listener.
283 * @param listener The listener to remove
284 */
285 public static void removeListener(TaggingPresetListener listener) {
286 if (listener != null) {
287 listeners.remove(listener);
288 }
289 }
290}
Note: See TracBrowser for help on using the repository browser.