Index: resources/data/tagging-preset.xsd
===================================================================
--- resources/data/tagging-preset.xsd	(revision 18639)
+++ resources/data/tagging-preset.xsd	(working copy)
@@ -100,12 +100,19 @@
     <complexType name="group">
         <annotation>
             <documentation>
-                Used to group items in sub menus. name is required, icon is optional attribute.
+                Used to group items in sub menus. name is required, icon and sort are optional attributes.
             </documentation>
         </annotation>
         <complexContent>
             <extension base="tns:group-parent">
                 <attributeGroup ref="tns:attributes.name" />
+                <attribute name="sort" type="boolean">
+                	<annotation>
+		                <documentation>
+		                    If the items in the menu should be sorted or not. Defaults to true.
+		                </documentation>
+		            </annotation>
+                </attribute>
             </extension>
         </complexContent>
     </complexType>
@@ -234,6 +241,7 @@
             <element name="combo" type="tns:combo" />
             <element name="multiselect" type="tns:multiselect" />
             <element name="checkgroup" type="tns:checkgroup" />
+            <element name="selectgroup" type="tns:selectgroup" />
             <element name="check" type="tns:check" />
             <element name="item_separator" type="tns:separator" />
             <element name="reference" type="tns:reference" />
@@ -267,6 +275,14 @@
                 ]]></documentation>
             </annotation>
         </attribute>
+        <attribute name="prefix" type="string">
+	        <annotation>
+	            <documentation>
+	            	Text that will be put at the start of the resulting value if key is empty, it's not used for appending of existing values.
+	            </documentation>
+	        </annotation>
+        </attribute>
+        <attributeGroup ref="tns:attributes.append" />
         <attribute name="match" type="tns:match" />
     </complexType>
 
@@ -378,6 +394,7 @@
             </annotation>
         </attribute>
         <attributeGroup ref="tns:attributes.icon" />
+        <attribute name="delimiter" type="tns:values.delimiter" />
         <anyAttribute processContents="skip" />
     </complexType>
 
@@ -404,6 +421,7 @@
         <attributeGroup ref="tns:attributes.icon" />
         <attributeGroup ref="tns:attributes.values" />
         <attribute name="use_last_as_default" type="tns:last_default" />
+        <attribute name="if_needed_only" type="tns:if_needed_only" />
         <attribute name="editable" type="boolean">
             <annotation>
                 <documentation>
@@ -433,7 +451,21 @@
         <attributeGroup ref="tns:attributes.values" />
         <attribute name="use_last_as_default" type="tns:last_default" />
         <attribute name="match" type="tns:match" />
-
+		<attribute name="quick_select" type="boolean">
+			<annotation>
+	            <documentation>
+	                Allows to enable quick selection of list entries with just clicking on it, without the need to use keyboard. Default is false.
+	            </documentation>
+	        </annotation>
+		</attribute>        
+        <attribute name="prefix" type="string">
+	        <annotation>
+	            <documentation>
+	            	Text that will be put at the start of the resulting value. If values start with prefix, it will be remove from the value first.
+	            </documentation>
+	        </annotation>
+        </attribute>
+		
         <attribute name="type" use="prohibited" />
         <attribute name="value" use="prohibited" />
         <attribute name="name" use="prohibited" />
@@ -441,7 +473,7 @@
         <attribute name="display-values" use="prohibited" />
         <anyAttribute processContents="skip" />
     </complexType>
-
+    
     <complexType name="checkgroup">
         <annotation>
             <documentation>
@@ -462,6 +494,20 @@
         </attribute>
         <anyAttribute processContents="skip" />
     </complexType>
+    
+    <complexType name="selectgroup">
+        <annotation>
+            <documentation>
+                To group list_entries for multiselect. From all list_entries in a group only one can be selected at a time. 
+            </documentation>
+        </annotation>
+        <sequence>
+            <choice minOccurs="1" maxOccurs="unbounded">
+                <element name="list_entry" type="tns:list_entry" />
+            </choice>
+        </sequence>
+        <anyAttribute processContents="skip" />
+    </complexType>
 
     <complexType name="check">
         <attributeGroup ref="tns:attributes.key" />
