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

Last change on this file since 12042 was 12042, checked in by bastiK, 7 years ago

applied #13956 - memory optimization with presets cache (patch by GerdP)

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