Index: trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionItem.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionItem.java (revision 12859)
+++ trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionItem.java (revision 12859)
@@ -0,0 +1,140 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.tagging.ac;
+
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * Represents an entry in the set of auto completion values.
+ *
+ * An AutoCompletionItem has a priority and a value.
+ *
+ * The priority helps to sort the auto completion items according to their importance. For instance,
+ * in an auto completion set for tag names, standard tag names would be assigned a higher
+ * priority than arbitrary tag names present in the current data set. There are three priority levels,
+ * {@link AutoCompletionPriority}.
+ *
+ * The value is a string which will be displayed in the auto completion list.
+ * @since 12859 (copied from {@code gui.tagging.ac.AutoCompletionListItem})
+ */
+public class AutoCompletionItem implements Comparable {
+
+ /** the priority of this item */
+ private AutoCompletionPriority priority;
+ /** the value of this item */
+ private String value;
+
+ /**
+ * Constructs a new {@code AutoCompletionItem} with the given value and priority.
+ * @param value The value
+ * @param priority The priority
+ */
+ public AutoCompletionItem(String value, AutoCompletionPriority priority) {
+ this.value = value;
+ this.priority = priority;
+ }
+
+ /**
+ * Constructs a new {@code AutoCompletionItem} with the given value and unknown priority.
+ * @param value The value
+ */
+ public AutoCompletionItem(String value) {
+ this.value = value;
+ priority = AutoCompletionPriority.UNKNOWN;
+ }
+
+ /**
+ * Constructs a new {@code AutoCompletionItem}.
+ */
+ public AutoCompletionItem() {
+ value = "";
+ priority = AutoCompletionPriority.UNKNOWN;
+ }
+
+ /**
+ * Returns the priority.
+ * @return the priority
+ */
+ public AutoCompletionPriority getPriority() {
+ return priority;
+ }
+
+ /**
+ * Sets the priority.
+ * @param priority the priority
+ */
+ public void setPriority(AutoCompletionPriority priority) {
+ this.priority = priority;
+ }
+
+ /**
+ * Returns the value.
+ * @return the value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * sets the value
+ * @param value the value; must not be null
+ * @throws IllegalArgumentException if value if null
+ */
+ public void setValue(String value) {
+ CheckParameterUtil.ensureParameterNotNull(value, "value");
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("');
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((priority == null) ? 0 : priority.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (obj instanceof String)
+ return obj.equals(value);
+ if (getClass() != obj.getClass())
+ return false;
+ final AutoCompletionItem other = (AutoCompletionItem) obj;
+ if (priority == null) {
+ if (other.priority != null)
+ return false;
+ } else if (!priority.equals(other.priority))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int compareTo(AutoCompletionItem other) {
+ int ret = other.priority.compareTo(priority); // higher priority items come first in the list
+ if (ret != 0)
+ return ret;
+ else
+ return this.value.compareTo(other.value);
+ }
+}
Index: trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionPriority.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionPriority.java (revision 12859)
+++ trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionPriority.java (revision 12859)
@@ -0,0 +1,173 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.tagging.ac;
+
+import java.util.Objects;
+
+/**
+ * Describes the priority of an item in an autocompletion set.
+ * The selected flag is currently only used in plugins.
+ *
+ * Instances of this class are not modifiable.
+ * @since 12859 (copied from {@code gui.tagging.ac.AutoCompletionItemPriority})
+ */
+public class AutoCompletionPriority implements Comparable {
+
+ /**
+ * Indicates, that the value is standard and it is found in the data.
+ * This has higher priority than some arbitrary standard value that is
+ * usually not used by the user.
+ */
+ public static final AutoCompletionPriority IS_IN_STANDARD_AND_IN_DATASET = new AutoCompletionPriority(true, true, false);
+
+ /**
+ * Indicates that this is an arbitrary value from the data set, i.e.
+ * the value of a tag name=*.
+ */
+ public static final AutoCompletionPriority IS_IN_DATASET = new AutoCompletionPriority(true, false, false);
+
+ /**
+ * Indicates that this is a standard value, i.e. a standard tag name
+ * or a standard value for a given tag name (from the presets).
+ */
+ public static final AutoCompletionPriority IS_IN_STANDARD = new AutoCompletionPriority(false, true, false);
+
+ /**
+ * Indicates that this is a value from a selected object.
+ */
+ public static final AutoCompletionPriority IS_IN_SELECTION = new AutoCompletionPriority(false, false, true);
+
+ /** Unknown priority. This is the lowest priority. */
+ public static final AutoCompletionPriority UNKNOWN = new AutoCompletionPriority(false, false, false);
+
+ private static final int NO_USER_INPUT = Integer.MAX_VALUE;
+
+ private final int userInput;
+ private final boolean inDataSet;
+ private final boolean inStandard;
+ private final boolean selected;
+
+ /**
+ * Constructs a new {@code AutoCompletionItemPriority}.
+ *
+ * @param inDataSet true, if the item is found in the currently active data layer
+ * @param inStandard true, if the item is a standard tag, e.g. from the presets
+ * @param selected true, if it is found on an object that is currently selected
+ * @param userInput null, if the user hasn't entered this tag so far. A number when
+ * the tag key / value has been entered by the user before. A lower number means
+ * this happened more recently and beats a higher number in priority.
+ */
+ public AutoCompletionPriority(boolean inDataSet, boolean inStandard, boolean selected, Integer userInput) {
+ this.inDataSet = inDataSet;
+ this.inStandard = inStandard;
+ this.selected = selected;
+ this.userInput = userInput == null ? NO_USER_INPUT : userInput;
+ }
+
+ /**
+ * Constructs a new {@code AutoCompletionItemPriority}.
+ *
+ * @param inDataSet true, if the item is found in the currently active data layer
+ * @param inStandard true, if the item is a standard tag, e.g. from the presets
+ * @param selected true, if it is found on an object that is currently selected
+ */
+ public AutoCompletionPriority(boolean inDataSet, boolean inStandard, boolean selected) {
+ this(inDataSet, inStandard, selected, NO_USER_INPUT);
+ }
+
+ /**
+ * Determines if the item is found in the currently active data layer.
+ * @return {@code true} if the item is found in the currently active data layer
+ */
+ public boolean isInDataSet() {
+ return inDataSet;
+ }
+
+ /**
+ * Determines if the item is a standard tag, e.g. from the presets.
+ * @return {@code true} if the item is a standard tag, e.g. from the presets
+ */
+ public boolean isInStandard() {
+ return inStandard;
+ }
+
+ /**
+ * Determines if it is found on an object that is currently selected.
+ * @return {@code true} if it is found on an object that is currently selected
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Returns a number when the tag key / value has been entered by the user before.
+ * A lower number means this happened more recently and beats a higher number in priority.
+ * @return a number when the tag key / value has been entered by the user before.
+ * {@code null}, if the user hasn't entered this tag so far.
+ */
+ public Integer getUserInput() {
+ return userInput == NO_USER_INPUT ? null : userInput;
+ }
+
+ /**
+ * Imposes an ordering on the priorities.
+ * Currently, being in the current DataSet is worth more than being in the Presets.
+ */
+ @Override
+ public int compareTo(AutoCompletionPriority other) {
+ int ui = Integer.compare(other.userInput, userInput);
+ if (ui != 0)
+ return ui;
+
+ int sel = Boolean.compare(selected, other.selected);
+ if (sel != 0)
+ return sel;
+
+ int ds = Boolean.compare(inDataSet, other.inDataSet);
+ if (ds != 0)
+ return ds;
+
+ int std = Boolean.compare(inStandard, other.inStandard);
+ if (std != 0)
+ return std;
+
+ return 0;
+ }
+
+ /**
+ * Merges two priorities.
+ * The resulting priority is always >= the original ones.
+ * @param other other priority
+ * @return the merged priority
+ */
+ public AutoCompletionPriority mergeWith(AutoCompletionPriority other) {
+ return new AutoCompletionPriority(
+ inDataSet || other.inDataSet,
+ inStandard || other.inStandard,
+ selected || other.selected,
+ Math.min(userInput, other.userInput));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(inDataSet, inStandard, selected, userInput);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ AutoCompletionPriority other = (AutoCompletionPriority) obj;
+ return inDataSet == other.inDataSet &&
+ inStandard == other.inStandard &&
+ selected == other.selected &&
+ userInput == other.userInput;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("",
+ userInput == NO_USER_INPUT ? "no" : Integer.toString(userInput), inDataSet, inStandard, selected);
+ }
+}
Index: trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionSet.java (revision 12859)
+++ trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionSet.java (revision 12859)
@@ -0,0 +1,86 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.tagging.ac;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+/**
+ * A sorted set of {@link AutoCompletionItem}s.
+ *
+ * Items are sorted with higher priority first, then according to lexicographic order
+ * on the value of the {@code AutoCompletionListItem}.
+ *
+ * @since 12859 (extracted from {@code gui.tagging.ac.AutoCompletionList})
+ */
+public class AutoCompletionSet extends TreeSet {
+
+ @Override
+ public boolean add(AutoCompletionItem e) {
+ // Is there already an item for the value?
+ Optional result = stream().filter(i -> i.getValue().equals(e.getValue())).findFirst();
+ if (result.isPresent()) {
+ AutoCompletionItem item = result.get();
+ // yes: merge priorities
+ AutoCompletionPriority newPriority = item.getPriority().mergeWith(e.getPriority());
+ // if needed, remove/re-add the updated item to maintain set ordering
+ if (!item.getPriority().equals(newPriority)) {
+ remove(item);
+ item.setPriority(newPriority);
+ return add(item);
+ } else {
+ return false;
+ }
+ } else {
+ return super.add(e);
+ }
+ }
+
+ /**
+ * Adds a list of strings to this list. Only strings which
+ * are not null and which do not exist yet in the list are added.
+ *
+ * @param values a list of strings to add
+ * @param priority the priority to use
+ * @return {@code true} if this set changed as a result of the call
+ */
+ public boolean addAll(Collection values, AutoCompletionPriority priority) {
+ return addAll(values.stream().filter(v -> v != null).map(v -> new AutoCompletionItem(v, priority)).collect(Collectors.toList()));
+ }
+
+ /**
+ * Adds values that have been entered by the user.
+ * @param values values that have been entered by the user
+ * @return {@code true} if this set changed as a result of the call
+ */
+ public boolean addUserInput(Collection values) {
+ int i = 0;
+ boolean modified = false;
+ for (String value : values) {
+ if (value != null && add(new AutoCompletionItem(value, new AutoCompletionPriority(false, false, false, i++)))) {
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Checks whether an item with the given value is already in the list. Ignores priority of the items.
+ *
+ * @param value the value of an auto completion item
+ * @return true, if value is in the list; false, otherwise
+ */
+ public boolean contains(String value) {
+ return stream().anyMatch(i -> i.getValue().equals(value));
+ }
+
+ /**
+ * Removes the auto completion item with key key
+ * @param key the key
+ * @return {@code true} if an element was removed
+ */
+ public boolean remove(String key) {
+ return removeIf(i -> i.getValue().equals(key));
+ }
+}
Index: trunk/src/org/openstreetmap/josm/data/tagging/ac/package-info.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/tagging/ac/package-info.java (revision 12859)
+++ trunk/src/org/openstreetmap/josm/data/tagging/ac/package-info.java (revision 12859)
@@ -0,0 +1,6 @@
+// License: GPL. For details, see LICENSE file.
+
+/**
+ * Provides classes for handling autocompletion of tags.
+ */
+package org.openstreetmap.josm.data.tagging.ac;