@@ -502,6 +548,54 @@
             <enumeration value="off" />
         </restriction>
     </simpleType>
+    
+    <simpleType name="append">
+    	<annotation>
+            <documentation>
+                Specify if value should be appended to existing value. This defaults implicitly to default if append_value is provided.
+            </documentation>
+        </annotation>
+        <restriction base="string">
+            <enumeration value="default" />
+            <enumeration value="always" />
+        </restriction>
+    </simpleType>
+        
+    <simpleType name="values.delimiter">
+		 <annotation>
+                <documentation><![CDATA[
+                    The character that separates values. In case of <combo /> the default is comma. In case of <multiselect /> the default is semicolon and this will also be used to separate selected values in the tag.
+                ]]></documentation>
+          </annotation>
+          <restriction base="string">
+          	<minLength value="1"/>
+          	<maxLength value="1"/>
+          </restriction>
+    </simpleType>
+    
+    <simpleType name="append.delimiter">
+		 <annotation>
+                <documentation><![CDATA[
+                    The character that separates values for <key />. The default is semicolon and it's possible to provide an empty delimiter.
+                ]]></documentation>
+          </annotation>
+          <restriction base="string">
+          	<minLength value="0"/>
+          	<maxLength value="1"/>
+          </restriction>
+    </simpleType>
+    
+    <simpleType name="if_needed_only">
+        <annotation>
+            <documentation>
+                Show combo selection only if key is missing otherwise don't show it and retain current value.
+            </documentation>
+        </annotation>
+        <restriction base="string">
+            <enumeration value="true" />
+            <enumeration value="false" />
+        </restriction>
+    </simpleType>
 
     <simpleType name="last_default">
         <annotation>
@@ -588,9 +682,34 @@
             <enumeration value="optional" />
         </restriction>
     </simpleType>
+    
+    <simpleType name="sort_options">
+        <annotation>
+            <documentation>
+                Possible options for values_sort. Default is "true";
+            </documentation>
+        </annotation>
+        <restriction base="string">
+            <enumeration value="true" />
+            <enumeration value="false" />
+            <enumeration value="user" />
+        </restriction>
+    </simpleType>
 
     <!-- Types and documentation for attributes -->
 
+    <attributeGroup name="attributes.append">
+    	<attribute name="append_value" type="string">
+            <annotation>
+                <documentation><![CDATA[
+                    Specify a value to be appended to the <key> tag. Optional if this value should be used instead of value. The value is only appened if it doesn't already is set for <key> tag or if append=always was specified.
+                ]]></documentation>
+            </annotation>
+        </attribute>
+        <attribute name="append" type="tns:append" />
+        <attribute name="delimiter" type="tns:append.delimiter" />
+    </attributeGroup>
+
     <attributeGroup name="attributes.name">
         <attribute name="name" type="string" use="required">
             <annotation>
@@ -671,7 +790,7 @@
                 </documentation>
             </annotation>
         </attribute>
-        <attribute name="values_sort" type="boolean">
+        <attribute name="values_sort" type="tns:sort_options">
             <annotation>
                 <documentation>
                     Values of are sorted alphabetic in every language. With this attribute you can disable the alphabetic sorting if the values should keep the given order, see #5509 and #11926. (In the JOSM internal preset this is used e.g. for the keys tracktype, direction, network, smoothness, visibility or trail_visibility.) Default is "true".<br />
@@ -693,13 +812,7 @@
                 </documentation>
             </annotation>
         </attribute>
-        <attribute name="delimiter" type="string">
-            <annotation>
-                <documentation><![CDATA[
-                    The character that separates values. In case of <combo /> the default is comma. In case of <multiselect /> the default is semicolon and this will also be used to separate selected values in the tag.
-                ]]></documentation>
-            </annotation>
-        </attribute>
+        <attribute name="delimiter" type="tns:values.delimiter" />
     </attributeGroup>
 
     <attributeGroup name="attributes.icon">
