source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java@ 16417

Last change on this file since 16417 was 16417, checked in by simon04, 4 years ago

Fix typo in Javadoc

File size: 7.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.tagging.presets.items;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7import java.util.EnumSet;
8import java.util.HashMap;
9import java.util.Map;
10import java.util.NoSuchElementException;
11import java.util.SortedSet;
12import java.util.TreeSet;
13
14import javax.swing.JPopupMenu;
15
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.OsmUtils;
18import org.openstreetmap.josm.data.osm.Tag;
19import org.openstreetmap.josm.data.preferences.BooleanProperty;
20import org.openstreetmap.josm.gui.dialogs.properties.HelpTagAction;
21import org.openstreetmap.josm.gui.dialogs.properties.TaginfoAction;
22import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItem;
23
24/**
25 * Preset item associated to an OSM key.
26 */
27public abstract class KeyedItem extends TextItem {
28
29 /** Translation of "<different>". Use in combo boxes to display an entry matching several different values. */
30 protected static final String DIFFERENT = tr("<different>");
31
32 protected static final BooleanProperty PROP_FILL_DEFAULT = new BooleanProperty("taggingpreset.fill-default-for-tagged-primitives", false);
33
34 /** Last value of each key used in presets, used for prefilling corresponding fields */
35 static final Map<String, String> LAST_VALUES = new HashMap<>();
36
37 /** This specifies the property key that will be modified by the item. */
38 public String key; // NOSONAR
39 /**
40 * Allows to change the matching process, i.e., determining whether the tags of an OSM object fit into this preset.
41 * If a preset fits then it is linked in the Tags/Membership dialog.<ul>
42 * <li>none: neutral, i.e., do not consider this item for matching</li>
43 * <li>key: positive if key matches, neutral otherwise</li>
44 * <li>key!: positive if key matches, negative otherwise</li>
45 * <li>keyvalue: positive if key and value matches, neutral otherwise</li>
46 * <li>keyvalue!: positive if key and value matches, negative otherwise</li></ul>
47 * Note that for a match, at least one positive and no negative is required.
48 * Default is "keyvalue!" for {@link Key} and "none" for {@link Text}, {@link Combo}, {@link MultiSelect} and {@link Check}.
49 */
50 public String match = getDefaultMatch().getValue(); // NOSONAR
51
52 /**
53 * Enum denoting how a match (see {@link TaggingPresetItem#matches}) is performed.
54 */
55 protected enum MatchType {
56
57 /** Neutral, i.e., do not consider this item for matching. */
58 NONE("none"),
59 /** Positive if key matches, neutral otherwise. */
60 KEY("key"),
61 /** Positive if key matches, negative otherwise. */
62 KEY_REQUIRED("key!"),
63 /** Positive if key and value matches, neutral otherwise. */
64 KEY_VALUE("keyvalue"),
65 /** Positive if key and value matches, negative otherwise. */
66 KEY_VALUE_REQUIRED("keyvalue!");
67
68 private final String value;
69
70 MatchType(String value) {
71 this.value = value;
72 }
73
74 /**
75 * Replies the associated textual value.
76 * @return the associated textual value
77 */
78 public String getValue() {
79 return value;
80 }
81
82 /**
83 * Determines the {@code MatchType} for the given textual value.
84 * @param type the textual value
85 * @return the {@code MatchType} for the given textual value
86 */
87 public static MatchType ofString(String type) {
88 for (MatchType i : EnumSet.allOf(MatchType.class)) {
89 if (i.getValue().equals(type))
90 return i;
91 }
92 throw new IllegalArgumentException(type + " is not allowed");
93 }
94 }
95
96 /**
97 * Usage information on a key
98 */
99 protected static class Usage {
100 /**
101 * A set of values that were used for this key.
102 */
103 public final SortedSet<String> values = new TreeSet<>(); // NOSONAR
104 private boolean hadKeys;
105 private boolean hadEmpty;
106
107 /**
108 * Check if there is exactly one value for this key.
109 * @return <code>true</code> if there was exactly one value.
110 */
111 public boolean hasUniqueValue() {
112 return values.size() == 1 && !hadEmpty;
113 }
114
115 /**
116 * Check if this key was not used in any primitive
117 * @return <code>true</code> if it was unused.
118 */
119 public boolean unused() {
120 return values.isEmpty();
121 }
122
123 /**
124 * Get the first value available.
125 * @return The first value
126 * @throws NoSuchElementException if there is no such value.
127 */
128 public String getFirst() {
129 return values.first();
130 }
131
132 /**
133 * Check if we encountered any primitive that had any keys
134 * @return <code>true</code> if any of the primitives had any tags.
135 */
136 public boolean hadKeys() {
137 return hadKeys;
138 }
139 }
140
141 protected static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
142 Usage returnValue = new Usage();
143 for (OsmPrimitive s : sel) {
144 String v = s.get(key);
145 if (v != null) {
146 returnValue.values.add(v);
147 } else {
148 returnValue.hadEmpty = true;
149 }
150 if (s.hasKeys()) {
151 returnValue.hadKeys = true;
152 }
153 }
154 return returnValue;
155 }
156
157 protected static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
158 Usage returnValue = new Usage();
159 for (OsmPrimitive s : sel) {
160 String booleanValue = OsmUtils.getNamedOsmBoolean(s.get(key));
161 if (booleanValue != null) {
162 returnValue.values.add(booleanValue);
163 }
164 }
165 return returnValue;
166 }
167
168 /**
169 * Determines whether key or key+value are required.
170 * @return whether key or key+value are required
171 */
172 public boolean isKeyRequired() {
173 final MatchType type = MatchType.ofString(match);
174 return MatchType.KEY_REQUIRED == type || MatchType.KEY_VALUE_REQUIRED == type;
175 }
176
177 /**
178 * Returns the default match.
179 * @return the default match
180 */
181 public abstract MatchType getDefaultMatch();
182
183 /**
184 * Returns the list of values.
185 * @return the list of values
186 */
187 public abstract Collection<String> getValues();
188
189 protected String getKeyTooltipText() {
190 return tr("This corresponds to the key ''{0}''", key);
191 }
192
193 @Override
194 public Boolean matches(Map<String, String> tags) {
195 switch (MatchType.ofString(match)) {
196 case NONE:
197 return null;
198 case KEY:
199 return tags.containsKey(key) ? Boolean.TRUE : null;
200 case KEY_REQUIRED:
201 return tags.containsKey(key);
202 case KEY_VALUE:
203 return tags.containsKey(key) && getValues().contains(tags.get(key)) ? Boolean.TRUE : null;
204 case KEY_VALUE_REQUIRED:
205 return tags.containsKey(key) && getValues().contains(tags.get(key));
206 default:
207 throw new IllegalStateException();
208 }
209 }
210
211 protected JPopupMenu getPopupMenu() {
212 Tag tag = new Tag(key, null);
213 JPopupMenu popupMenu = new JPopupMenu();
214 popupMenu.add(tr("Key: {0}", key)).setEnabled(false);
215 popupMenu.add(new HelpTagAction(() -> tag));
216 popupMenu.add(new TaginfoAction(() -> tag, () -> null));
217 return popupMenu;
218 }
219
220 @Override
221 public String toString() {
222 return "KeyedItem [key=" + key + ", text=" + text
223 + ", text_context=" + text_context + ", match=" + match
224 + ']';
225 }
226}
Note: See TracBrowser for help on using the repository browser.