Index: src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(working copy)
@@ -138,6 +138,11 @@
     public boolean preset_name_label;
 
     /**
+     * If menu items should be sorted
+     */
+    public boolean sort = true;
+
+    /**
      * The types as preparsed collection.
      */
     public transient Set<TaggingPresetType> types;
@@ -255,6 +260,15 @@
     }
 
     /**
+     * Called from the XML parser to set the sort option.
+     * @param sort If the resulting menu should contain sorted items.
+     * @since 18619
+     */
+    public void setSort(final boolean sort) {
+        this.sort = sort;
+    }
+
+    /**
      * Called from the XML parser to set the icon.
      * The loading task is performed in the background in order to speedup startup.
      * @param iconName icon name
Index: src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetMenu.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetMenu.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetMenu.java	(working copy)
@@ -128,6 +128,13 @@
      * @param menu menu to sort
      */
     public static void sortMenu(JMenu menu) {
+        Action a = menu.getAction();
+        boolean sort = true;
+
+        if(a instanceof TaggingPreset) {
+            sort = ((TaggingPreset) a).sort;
+        }
+
         Component[] items = menu.getMenuComponents();
         PresetTextComparator comp = new PresetTextComparator();
         List<JMenuItem> sortarray = new ArrayList<>();
@@ -137,17 +144,19 @@
             if (item instanceof JMenu) {
                 sortMenu((JMenu) item);
             }
-            if (item instanceof JMenuItem) {
-                sortarray.add((JMenuItem) item);
-                if (i == items.length-1) {
+            if(sort) {
+                if (item instanceof JMenuItem) {
+                    sortarray.add((JMenuItem) item);
+                    if (i == items.length-1) {
+                        handleMenuItem(menu, comp, sortarray, lastSeparator);
+                        sortarray = new ArrayList<>();
+                        lastSeparator = 0;
+                    }
+                } else if (item instanceof JSeparator) {
                     handleMenuItem(menu, comp, sortarray, lastSeparator);
                     sortarray = new ArrayList<>();
-                    lastSeparator = 0;
+                    lastSeparator = i;
                 }
-            } else if (item instanceof JSeparator) {
-                handleMenuItem(menu, comp, sortarray, lastSeparator);
-                sortarray = new ArrayList<>();
-                lastSeparator = i;
             }
         }
     }
Index: src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(working copy)
@@ -39,6 +39,7 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.PresetListEntry;
 import org.openstreetmap.josm.gui.tagging.presets.items.Roles;
 import org.openstreetmap.josm.gui.tagging.presets.items.Roles.Role;
+import org.openstreetmap.josm.gui.tagging.presets.items.SelectGroup;
 import org.openstreetmap.josm.gui.tagging.presets.items.Space;
 import org.openstreetmap.josm.gui.tagging.presets.items.Text;
 import org.openstreetmap.josm.io.CachedFile;
@@ -145,6 +146,7 @@
         parser.mapOnStart("roles", Roles.class);
         parser.map("role", Role.class);
         parser.mapBoth("checkgroup", CheckGroup.class);
+        parser.mapBoth("selectgroup", SelectGroup.class);
         parser.map("check", Check.class);
         parser.map("combo", Combo.class);
         parser.map("multiselect", MultiSelect.class);
@@ -182,6 +184,9 @@
 
         /** to detect end of {@code <checkgroup>} */
         CheckGroup lastcheckgroup = null;
+        /** to detect end of {@code <selectgroup>} */
+        SelectGroup lastselectgroup = null;
+        int selectgroupcount = PresetListEntry.SELECT_GROUP_NONE;
         /** to detect end of {@code <group>} */
         TaggingPresetMenu lastmenu = null;
         /** to detect end of reused {@code <group>} */
@@ -302,7 +307,9 @@
                             all.getLast().data.add((TaggingPresetItem) o);
                         }
                     } else if (o instanceof PresetListEntry) {
-                        listEntries.add((PresetListEntry) o);
+                        PresetListEntry entry = (PresetListEntry) o;
+                        entry.select_group = selectgroupcount;
+                        listEntries.add(entry);
                     } else if (o instanceof CheckGroup) {
                         CheckGroup cg = (CheckGroup) o;
                         if (cg == lastcheckgroup) {
@@ -316,6 +323,14 @@
                         } else {
                             lastcheckgroup = cg;
                         }
+                    } else if (o instanceof SelectGroup) {
+                        SelectGroup sg = (SelectGroup) o;
+                        if (sg == lastselectgroup) {
+                            lastselectgroup = null;
+                        } else {
+                            lastselectgroup = sg;
+                            selectgroupcount++;
+                        }
                     } else {
                         if (!checks.isEmpty()) {
                             all.getLast().data.addAll(checks);
@@ -329,6 +344,7 @@
                         }
                         listEntries.clear();
                         lastrole = null;
+                        selectgroupcount = PresetListEntry.SELECT_GROUP_NONE;
                     }
                 } else
                     throw new SAXException(tr("Preset sub element without parent"));
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/Combo.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/Combo.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/Combo.java	(working copy)
@@ -168,9 +168,12 @@
         combobox.setToolTipText(getKeyTooltipText());
         combobox.applyComponentOrientation(OrientationAction.getValueOrientation(key));
 
-        return true;
+
+        return isNeeded(usage);
     }
 
+
+
     /**
      * Finds the PresetListEntry that matches value.
      * <p>
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java	(working copy)
@@ -35,7 +35,7 @@
  * Abstract superclass for combo box and multi-select list types.
  */
 public abstract class ComboMultiSelect extends KeyedItem {
-
+    protected static final String VALUE_SORT_USER = "user";
     /**
      * A list of entries.
      * The list has to be separated by commas (for the {@link Combo} box) or by the specified delimiter (for the {@link MultiSelect}).
@@ -53,7 +53,10 @@
     /** Disabled internationalisation for value to avoid mistakes, see #11696 */
     public boolean values_no_i18n; // NOSONAR
     /** Whether to sort the values, defaults to true. */
-    public boolean values_sort = true; // NOSONAR
+    public String values_sort = String.valueOf(true); // NOSONAR
+    /** Whether to show this combo in dialog only when it's needed.
+     * It's needed when key doesn't exist or if current value is not in values */
+    public boolean if_needed_only = false; // NOSONAR
     /**
      * A list of entries that is displayed to the user.
      * Must be the same number and order of entries as {@link #values} and editable must be false or not specified.
@@ -138,6 +141,7 @@
                 // editor-ersatz of a readonly combobox. fixes #6157
                 l.setText(value.getListDisplay(width));
             }
+
             if (value.getCount() > 0) {
                 l.setFont(l.getFont().deriveFont(Font.ITALIC + Font.BOLD));
             }
@@ -310,7 +314,7 @@
             addListEntry(e);
         }
 
-        if (values_sort && TaggingPresets.SORT_MENU.get()) {
+        if (values_sort.equals(String.valueOf(true)) && TaggingPresets.SORT_MENU.get()) {
             Collections.sort(presetListEntries, (a, b) -> AlphanumComparator.getInstance().compare(a.getDisplayValue(), b.getDisplayValue()));
         }
     }
@@ -430,4 +434,20 @@
     public MatchType getDefaultMatch() {
         return MatchType.NONE;
     }
+
+    protected boolean isNeeded(Usage usage) {
+        boolean result = !if_needed_only || usage.unused();
+
+        if (!result) {
+            for (String v : usage.map.keySet()) {
+                for (PresetListEntry p : presetListEntries) {
+                    if (p.value.equals(v)) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
 }
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/Key.java	(working copy)
@@ -7,6 +7,7 @@
 
 import javax.swing.JPanel;
 
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
 
@@ -14,12 +15,55 @@
  * Invisible type allowing to hardcode an OSM key/value from the preset definition.
  */
 public class Key extends KeyedItem {
+    private static final String VALUE_APPEND_ALWAYS = "always";
 
     /** The hardcoded value for key */
     public String value; // NOSONAR
 
+    /** The hardcoded value for key appending existing value **/
+    public String append_value;  // NOSONAR
+
+    /** The hardcoded delimiter to use for appending values **/
+    public String delimiter = ";"; // NOSONAR
+
+    /** The hardcoded type of appending */
+    public String append = null; // NOSONAR
+
+    /** The hardcoded prefix to use for setting value to empty key */
+    public String prefix = null; // NOSONAR
+
+    private String useValue;
+
     @Override
     public boolean addToPanel(JPanel p, TaggingPresetItemGuiSupport support) {
+        if (prefix != null) {
+            useValue = prefix + value;
+        }
+        else {
+            useValue = value;
+        }
+
+        // If append_value is present append also if append was not set
+        if (append_value != null || append != null) {
+            String toUse = append_value != null ? append_value : value;
+
+            Collection<OsmPrimitive> col = support.getSelected();
+
+            for (OsmPrimitive pr : col) {
+                String currentValue = pr.get(key);
+
+                if (currentValue != null) {
+                    useValue = currentValue;
+
+                    if ((append != null && append.equals(VALUE_APPEND_ALWAYS)) || !useValue.contains(toUse)) {
+                        useValue += delimiter + toUse;
+                    }
+
+                    break;
+                }
+            }
+        }
+
         return false;
     }
 
@@ -33,7 +77,7 @@
      * @return the tag
      */
     public Tag asTag() {
-        return new Tag(key, value);
+        return new Tag(key, useValue != null ? useValue : value);
     }
 
     @Override
@@ -43,13 +87,13 @@
 
     @Override
     public Collection<String> getValues() {
-        return Collections.singleton(value);
+        return Collections.singleton(useValue != null ? useValue : value);
     }
 
     @Override
     public String toString() {
-        return "Key [key=" + key + ", value=" + value + ", text=" + text
-                + ", text_context=" + text_context + ", match=" + match
-                + ']';
+        return "Key [key=" + key + ", value=" + value + ", value_append=" + append_value
+                + ", text=" + text + ", text_context=" + text_context + ", match=" + match
+                + ", delimiter=" + delimiter + ']';
     }
 }
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/MultiSelect.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/MultiSelect.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/MultiSelect.java	(working copy)
@@ -1,40 +1,139 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.tagging.presets.items;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.awt.Dimension;
+import java.awt.GridBagLayout;
 import java.awt.Insets;
 import java.awt.Rectangle;
-import java.util.stream.Collectors;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 
 import javax.swing.DefaultListModel;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.JButton;
 import javax.swing.JLabel;
 import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
 
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
+import org.openstreetmap.josm.gui.util.ReorderableTableModel;
 import org.openstreetmap.josm.gui.widgets.OrientationAction;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
 
 /**
  * Multi-select list type.
  */
 public class MultiSelect extends ComboMultiSelect {
-
     /**
      * Number of rows to display (positive integer, optional).
      */
     public short rows; // NOSONAR
 
     /** The model for the JList */
-    protected final DefaultListModel<PresetListEntry> model = new DefaultListModel<>();
+    protected final PresetListModel model = new PresetListModel();
     /** The swing component */
     protected final JList<PresetListEntry> list = new JList<>(model);
 
+    /**
+     * Text that will be put in front of the resulting value.
+     */
+    public String prefix; // NOSONAR
+
+    /**
+     * If the entries in the list should be selected with clicking only.
+     */
+    public boolean quick_select = false;
+
+    /**
+     * Use selection model that selects/deselects values with single click.
+     * @since 18619
+     */
+    public MultiSelect() {
+        list.setSelectionModel(new SingleClickSelectionModel(list));
+    }
+
     private void addEntry(PresetListEntry entry) {
+        addEntry(entry, -1);
+    }
+
+    private void addEntry(PresetListEntry entry, int presetCount) {
+        if (prefix != null && entry.value.startsWith(prefix)) {
+            entry.value = entry.value.substring(prefix.length());
+        }
+
         if (!seenValues.containsKey(entry.value)) {
-            model.addElement(entry);
-            seenValues.put(entry.value, entry);
+            boolean add = true;
+
+            for (int i = 0; i < model.size(); i++) {
+                PresetListEntry test = model.get(i);
+
+                if (test.delimiter != null && entry.value.matches(".*\\\\{0}" + test.delimiter+".*")) {
+                    add = false;
+
+                    String[] parts = entry.value.split(test.delimiter,-1);
+
+                    for (int j = 0; j < parts.length; j++) {
+                        if (prefix != null && parts[j].startsWith(prefix)) {
+                            parts[j] = parts[j].substring(prefix.length());
+                        }
+                        addEntry(new PresetListEntry(parts[j], this, j == 0 ? String.valueOf(delimiter) : test.delimiter), presetCount);
+                    }
+
+                    break;
+                }
+            }
+
+            if (add) {
+                if (presetCount == -1) {
+                    model.addElement(entry);
+                }
+                else {
+                    model.insertElementAt(entry, model.getSize() - presetCount);
+                }
+                seenValues.put(entry.value, entry);
+            }
+        }
+    }
+
+    private void select(PresetListEntry entry) {
+        for (int i = 0; i < model.getSize(); i++) {
+            PresetListEntry test = model.get(i);
+
+            if (Objects.equals(test.value, entry.value)) {
+                int[] indices = model.getSelectedIndices();
+
+                if (indices != null && indices.length > 0 && indices[indices.length - 1] > i) {
+                    PresetListEntry removed = model.remove(i);
+                    model.add(indices[indices.length-1], removed);
+                    list.addSelectionInterval(indices[indices.length-1], indices[indices.length-1]);
+                }
+                else {
+                    list.addSelectionInterval(i, i);
+                }
+
+                if(usage != null && usage.map != null && !usage.map.containsKey(test.value)) {
+                    usage.map.put(test.value, 1);
+                }
+
+                break;
+            }
+            else if (test.delimiter != null && entry.value.matches(".*\\\\{0}" + test.delimiter+".*")) {
+                for (String part : entry.value.split(test.delimiter, -1)) {
+                    select(new PresetListEntry(part, this, test.delimiter));
+                }
+            }
         }
     }
 
@@ -53,22 +152,30 @@
         // Add values from the preset.
         presetListEntries.forEach(this::addEntry);
 
+        int count = model.getSize();
+
         // Add all values used in the selected primitives. This also adds custom values and makes
         // sure we won't lose them.
         usage = usage.splitValues(String.valueOf(delimiter));
         for (String value: usage.map.keySet()) {
-            addEntry(new PresetListEntry(value, this));
+            addEntry(new PresetListEntry(value, this), count);
         }
 
         // Select the values in the initial value.
         if (!initialValue.isEmpty() && !DIFFERENT.equals(initialValue)) {
+            if(prefix != null && initialValue.startsWith(prefix)) {
+                initialValue = initialValue.substring(prefix.length());
+            }
+
             for (String value : initialValue.split(String.valueOf(delimiter), -1)) {
                 PresetListEntry e = new PresetListEntry(value, this);
                 addEntry(e);
-                int i = model.indexOf(e);
-                list.addSelectionInterval(i, i);
+                select(e);
             }
         }
+        else if (default_ != null) {
+            select(new PresetListEntry(default_, this));
+        }
 
         ComboMultiSelectListCellRenderer renderer = new ComboMultiSelectListCellRenderer(list, list.getCellRenderer(), 200, key);
         list.setCellRenderer(renderer);
@@ -92,7 +199,41 @@
                 sp.setPreferredSize(new Dimension(r.width, r.height));
             }
         }
-        p.add(sp, GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
+
+        if(values_sort.equals(VALUE_SORT_USER)) {
+            final JButton up = new JButton(ImageProvider.get("dialogs", "up", ImageSizes.LARGEICON));
+            up.setToolTipText(tr("Move the currently selected members up"));
+            up.addActionListener(e -> {
+                model.moveUp();
+            });
+            final JButton down = new JButton(ImageProvider.get("dialogs", "down", ImageSizes.LARGEICON));
+            down.setToolTipText(tr("Move the currently selected members down"));
+            down.addActionListener(e -> {
+                model.moveDown();
+            });
+            up.setEnabled(model.canMoveUp());
+            down.setEnabled(model.canMoveDown());
+
+            list.addListSelectionListener(new ListSelectionListener() {
+                @Override
+                public void valueChanged(ListSelectionEvent e) {
+                    up.setEnabled(model.canMoveUp());
+                    down.setEnabled(model.canMoveDown());
+                }
+            });
+
+            JPanel content = new JPanel(new GridBagLayout());
+            content.add(sp, GBC.std(0,0).span(1, 4).fill());
+            content.add(GBC.glue(0, 1), GBC.std(1, 0).fill(GBC.VERTICAL));
+            content.add(up, GBC.std(1, 1));
+            content.add(down, GBC.std(1, 2));
+            content.add(GBC.glue(0, 1), GBC.std(1, 3).fill(GBC.VERTICAL));
+
+            p.add(content, GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
+        }
+        else {
+            p.add(sp, GBC.eol().fill(GBC.HORIZONTAL)); // NOSONAR
+        }
 
         list.addListSelectionListener(l -> support.fireItemValueModified(this, key, getSelectedItem().value));
         list.setToolTipText(getKeyTooltipText());
@@ -103,7 +244,106 @@
 
     @Override
     protected PresetListEntry getSelectedItem() {
-        return new PresetListEntry(list.getSelectedValuesList()
-            .stream().map(e -> e.value).distinct().sorted().collect(Collectors.joining(String.valueOf(delimiter))), this);
+         StringBuilder result = new StringBuilder();
+         List<PresetListEntry> temp = list.getSelectedValuesList();
+
+         if (!temp.isEmpty()) {
+             if (values_sort.equals(String.valueOf(true))) {
+                 Collections.sort(temp);
+             }
+
+             if (prefix != null) {
+                 result.append(prefix);
+             }
+
+             result.append(temp.get(0).value);
+
+             for (int i = 1; i < temp.size(); i++) {
+                 if (result.indexOf(temp.get(i).value) == -1) {
+                     result.append(temp.get(i).delimiter != null ? temp.get(i).delimiter : delimiter).append(temp.get(i).value);
+                 }
+             }
+         }
+
+         return new PresetListEntry(result.toString(), this);
+    }
+
+    private final class SingleClickSelectionModel extends DefaultListSelectionModel {
+        private boolean mousePressed;
+        private ListModel<PresetListEntry> model;
+
+        private SingleClickSelectionModel(JList<PresetListEntry> list) {
+            this.model = list.getModel();
+            list.addMouseListener(new MouseAdapter() {
+                @Override
+                public void mousePressed(MouseEvent e) {
+                    mousePressed = true;
+                }
+                @Override
+                public void mouseReleased(MouseEvent e) {
+                    mousePressed = false;
+                }
+            });
+        }
+
+        @Override
+        public void addSelectionInterval(int index0, int index1) {
+            removeSelectionForGroupAtIndex(index0);
+            super.addSelectionInterval(index0, index1);
+        }
+
+        private void removeSelectionForGroupAtIndex(int index) {
+            if(!isSelectedIndex(index)) {
+                int selectGroup = model.getElementAt(index).select_group;
+
+                if(selectGroup != PresetListEntry.SELECT_GROUP_NONE) {
+                    for(int i = 0; i < model.getSize(); i++) {
+                        if(isSelectedIndex(i) && model.getElementAt(i).select_group == selectGroup) {
+                            super.removeSelectionInterval(i, i);
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void setSelectionInterval(int index0, int index1) {
+            if (quick_select && getSelectionMode() == MULTIPLE_INTERVAL_SELECTION) {
+                if (!mousePressed) {
+                    if (isSelectedIndex(index0)) {
+                        super.removeSelectionInterval(index0, index1);
+                    }
+                    else {
+                        removeSelectionForGroupAtIndex(index0);
+                        super.addSelectionInterval(index0, index1);
+                    }
+                }
+            }
+            else {
+                super.setSelectionInterval(index0, index1);
+            }
+        }
+    }
+
+    private final class PresetListModel extends DefaultListModel<PresetListEntry> implements ReorderableTableModel<PresetListEntry> {
+        @Override
+        public PresetListEntry getValue(int index) {
+            return get(index);
+        }
+
+        @Override
+        public PresetListEntry setValue(int index, PresetListEntry value) {
+            return set(index, value);
+        }
+
+        @Override
+        public ListSelectionModel getSelectionModel() {
+            return list.getSelectionModel();
+        }
+
+        @Override
+        public int getRowCount() {
+            return size();
+        }
     }
 }
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java	(revision 18639)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java	(working copy)
@@ -21,6 +21,8 @@
  * {@link MultiSelect}.
  */
 public class PresetListEntry implements Comparable<PresetListEntry> {
+    /** Value for entries without a select group*/
+    public static final int SELECT_GROUP_NONE = -1;
     /** Used to display an entry matching several different values. */
     protected static final PresetListEntry ENTRY_DIFFERENT = new PresetListEntry(KeyedItem.DIFFERENT, null);
     /** Used to display an empty entry used to clear values. */
@@ -46,11 +48,16 @@
     public String locale_display_value; // NOSONAR
     /** The localized version of {@link #short_description}. */
     public String locale_short_description; // NOSONAR
+    /** The delimiter for separating this entry from the previous */
+    public String delimiter; // NOSONAR
+    /** The select group for multi select */
+    public int select_group = SELECT_GROUP_NONE;
 
     private String cachedDisplayValue;
     private String cachedShortDescription;
     private ImageIcon cachedIcon;
 
+
     /**
      * Constructs a new {@code PresetListEntry}, uninitialized.
      *
@@ -67,8 +74,22 @@
      * @param cms the ComboMultiSelect
      */
     public PresetListEntry(String value, ComboMultiSelect cms) {
+        this(value, cms, null);
+    }
+
+    /**
+     * Constructs a new {@code PresetListEntry}, initialized with a value and
+     * {@link ComboMultiSelect} context and the delimiter for this entry.
+     *
+     * @param value value
+     * @param cms the ComboMultiSelect
+     * @param delimiter The character to use to separate this entry from the previous
+     * @since 18619
+     */
+    public PresetListEntry(String value, ComboMultiSelect cms, String delimiter) {
         this.value = value;
         this.cms = cms;
+        this.delimiter = delimiter;
     }
 
     /**
Index: src/org/openstreetmap/josm/gui/tagging/presets/items/SelectGroup.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/items/SelectGroup.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/tagging/presets/items/SelectGroup.java	(working copy)
@@ -0,0 +1,30 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.presets.items;
+
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItem;
+import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
+
+/**
+ * A group of {@link PresetListEntry}s.
+ * @since 18637
+ */
+public class SelectGroup extends TaggingPresetItem {
+
+    @Override
+    protected boolean addToPanel(JPanel p, TaggingPresetItemGuiSupport support) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    protected void addCommands(List<Tag> changedTags) {
+        // TODO Auto-generated method stub
+
+    }
+
+}

Property changes on: src/org/openstreetmap/josm/gui/tagging/presets/items/SelectGroup.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
