Changeset 6068 in josm for trunk/src/org/openstreetmap/josm


Ignore:
Timestamp:
2013-07-16T21:38:36+02:00 (11 years ago)
Author:
akks
Message:

see #8853: Massive (and dumb) refactoring of TaggingPreset class (splitting into smaller files)
Separate preset-choosing panel (TaggingPresetSelector class) for reuse not only in F3.

Location:
trunk/src/org/openstreetmap/josm
Files:
5 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/RelationChecker.java

    r6062 r6068  
    2525import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
    2626import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    27 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
     27import org.openstreetmap.josm.gui.tagging.TaggingPresetItem;
     28import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Role;
     29import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Key;
     30import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Roles;
     31import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    2832
    2933/**
     
    6569        if (presets != null) {
    6670            for (TaggingPreset p : presets) {
    67                 for (TaggingPreset.Item i : p.data) {
    68                     if (i instanceof TaggingPreset.Roles) {
     71                for (TaggingPresetItem i : p.data) {
     72                    if (i instanceof Roles) {
    6973                        relationpresets.add(p);
    7074                        break;
     
    8690    @Override
    8791    public void visit(Relation n) {
    88         LinkedList<TaggingPreset.Role> allroles = new LinkedList<TaggingPreset.Role>();
     92        LinkedList<Role> allroles = new LinkedList<Role>();
    8993        for (TaggingPreset p : relationpresets) {
    9094            boolean matches = true;
    91             TaggingPreset.Roles r = null;
    92             for (TaggingPreset.Item i : p.data) {
    93                 if (i instanceof TaggingPreset.Key) {
    94                     TaggingPreset.Key k = (TaggingPreset.Key) i;
     95            Roles r = null;
     96            for (TaggingPresetItem i : p.data) {
     97                if (i instanceof Key) {
     98                    Key k = (Key) i;
    9599                    if (!k.value.equals(n.get(k.key))) {
    96100                        matches = false;
    97101                        break;
    98102                    }
    99                 } else if (i instanceof TaggingPreset.Roles) {
    100                     r = (TaggingPreset.Roles) i;
     103                } else if (i instanceof Roles) {
     104                    r = (Roles) i;
    101105                }
    102106            }
     
    140144            } else {
    141145                LinkedList<String> done = new LinkedList<String>();
    142                 for (TaggingPreset.Role r : allroles) {
     146                for (Role r : allroles) {
    143147                    done.add(r.key);
    144148                    String keyname = r.key;
     
    168172                        Set<OsmPrimitive> wrongTypes = new HashSet<OsmPrimitive>();
    169173                        if (r.types != null) {
    170                             if (!r.types.contains(PresetType.WAY)) {
    171                                 wrongTypes.addAll(r.types.contains(PresetType.CLOSEDWAY) ? ri.openways : ri.ways);
    172                             }
    173                             if (!r.types.contains(PresetType.NODE)) {
     174                            if (!r.types.contains(TaggingPresetType.WAY)) {
     175                                wrongTypes.addAll(r.types.contains(TaggingPresetType.CLOSEDWAY) ? ri.openways : ri.ways);
     176                            }
     177                            if (!r.types.contains(TaggingPresetType.NODE)) {
    174178                                wrongTypes.addAll(ri.nodes);
    175179                            }
    176                             if (!r.types.contains(PresetType.RELATION)) {
     180                            if (!r.types.contains(TaggingPresetType.RELATION)) {
    177181                                wrongTypes.addAll(ri.relations);
    178182                            }
  • trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java

    r5791 r6068  
    5757import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    5858import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     59import org.openstreetmap.josm.gui.tagging.TaggingPresetItem;
     60import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.KeyedItem;
    5961import org.openstreetmap.josm.io.MirroredInputStream;
    6062import org.openstreetmap.josm.tools.GBC;
     
    301303            }
    302304            for (TaggingPreset p : presets) {
    303                 for (TaggingPreset.Item i : p.data) {
    304                     if (i instanceof TaggingPreset.KeyedItem) {
    305                         TaggingPreset.KeyedItem ky = (TaggingPreset.KeyedItem) i;
     305                for (TaggingPresetItem i : p.data) {
     306                    if (i instanceof KeyedItem) {
     307                        KeyedItem ky = (KeyedItem) i;
    306308                        if (ky.key != null && ky.getValues() != null) {
    307309                            try {
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java

    r5614 r6068  
    2222import org.openstreetmap.josm.data.osm.Tag;
    2323import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    24 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
     24import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    2525import org.openstreetmap.josm.tools.GBC;
    2626
     
    7777    }
    7878
    79     public void updatePresets(final Collection<PresetType> types, final Map<String, String> tags, PresetHandler presetHandler) {
     79    public void updatePresets(final Collection<TaggingPresetType> types, final Map<String, String> tags, PresetHandler presetHandler) {
    8080
    8181        removeAll();
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java

    r6038 r6068  
    8484import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    8585import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    86 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
     86import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    8787import org.openstreetmap.josm.gui.util.GuiHelper;
    8888import org.openstreetmap.josm.gui.util.HighlightHelper;
     
    597597        final Map<String, String> tags = new HashMap<String, String>();
    598598        valueCount.clear();
    599         EnumSet<PresetType> types = EnumSet.noneOf(TaggingPreset.PresetType.class);
     599        EnumSet<TaggingPresetType> types = EnumSet.noneOf(TaggingPresetType.class);
    600600        for (OsmPrimitive osm : newSelection) {
    601             types.add(PresetType.forPrimitive(osm));
     601            types.add(TaggingPresetType.forPrimitive(osm));
    602602            for (String key : osm.keySet()) {
    603603                String value = osm.get(key);
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java

    r6064 r6068  
    8585import org.openstreetmap.josm.gui.tagging.TagModel;
    8686import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     87import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    8788import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
    8889import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
     
    769770    public static Command addPrimitivesToRelation(final Relation orig, Collection<? extends OsmPrimitive> primitivesToAdd) {
    770771        try {
    771             final Collection<TaggingPreset> presets = TaggingPreset.getMatchingPresets(EnumSet.of(TaggingPreset.PresetType.RELATION), orig.getKeys(), false);
     772            final Collection<TaggingPreset> presets = TaggingPreset.getMatchingPresets(EnumSet.of(TaggingPresetType.RELATION), orig.getKeys(), false);
    772773            Relation relation = new Relation(orig);
    773774            boolean modified = false;
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java

    r5630 r6068  
    4040import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    4141import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     42import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    4243import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTableModel;
    4344
     
    384385
    385386    private void addMembersAtIndex(List<? extends OsmPrimitive> primitives, int index) {
    386         final Collection<TaggingPreset> presets = TaggingPreset.getMatchingPresets(EnumSet.of(TaggingPreset.PresetType.RELATION), presetHandler.getSelection().iterator().next().getKeys(), false);
     387        final Collection<TaggingPreset> presets = TaggingPreset.getMatchingPresets(EnumSet.of(TaggingPresetType.RELATION), presetHandler.getSelection().iterator().next().getKeys(), false);
    387388        if (primitives == null)
    388389            return;
  • trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java

    r5763 r6068  
    3939import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    4040import org.openstreetmap.josm.gui.tagging.TaggingPresetMenu;
     41import org.openstreetmap.josm.gui.tagging.TaggingPresetReader;
    4142import org.openstreetmap.josm.gui.tagging.TaggingPresetSeparator;
    4243import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
     
    4849
    4950    public static class Factory implements PreferenceSettingFactory {
     51        @Override
    5052        public PreferenceSetting createPreferenceSetting() {
    5153            return new TaggingPresetPreference();
     
    6971
    7072    private ValidationListener validationListener = new ValidationListener() {
     73        @Override
    7174        public boolean validatePreferences() {
    7275            if (sources.hasActiveSourcesChanged()) {
     
    7881                        boolean canLoad = false;
    7982                        try {
    80                             TaggingPreset.readAll(source.url, false);
     83                            TaggingPresetReader.readAll(source.url, false);
    8184                            canLoad = true;
    8285                        } catch (IOException e) {
     
    101104
    102105                        try {
    103                             TaggingPreset.readAll(source.url, true);
     106                            TaggingPresetReader.readAll(source.url, true);
    104107                        } catch (IOException e) {
    105108                            // Should not happen, but at least show message
     
    154157    };
    155158
     159    @Override
    156160    public void addGui(final PreferenceTabbedPane gui) {
    157161        sortMenu = new JCheckBox(tr("Sort presets menu"),
     
    258262    }
    259263
     264    @Override
    260265    public boolean ok() {
    261266        boolean restart = Main.pref.put("taggingpreset.sortmenu", sortMenu.getSelectedObjects() != null);
     
    269274     */
    270275    public static void initialize() {
    271         taggingPresets = TaggingPreset.readFromPreferences(false);
     276        taggingPresets = TaggingPresetReader.readFromPreferences(false);
    272277        for (TaggingPreset tp: taggingPresets) {
    273278            if (!(tp instanceof TaggingPresetSeparator)) {
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java

    r6064 r6068  
    193193    private void updatePresets() {
    194194        presetListPanel.updatePresets(
    195                 EnumSet.of(TaggingPreset.PresetType.RELATION),
     195                EnumSet.of(TaggingPresetType.RELATION),
    196196                model.getTags(), presetHandler);
    197197        validate();
  • trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java

    r5997 r6068  
    88import java.awt.Component;
    99import java.awt.Dimension;
    10 import java.awt.Font;
    1110import java.awt.GridBagLayout;
    1211import java.awt.Insets;
    1312import java.awt.event.ActionEvent;
    14 import java.awt.event.ActionListener;
    15 import java.io.BufferedReader;
    16 import java.io.File;
    17 import java.io.IOException;
    18 import java.io.InputStream;
    19 import java.io.InputStreamReader;
    20 import java.io.Reader;
    21 import java.io.UnsupportedEncodingException;
    22 import java.lang.reflect.Method;
    23 import java.lang.reflect.Modifier;
    24 import java.text.NumberFormat;
    25 import java.text.ParseException;
    2613import java.util.ArrayList;
    27 import java.util.Arrays;
    2814import java.util.Collection;
    29 import java.util.Collections;
    3015import java.util.EnumSet;
    31 import java.util.HashMap;
    3216import java.util.HashSet;
    33 import java.util.LinkedHashMap;
    3417import java.util.LinkedList;
    3518import java.util.List;
    3619import java.util.Map;
    37 import java.util.TreeSet;
    3820
    3921import javax.swing.AbstractAction;
    4022import javax.swing.Action;
    41 import javax.swing.ButtonGroup;
    4223import javax.swing.ImageIcon;
    43 import javax.swing.JButton;
    44 import javax.swing.JComponent;
    4524import javax.swing.JLabel;
    46 import javax.swing.JList;
    47 import javax.swing.JOptionPane;
    4825import javax.swing.JPanel;
    49 import javax.swing.JScrollPane;
    50 import javax.swing.JToggleButton;
    51 import javax.swing.ListCellRenderer;
    52 import javax.swing.ListModel;
    5326import javax.swing.SwingUtilities;
    5427
     
    6134import org.openstreetmap.josm.data.osm.Node;
    6235import org.openstreetmap.josm.data.osm.OsmPrimitive;
    63 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    64 import org.openstreetmap.josm.data.osm.OsmUtils;
    6536import org.openstreetmap.josm.data.osm.Relation;
    6637import org.openstreetmap.josm.data.osm.RelationMember;
    6738import org.openstreetmap.josm.data.osm.Tag;
    6839import org.openstreetmap.josm.data.osm.Way;
    69 import org.openstreetmap.josm.data.preferences.BooleanProperty;
    7040import org.openstreetmap.josm.gui.ExtendedDialog;
    7141import org.openstreetmap.josm.gui.MapView;
    72 import org.openstreetmap.josm.gui.QuadStateCheckBox;
    7342import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
    7443import org.openstreetmap.josm.gui.layer.Layer;
    75 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    76 import org.openstreetmap.josm.gui.preferences.SourceEntry;
    7744import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
    78 import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference.PresetPrefHelper;
    79 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
    80 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionItemPritority;
    81 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
     45import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Link;
     46import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Role;
     47import org.openstreetmap.josm.gui.tagging.TaggingPresetItems.Roles;
    8248import org.openstreetmap.josm.gui.util.GuiHelper;
    83 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
    84 import org.openstreetmap.josm.gui.widgets.JosmTextField;
    85 import org.openstreetmap.josm.io.MirroredInputStream;
    8649import org.openstreetmap.josm.tools.GBC;
    8750import org.openstreetmap.josm.tools.ImageProvider;
    8851import org.openstreetmap.josm.tools.Predicate;
    89 import org.openstreetmap.josm.tools.UrlLabel;
    9052import org.openstreetmap.josm.tools.Utils;
    91 import org.openstreetmap.josm.tools.XmlObjectParser;
    9253import org.openstreetmap.josm.tools.template_engine.ParseError;
    9354import org.openstreetmap.josm.tools.template_engine.TemplateEntry;
     
    10566public class TaggingPreset extends AbstractAction implements MapView.LayerChangeListener {
    10667
    107     public enum PresetType {
    108         NODE(/* ICON */"Mf_node", "node"),
    109         WAY(/* ICON */"Mf_way", "way"),
    110         RELATION(/* ICON */"Mf_relation", "relation"),
    111         CLOSEDWAY(/* ICON */"Mf_closedway", "closedway");
    112 
    113         private final String iconName;
    114         private final String name;
    115 
    116         PresetType(String iconName, String name) {
    117             this.iconName = iconName;
    118             this.name = name;
    119         }
    120 
    121         public String getIconName() {
    122             return iconName;
    123         }
    124 
    125         public String getName() {
    126             return name;
    127         }
    128 
    129         public static PresetType forPrimitive(OsmPrimitive p) {
    130             return forPrimitiveType(p.getDisplayType());
    131         }
    132 
    133         public static PresetType forPrimitiveType(OsmPrimitiveType type) {
    134             switch (type) {
    135             case NODE:
    136                 return NODE;
    137             case WAY:
    138                 return WAY;
    139             case CLOSEDWAY:
    140                 return CLOSEDWAY;
    141             case RELATION:
    142             case MULTIPOLYGON:
    143                 return RELATION;
    144             default:
    145                 throw new IllegalArgumentException("Unexpected primitive type: " + type);
    146             }
    147         }
    148 
    149         public static PresetType fromString(String type) {
    150             for (PresetType t : PresetType.values()) {
    151                 if (t.getName().equals(type))
    152                     return t;
    153             }
    154             return null;
    155         }
    156     }
    157 
    158     /**
    159      * Enum denoting how a match (see {@link Item#matches}) is performed.
    160      */
    161     private enum MatchType {
    162 
    163         /**
    164          * Neutral, i.e., do not consider this item for matching.
    165          */
    166         NONE("none"),
    167         /**
    168          * Positive if key matches, neutral otherwise.
    169          */
    170         KEY("key"),
    171         /**
    172          * Positive if key matches, negative otherwise.
    173          */
    174         KEY_REQUIRED("key!"),
    175         /**
    176          * Positive if key and value matches, negative otherwise.
    177          */
    178         KEY_VALUE("keyvalue");
    179 
    180         private final String value;
    181 
    182         private MatchType(String value) {
    183             this.value = value;
    184         }
    185 
    186         public String getValue() {
    187             return value;
    188         }
    189 
    190         public static MatchType ofString(String type) {
    191             for (MatchType i : EnumSet.allOf(MatchType.class)) {
    192                 if (i.getValue().equals(type))
    193                     return i;
    194             }
    195             throw new IllegalArgumentException(type + " is not allowed");
    196         }
    197     }
    198 
    19968    public static final int DIALOG_ANSWER_APPLY = 1;
    20069    public static final int DIALOG_ANSWER_NEW_RELATION = 2;
     
    20574    public String name_context;
    20675    public String locale_name;
    207     public final static String OPTIONAL_TOOLTIP_TEXT = "Optional tooltip text";
    208     private static File zipIcons = null;
    209     private static final BooleanProperty PROP_FILL_DEFAULT = new BooleanProperty("taggingpreset.fill-default-for-tagged-primitives", false);
    210 
    211     public static abstract class Item {
    212 
    213         protected void initAutoCompletionField(AutoCompletingTextField field, String key) {
    214             OsmDataLayer layer = Main.main.getEditLayer();
    215             if (layer == null)
    216                 return;
    217             AutoCompletionList list = new AutoCompletionList();
    218             Main.main.getEditLayer().data.getAutoCompletionManager().populateWithTagValues(list, key);
    219             field.setAutoCompletionList(list);
    220         }
    221 
    222         abstract boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel);
    223 
    224         abstract void addCommands(List<Tag> changedTags);
    225 
    226         boolean requestFocusInWindow() {
    227             return false;
    228         }
    229 
    230         /**
    231          * Tests whether the tags match this item.
    232          * Note that for a match, at least one positive and no negative is required.
    233          * @param tags the tags of an {@link OsmPrimitive}
    234          * @return {@code true} if matches (positive), {@code null} if neutral, {@code false} if mismatches (negative).
    235          */
    236         Boolean matches(Map<String, String> tags) {
    237             return null;
    238         }
    239     }
    240 
    241     public static abstract class KeyedItem extends Item {
    242 
    243         public String key;
    244         public String text;
    245         public String text_context;
    246         public String match = getDefaultMatch().getValue();
    247 
    248         public abstract MatchType getDefaultMatch();
    249         public abstract Collection<String> getValues();
    250 
    251         @Override
    252         Boolean matches(Map<String, String> tags) {
    253             switch (MatchType.ofString(match)) {
    254             case NONE:
    255                 return null;
    256             case KEY:
    257                 return tags.containsKey(key) ? true : null;
    258             case KEY_REQUIRED:
    259                 return tags.containsKey(key);
    260             case KEY_VALUE:
    261                 return tags.containsKey(key) && (getValues().contains(tags.get(key)));
    262             default:
    263                 throw new IllegalStateException();
    264             }
    265         }
    266        
    267         @Override
    268         public String toString() {
    269             return "KeyedItem [key=" + key + ", text=" + text
    270                     + ", text_context=" + text_context + ", match=" + match
    271                     + "]";
    272         }
    273     }
    274 
    275     public static class Usage {
    276         TreeSet<String> values;
    277         boolean hadKeys = false;
    278         boolean hadEmpty = false;
    279         public boolean hasUniqueValue() {
    280             return values.size() == 1 && !hadEmpty;
    281         }
    282 
    283         public boolean unused() {
    284             return values.isEmpty();
    285         }
    286         public String getFirst() {
    287             return values.first();
    288         }
    289 
    290         public boolean hadKeys() {
    291             return hadKeys;
    292         }
    293     }
    294 
    295     public static final String DIFFERENT = tr("<different>");
    296 
    297     static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
    298         Usage returnValue = new Usage();
    299         returnValue.values = new TreeSet<String>();
    300         for (OsmPrimitive s : sel) {
    301             String v = s.get(key);
    302             if (v != null) {
    303                 returnValue.values.add(v);
    304             } else {
    305                 returnValue.hadEmpty = true;
    306             }
    307             if(s.hasKeys()) {
    308                 returnValue.hadKeys = true;
    309             }
    310         }
    311         return returnValue;
    312     }
    313 
    314     static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
    315 
    316         Usage returnValue = new Usage();
    317         returnValue.values = new TreeSet<String>();
    318         for (OsmPrimitive s : sel) {
    319             String booleanValue = OsmUtils.getNamedOsmBoolean(s.get(key));
    320             if (booleanValue != null) {
    321                 returnValue.values.add(booleanValue);
    322             }
    323         }
    324         return returnValue;
    325     }
    326 
    327     public static class PresetListEntry {
    328         public String value;
    329         public String value_context;
    330         public String display_value;
    331         public String short_description;
    332         public String icon;
    333         public String icon_size;
    334         public String locale_display_value;
    335         public String locale_short_description;
    336         private final File zipIcons = TaggingPreset.zipIcons;
    337 
    338         // Cached size (currently only for Combo) to speed up preset dialog initialization
    339         private int prefferedWidth = -1;
    340         private int prefferedHeight = -1;
    341 
    342         public String getListDisplay() {
    343             if (value.equals(DIFFERENT))
    344                 return "<b>"+DIFFERENT.replaceAll("<", "&lt;").replaceAll(">", "&gt;")+"</b>";
    345 
    346             if (value.equals(""))
    347                 return "&nbsp;";
    348 
    349             final StringBuilder res = new StringBuilder("<b>");
    350             res.append(getDisplayValue(true));
    351             res.append("</b>");
    352             if (getShortDescription(true) != null) {
    353                 // wrap in table to restrict the text width
    354                 res.append("<div style=\"width:300px; padding:0 0 5px 5px\">");
    355                 res.append(getShortDescription(true));
    356                 res.append("</div>");
    357             }
    358             return res.toString();
    359         }
    360 
    361         public ImageIcon getIcon() {
    362             return icon == null ? null : loadImageIcon(icon, zipIcons, parseInteger(icon_size));
    363         }
    364 
    365         private Integer parseInteger(String str) {
    366             if (str == null || "".equals(str))
    367                 return null;
    368             try {
    369                 return Integer.parseInt(str);
    370             } catch (Exception e) {
    371                 //
    372             }
    373             return null;
    374         }
    375 
    376         public PresetListEntry() {
    377         }
    378 
    379         public PresetListEntry(String value) {
    380             this.value = value;
    381         }
    382 
    383         public String getDisplayValue(boolean translated) {
    384             return translated
    385                     ? Utils.firstNonNull(locale_display_value, tr(display_value), trc(value_context, value))
    386                             : Utils.firstNonNull(display_value, value);
    387         }
    388 
    389         public String getShortDescription(boolean translated) {
    390             return translated
    391                     ? Utils.firstNonNull(locale_short_description, tr(short_description))
    392                             : short_description;
    393         }
    394 
    395         // toString is mainly used to initialize the Editor
    396         @Override
    397         public String toString() {
    398             if (value.equals(DIFFERENT))
    399                 return DIFFERENT;
    400             return getDisplayValue(true).replaceAll("<.*>", ""); // remove additional markup, e.g. <br>
    401         }
    402     }
    403 
    404     public static class Text extends KeyedItem {
    405 
    406         public String locale_text;
    407         public String default_;
    408         public String originalValue;
    409         public String use_last_as_default = "false";
    410         public String auto_increment;
    411         public String length;
    412 
    413         private JComponent value;
    414 
    415         @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    416 
    417             // find out if our key is already used in the selection.
    418             Usage usage = determineTextUsage(sel, key);
    419             AutoCompletingTextField textField = new AutoCompletingTextField();
    420             initAutoCompletionField(textField, key);
    421             if (length != null && !length.isEmpty()) {
    422                 textField.setMaxChars(new Integer(length));
    423             }
    424             if (usage.unused()){
    425                 if (auto_increment_selected != 0  && auto_increment != null) {
    426                     try {
    427                         textField.setText(Integer.toString(Integer.parseInt(lastValue.get(key)) + auto_increment_selected));
    428                     } catch (NumberFormatException ex) {
    429                         // Ignore - cannot auto-increment if last was non-numeric
    430                     }
    431                 }
    432                 else if (!usage.hadKeys() || PROP_FILL_DEFAULT.get() || "force".equals(use_last_as_default)) {
    433                     // selected osm primitives are untagged or filling default values feature is enabled
    434                     if (!"false".equals(use_last_as_default) && lastValue.containsKey(key)) {
    435                         textField.setText(lastValue.get(key));
    436                     } else {
    437                         textField.setText(default_);
    438                     }
    439                 } else {
    440                     // selected osm primitives are tagged and filling default values feature is disabled
    441                     textField.setText("");
    442                 }
    443                 value = textField;
    444                 originalValue = null;
    445             } else if (usage.hasUniqueValue()) {
    446                 // all objects use the same value
    447                 textField.setText(usage.getFirst());
    448                 value = textField;
    449                 originalValue = usage.getFirst();
    450             } else {
    451                 // the objects have different values
    452                 JosmComboBox comboBox = new JosmComboBox(usage.values.toArray());
    453                 comboBox.setEditable(true);
    454                 comboBox.setEditor(textField);
    455                 comboBox.getEditor().setItem(DIFFERENT);
    456                 value=comboBox;
    457                 originalValue = DIFFERENT;
    458             }
    459             if (locale_text == null) {
    460                 if (text != null) {
    461                     if (text_context != null) {
    462                         locale_text = trc(text_context, fixPresetString(text));
    463                     } else {
    464                         locale_text = tr(fixPresetString(text));
    465                     }
    466                 }
    467             }
    468 
    469             // if there's an auto_increment setting, then wrap the text field
    470             // into a panel, appending a number of buttons.
    471             // auto_increment has a format like -2,-1,1,2
    472             // the text box being the first component in the panel is relied
    473             // on in a rather ugly fashion further down.
    474             if (auto_increment != null) {
    475                 ButtonGroup bg = new ButtonGroup();
    476                 JPanel pnl = new JPanel(new GridBagLayout());
    477                 pnl.add(value, GBC.std().fill(GBC.HORIZONTAL));
    478 
    479                 // first, one button for each auto_increment value
    480                 for (final String ai : auto_increment.split(",")) {
    481                     JToggleButton aibutton = new JToggleButton(ai);
    482                     aibutton.setToolTipText(tr("Select auto-increment of {0} for this field", ai));
    483                     aibutton.setMargin(new java.awt.Insets(0,0,0,0));
    484                     bg.add(aibutton);
    485                     try {
    486                         // TODO there must be a better way to parse a number like "+3" than this.
    487                         final int buttonvalue = ((Number)NumberFormat.getIntegerInstance().parse(ai.replace("+", ""))).intValue();
    488                         if (auto_increment_selected == buttonvalue) aibutton.setSelected(true);
    489                         aibutton.addActionListener(new ActionListener() {
    490                             public void actionPerformed(ActionEvent e) {
    491                                 auto_increment_selected = buttonvalue;
    492                             }
    493                         });
    494                         pnl.add(aibutton, GBC.std());
    495                     } catch (ParseException x) {
    496                         System.err.println("Cannot parse auto-increment value of '" + ai + "' into an integer");
    497                     }
    498                 }
    499 
    500                 // an invisible toggle button for "release" of the button group
    501                 final JToggleButton clearbutton = new JToggleButton("X");
    502                 clearbutton.setVisible(false);
    503                 bg.add(clearbutton);
    504                 // and its visible counterpart. - this mechanism allows us to
    505                 // have *no* button selected after the X is clicked, instead
    506                 // of the X remaining selected
    507                 JButton releasebutton = new JButton("X");
    508                 releasebutton.setToolTipText(tr("Cancel auto-increment for this field"));
    509                 releasebutton.setMargin(new java.awt.Insets(0,0,0,0));
    510                 releasebutton.addActionListener(new ActionListener() {
    511                     public void actionPerformed(ActionEvent e) {
    512                         auto_increment_selected = 0;
    513                         clearbutton.setSelected(true);
    514                     }
    515                 });
    516                 pnl.add(releasebutton, GBC.eol());
    517                 value = pnl;
    518             }
    519             p.add(new JLabel(locale_text+":"), GBC.std().insets(0,0,10,0));
    520             p.add(value, GBC.eol().fill(GBC.HORIZONTAL));
    521             return true;
    522         }
    523 
    524         private static String getValue(Component comp) {
    525             if (comp instanceof JosmComboBox) {
    526                 return ((JosmComboBox) comp).getEditor().getItem().toString();
    527             } else if (comp instanceof JosmTextField) {
    528                 return ((JosmTextField) comp).getText();
    529             } else if (comp instanceof JPanel) {
    530                 return getValue(((JPanel)comp).getComponent(0));
    531             } else {
    532                 return null;
    533             }
    534         }
    535        
    536         @Override
    537         public void addCommands(List<Tag> changedTags) {
    538 
    539             // return if unchanged
    540             String v = getValue(value);
    541             if (v == null) {
    542                 System.err.println("No 'last value' support for component " + value);
    543                 return;
    544             }
    545            
    546             v = v.trim();
    547 
    548             if (!"false".equals(use_last_as_default) || auto_increment != null) {
    549                 lastValue.put(key, v);
    550             }
    551             if (v.equals(originalValue) || (originalValue == null && v.length() == 0))
    552                 return;
    553 
    554             changedTags.add(new Tag(key, v));
    555         }
    556 
    557         @Override
    558         boolean requestFocusInWindow() {
    559             return value.requestFocusInWindow();
    560         }
    561 
    562         @Override
    563         public MatchType getDefaultMatch() {
    564             return MatchType.NONE;
    565         }
    566 
    567         @Override
    568         public Collection<String> getValues() {
    569             if (default_ == null || default_.isEmpty())
    570                 return Collections.emptyList();
    571             return Collections.singleton(default_);
    572         }
    573     }
    574 
    575     public static class Check extends KeyedItem {
    576 
    577         public String locale_text;
    578         public String value_on = OsmUtils.trueval;
    579         public String value_off = OsmUtils.falseval;
    580         public boolean default_ = false; // only used for tagless objects
    581 
    582         private QuadStateCheckBox check;
    583         private QuadStateCheckBox.State initialState;
    584         private boolean def;
    585 
    586         @Override public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    587 
    588             // find out if our key is already used in the selection.
    589             Usage usage = determineBooleanUsage(sel, key);
    590             def = default_;
    591 
    592             if(locale_text == null) {
    593                 if(text_context != null) {
    594                     locale_text = trc(text_context, fixPresetString(text));
    595                 } else {
    596                     locale_text = tr(fixPresetString(text));
    597                 }
    598             }
    599 
    600             String oneValue = null;
    601             for (String s : usage.values) {
    602                 oneValue = s;
    603             }
    604             if (usage.values.size() < 2 && (oneValue == null || value_on.equals(oneValue) || value_off.equals(oneValue))) {
    605                 if (def && !PROP_FILL_DEFAULT.get()) {
    606                     // default is set and filling default values feature is disabled - check if all primitives are untagged
    607                     for (OsmPrimitive s : sel)
    608                         if(s.hasKeys()) {
    609                             def = false;
    610                         }
    611                 }
    612 
    613                 // all selected objects share the same value which is either true or false or unset,
    614                 // we can display a standard check box.
    615                 initialState = value_on.equals(oneValue) ?
    616                         QuadStateCheckBox.State.SELECTED :
    617                             value_off.equals(oneValue) ?
    618                                     QuadStateCheckBox.State.NOT_SELECTED :
    619                                         def ? QuadStateCheckBox.State.SELECTED
    620                                                 : QuadStateCheckBox.State.UNSET;
    621                 check = new QuadStateCheckBox(locale_text, initialState,
    622                         new QuadStateCheckBox.State[] {
    623                         QuadStateCheckBox.State.SELECTED,
    624                         QuadStateCheckBox.State.NOT_SELECTED,
    625                         QuadStateCheckBox.State.UNSET });
    626             } else {
    627                 def = false;
    628                 // the objects have different values, or one or more objects have something
    629                 // else than true/false. we display a quad-state check box
    630                 // in "partial" state.
    631                 initialState = QuadStateCheckBox.State.PARTIAL;
    632                 check = new QuadStateCheckBox(locale_text, QuadStateCheckBox.State.PARTIAL,
    633                         new QuadStateCheckBox.State[] {
    634                         QuadStateCheckBox.State.PARTIAL,
    635                         QuadStateCheckBox.State.SELECTED,
    636                         QuadStateCheckBox.State.NOT_SELECTED,
    637                         QuadStateCheckBox.State.UNSET });
    638             }
    639             p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
    640             return true;
    641         }
    642 
    643         @Override public void addCommands(List<Tag> changedTags) {
    644             // if the user hasn't changed anything, don't create a command.
    645             if (check.getState() == initialState && !def) return;
    646 
    647             // otherwise change things according to the selected value.
    648             changedTags.add(new Tag(key,
    649                     check.getState() == QuadStateCheckBox.State.SELECTED ? value_on :
    650                         check.getState() == QuadStateCheckBox.State.NOT_SELECTED ? value_off :
    651                             null));
    652         }
    653         @Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
    654 
    655         @Override
    656         public MatchType getDefaultMatch() {
    657             return MatchType.NONE;
    658         }
    659 
    660         @Override
    661         public Collection<String> getValues() {
    662             return Arrays.asList(value_on, value_off);
    663         }
    664     }
    665 
    666     public static abstract class ComboMultiSelect extends KeyedItem {
    667 
    668         public String locale_text;
    669         public String values;
    670         public String values_from;
    671         public String values_context;
    672         public String display_values;
    673         public String locale_display_values;
    674         public String short_descriptions;
    675         public String locale_short_descriptions;
    676         public String default_;
    677         public String delimiter = ";";
    678         public String use_last_as_default = "false";
    679 
    680         protected JComponent component;
    681         protected final Map<String, PresetListEntry> lhm = new LinkedHashMap<String, PresetListEntry>();
    682         private boolean initialized = false;
    683         protected Usage usage;
    684         protected Object originalValue;
    685 
    686         protected abstract Object getSelectedItem();
    687         protected abstract void addToPanelAnchor(JPanel p, String def);
    688 
    689         protected char getDelChar() {
    690             return delimiter.isEmpty() ? ';' : delimiter.charAt(0);
    691         }
    692 
    693         @Override
    694         public Collection<String> getValues() {
    695             initListEntries();
    696             return lhm.keySet();
    697         }
    698 
    699         public Collection<String> getDisplayValues() {
    700             initListEntries();
    701             return Utils.transform(lhm.values(), new Utils.Function<PresetListEntry, String>() {
    702 
    703                 @Override
    704                 public String apply(PresetListEntry x) {
    705                     return x.getDisplayValue(true);
    706                 }
    707             });
    708         }
    709 
    710         @Override
    711         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    712 
    713             initListEntries();
    714 
    715             // find out if our key is already used in the selection.
    716             usage = determineTextUsage(sel, key);
    717             if (!usage.hasUniqueValue() && !usage.unused()) {
    718                 lhm.put(DIFFERENT, new PresetListEntry(DIFFERENT));
    719             }
    720 
    721             p.add(new JLabel(tr("{0}:", locale_text)), GBC.std().insets(0, 0, 10, 0));
    722             addToPanelAnchor(p, default_);
    723 
    724             return true;
    725 
    726         }
    727 
    728         private void initListEntries() {
    729             if (initialized) {
    730                 lhm.remove(DIFFERENT); // possibly added in #addToPanel
    731                 return;
    732             } else if (lhm.isEmpty()) {
    733                 initListEntriesFromAttributes();
    734             } else {
    735                 if (values != null) {
    736                     System.err.println(tr("Warning in tagging preset \"{0}-{1}\": "
    737                             + "Ignoring ''{2}'' attribute as ''{3}'' elements are given.",
    738                             key, text, "values", "list_entry"));
    739                 }
    740                 if (display_values != null || locale_display_values != null) {
    741                     System.err.println(tr("Warning in tagging preset \"{0}-{1}\": "
    742                             + "Ignoring ''{2}'' attribute as ''{3}'' elements are given.",
    743                             key, text, "display_values", "list_entry"));
    744                 }
    745                 if (short_descriptions != null || locale_short_descriptions != null) {
    746                     System.err.println(tr("Warning in tagging preset \"{0}-{1}\": "
    747                             + "Ignoring ''{2}'' attribute as ''{3}'' elements are given.",
    748                             key, text, "short_descriptions", "list_entry"));
    749                 }
    750                 for (PresetListEntry e : lhm.values()) {
    751                     if (e.value_context == null) {
    752                         e.value_context = values_context;
    753                     }
    754                 }
    755             }
    756             if (locale_text == null) {
    757                 locale_text = trc(text_context, fixPresetString(text));
    758             }
    759             initialized = true;
    760         }
    761 
    762         private String[] initListEntriesFromAttributes() {
    763             char delChar = getDelChar();
    764 
    765             String[] value_array = null;
    766            
    767             if (values_from != null) {
    768                 String[] class_method = values_from.split("#");
    769                 if (class_method != null && class_method.length == 2) {
    770                     try {
    771                         Method method = Class.forName(class_method[0]).getMethod(class_method[1]);
    772                         // Check method is public static String[] methodName();
    773                         int mod = method.getModifiers();
    774                         if (Modifier.isPublic(mod) && Modifier.isStatic(mod)
    775                                 && method.getReturnType().equals(String[].class) && method.getParameterTypes().length == 0) {
    776                             value_array = (String[]) method.invoke(null);
    777                         } else {
    778                             System.err.println(tr("Broken tagging preset \"{0}-{1}\" - Java method given in ''values_from'' is not \"{2}\"", key, text,
    779                                     "public static String[] methodName()"));
    780                         }
    781                     } catch (Exception e) {
    782                         System.err.println(tr("Broken tagging preset \"{0}-{1}\" - Java method given in ''values_from'' threw {2} ({3})", key, text,
    783                                 e.getClass().getName(), e.getMessage()));
    784                     }
    785                 }
    786             }
    787            
    788             if (value_array == null) {
    789                 value_array = splitEscaped(delChar, values);
    790             }
    791 
    792             final String displ = Utils.firstNonNull(locale_display_values, display_values);
    793             String[] display_array = displ == null ? value_array : splitEscaped(delChar, displ);
    794 
    795             final String descr = Utils.firstNonNull(locale_short_descriptions, short_descriptions);
    796             String[] short_descriptions_array = descr == null ? null : splitEscaped(delChar, descr);
    797 
    798             if (display_array.length != value_array.length) {
    799                 System.err.println(tr("Broken tagging preset \"{0}-{1}\" - number of items in ''display_values'' must be the same as in ''values''", key, text));
    800                 display_array = value_array;
    801             }
    802 
    803             if (short_descriptions_array != null && short_descriptions_array.length != value_array.length) {
    804                 System.err.println(tr("Broken tagging preset \"{0}-{1}\" - number of items in ''short_descriptions'' must be the same as in ''values''", key, text));
    805                 short_descriptions_array = null;
    806             }
    807 
    808             for (int i = 0; i < value_array.length; i++) {
    809                 final PresetListEntry e = new PresetListEntry(value_array[i]);
    810                 e.locale_display_value = locale_display_values != null
    811                         ? display_array[i]
    812                                 : trc(values_context, fixPresetString(display_array[i]));
    813                         if (short_descriptions_array != null) {
    814                             e.locale_short_description = locale_short_descriptions != null
    815                                     ? short_descriptions_array[i]
    816                                             : tr(fixPresetString(short_descriptions_array[i]));
    817                         }
    818                         lhm.put(value_array[i], e);
    819                         display_array[i] = e.getDisplayValue(true);
    820             }
    821 
    822             return display_array;
    823         }
    824 
    825         protected String getDisplayIfNull(String display) {
    826             return display;
    827         }
    828 
    829         @Override
    830         public void addCommands(List<Tag> changedTags) {
    831             Object obj = getSelectedItem();
    832             String display = (obj == null) ? null : obj.toString();
    833             String value = null;
    834             if (display == null) {
    835                 display = getDisplayIfNull(display);
    836             }
    837 
    838             if (display != null) {
    839                 for (String key : lhm.keySet()) {
    840                     String k = lhm.get(key).toString();
    841                     if (k != null && k.equals(display)) {
    842                         value = key;
    843                         break;
    844                     }
    845                 }
    846                 if (value == null) {
    847                     value = display;
    848                 }
    849             } else {
    850                 value = "";
    851             }
    852             value = value.trim();
    853 
    854             // no change if same as before
    855             if (originalValue == null) {
    856                 if (value.length() == 0)
    857                     return;
    858             } else if (value.equals(originalValue.toString()))
    859                 return;
    860 
    861             if (!"false".equals(use_last_as_default)) {
    862                 lastValue.put(key, value);
    863             }
    864             changedTags.add(new Tag(key, value));
    865         }
    866 
    867         public void addListEntry(PresetListEntry e) {
    868             lhm.put(e.value, e);
    869         }
    870 
    871         public void addListEntries(Collection<PresetListEntry> e) {
    872             for (PresetListEntry i : e) {
    873                 addListEntry(i);
    874             }
    875         }
    876 
    877         @Override
    878         boolean requestFocusInWindow() {
    879             return component.requestFocusInWindow();
    880         }
    881 
    882         private static ListCellRenderer RENDERER = new ListCellRenderer() {
    883 
    884             JLabel lbl = new JLabel();
    885 
    886             public Component getListCellRendererComponent(
    887                     JList list,
    888                     Object value,
    889                     int index,
    890                     boolean isSelected,
    891                     boolean cellHasFocus) {
    892                 PresetListEntry item = (PresetListEntry) value;
    893 
    894                 // Only return cached size, item is not shown
    895                 if (!list.isShowing() && item.prefferedWidth != -1 && item.prefferedHeight != -1) {
    896                     if (index == -1) {
    897                         lbl.setPreferredSize(new Dimension(item.prefferedWidth, 10));
    898                     } else {
    899                         lbl.setPreferredSize(new Dimension(item.prefferedWidth, item.prefferedHeight));
    900                     }
    901                     return lbl;
    902                 }
    903 
    904                 lbl.setPreferredSize(null);
    905 
    906 
    907                 if (isSelected) {
    908                     lbl.setBackground(list.getSelectionBackground());
    909                     lbl.setForeground(list.getSelectionForeground());
    910                 } else {
    911                     lbl.setBackground(list.getBackground());
    912                     lbl.setForeground(list.getForeground());
    913                 }
    914 
    915                 lbl.setOpaque(true);
    916                 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
    917                 lbl.setText("<html>" + item.getListDisplay() + "</html>");
    918                 lbl.setIcon(item.getIcon());
    919                 lbl.setEnabled(list.isEnabled());
    920 
    921                 // Cache size
    922                 item.prefferedWidth = lbl.getPreferredSize().width;
    923                 item.prefferedHeight = lbl.getPreferredSize().height;
    924 
    925                 // We do not want the editor to have the maximum height of all
    926                 // entries. Return a dummy with bogus height.
    927                 if (index == -1) {
    928                     lbl.setPreferredSize(new Dimension(lbl.getPreferredSize().width, 10));
    929                 }
    930                 return lbl;
    931             }
    932         };
    933 
    934 
    935         protected ListCellRenderer getListCellRenderer() {
    936             return RENDERER;
    937         }
    938 
    939         @Override
    940         public MatchType getDefaultMatch() {
    941             return MatchType.NONE;
    942         }
    943     }
    944 
    945     public static class Combo extends ComboMultiSelect {
    946 
    947         public boolean editable = true;
    948         protected JosmComboBox combo;
    949         public String length;
    950 
    951         public Combo() {
    952             delimiter = ",";
    953         }
    954 
    955         @Override
    956         protected void addToPanelAnchor(JPanel p, String def) {
    957             if (!usage.unused()) {
    958                 for (String s : usage.values) {
    959                     if (!lhm.containsKey(s)) {
    960                         lhm.put(s, new PresetListEntry(s));
    961                     }
    962                 }
    963             }
    964             if (def != null && !lhm.containsKey(def)) {
    965                 lhm.put(def, new PresetListEntry(def));
    966             }
    967             lhm.put("", new PresetListEntry(""));
    968 
    969             combo = new JosmComboBox(lhm.values().toArray());
    970             component = combo;
    971             combo.setRenderer(getListCellRenderer());
    972             combo.setEditable(editable);
    973             combo.reinitialize(lhm.values());
    974             AutoCompletingTextField tf = new AutoCompletingTextField();
    975             initAutoCompletionField(tf, key);
    976             if (length != null && !length.isEmpty()) {
    977                 tf.setMaxChars(new Integer(length));
    978             }
    979             AutoCompletionList acList = tf.getAutoCompletionList();
    980             if (acList != null) {
    981                 acList.add(getDisplayValues(), AutoCompletionItemPritority.IS_IN_STANDARD);
    982             }
    983             combo.setEditor(tf);
    984 
    985             if (usage.hasUniqueValue()) {
    986                 // all items have the same value (and there were no unset items)
    987                 originalValue = lhm.get(usage.getFirst());
    988                 combo.setSelectedItem(originalValue);
    989             } else if (def != null && usage.unused()) {
    990                 // default is set and all items were unset
    991                 if (!usage.hadKeys() || PROP_FILL_DEFAULT.get() || "force".equals(use_last_as_default)) {
    992                     // selected osm primitives are untagged or filling default feature is enabled
    993                     combo.setSelectedItem(lhm.get(def).getDisplayValue(true));
    994                 } else {
    995                     // selected osm primitives are tagged and filling default feature is disabled
    996                     combo.setSelectedItem("");
    997                 }
    998                 originalValue = lhm.get(DIFFERENT);
    999             } else if (usage.unused()) {
    1000                 // all items were unset (and so is default)
    1001                 originalValue = lhm.get("");
    1002                 if ("force".equals(use_last_as_default) && lastValue.containsKey(key)) {
    1003                     combo.setSelectedItem(lhm.get(lastValue.get(key)));
    1004                 } else {
    1005                     combo.setSelectedItem(originalValue);
    1006                 }
    1007             } else {
    1008                 originalValue = lhm.get(DIFFERENT);
    1009                 combo.setSelectedItem(originalValue);
    1010             }
    1011             p.add(combo, GBC.eol().fill(GBC.HORIZONTAL));
    1012 
    1013         }
    1014 
    1015         @Override
    1016         protected Object getSelectedItem() {
    1017             return combo.getSelectedItem();
    1018 
    1019         }
    1020 
    1021         @Override
    1022         protected String getDisplayIfNull(String display) {
    1023             if (combo.isEditable())
    1024                 return combo.getEditor().getItem().toString();
    1025             else
    1026                 return display;
    1027 
    1028         }
    1029     }
    1030 
    1031     /**
    1032      * Class that allows list values to be assigned and retrieved as a comma-delimited
    1033      * string.
    1034      */
    1035     public static class ConcatenatingJList extends JList {
    1036         private String delimiter;
    1037         public ConcatenatingJList(String del, Object[] o) {
    1038             super(o);
    1039             delimiter = del;
    1040         }
    1041         public void setSelectedItem(Object o) {
    1042             if (o == null) {
    1043                 clearSelection();
    1044             } else {
    1045                 String s = o.toString();
    1046                 TreeSet<String> parts = new TreeSet<String>(Arrays.asList(s.split(delimiter)));
    1047                 ListModel lm = getModel();
    1048                 int[] intParts = new int[lm.getSize()];
    1049                 int j = 0;
    1050                 for (int i = 0; i < lm.getSize(); i++) {
    1051                     if (parts.contains((((PresetListEntry)lm.getElementAt(i)).value))) {
    1052                         intParts[j++]=i;
    1053                     }
    1054                 }
    1055                 setSelectedIndices(Arrays.copyOf(intParts, j));
    1056                 // check if we have actually managed to represent the full
    1057                 // value with our presets. if not, cop out; we will not offer
    1058                 // a selection list that threatens to ruin the value.
    1059                 setEnabled(Utils.join(delimiter, parts).equals(getSelectedItem()));
    1060             }
    1061         }
    1062         public String getSelectedItem() {
    1063             ListModel lm = getModel();
    1064             int[] si = getSelectedIndices();
    1065             StringBuilder builder = new StringBuilder();
    1066             for (int i=0; i<si.length; i++) {
    1067                 if (i>0) {
    1068                     builder.append(delimiter);
    1069                 }
    1070                 builder.append(((PresetListEntry)lm.getElementAt(si[i])).value);
    1071             }
    1072             return builder.toString();
    1073         }
    1074     }
    1075 
    1076     public static class MultiSelect extends ComboMultiSelect {
    1077 
    1078         public long rows = -1;
    1079         protected ConcatenatingJList list;
    1080 
    1081         @Override
    1082         protected void addToPanelAnchor(JPanel p, String def) {
    1083             list = new ConcatenatingJList(delimiter, lhm.values().toArray());
    1084             component = list;
    1085             ListCellRenderer renderer = getListCellRenderer();
    1086             list.setCellRenderer(renderer);
    1087 
    1088             if (usage.hasUniqueValue() && !usage.unused()) {
    1089                 originalValue = usage.getFirst();
    1090                 list.setSelectedItem(originalValue);
    1091             } else if (def != null && !usage.hadKeys() || PROP_FILL_DEFAULT.get() || "force".equals(use_last_as_default)) {
    1092                 originalValue = DIFFERENT;
    1093                 list.setSelectedItem(def);
    1094             } else if (usage.unused()) {
    1095                 originalValue = null;
    1096                 list.setSelectedItem(originalValue);
    1097             } else {
    1098                 originalValue = DIFFERENT;
    1099                 list.setSelectedItem(originalValue);
    1100             }
    1101 
    1102             JScrollPane sp = new JScrollPane(list);
    1103             // if a number of rows has been specified in the preset,
    1104             // modify preferred height of scroll pane to match that row count.
    1105             if (rows != -1) {
    1106                 double height = renderer.getListCellRendererComponent(list,
    1107                         new PresetListEntry("x"), 0, false, false).getPreferredSize().getHeight() * rows;
    1108                 sp.setPreferredSize(new Dimension((int) sp.getPreferredSize().getWidth(), (int) height));
    1109             }
    1110             p.add(sp, GBC.eol().fill(GBC.HORIZONTAL));
    1111 
    1112 
    1113         }
    1114 
    1115         @Override
    1116         protected Object getSelectedItem() {
    1117             return list.getSelectedItem();
    1118         }
    1119 
    1120         @Override
    1121         public void addCommands(List<Tag> changedTags) {
    1122             // Do not create any commands if list has been disabled because of an unknown value (fix #8605)
    1123             if (list.isEnabled()) {
    1124                 super.addCommands(changedTags);
    1125             }
    1126         }
    1127     }
    1128 
    1129     /**
    1130      * allow escaped comma in comma separated list:
    1131      * "A\, B\, C,one\, two" --> ["A, B, C", "one, two"]
    1132      * @param delimiter the delimiter, e.g. a comma. separates the entries and
    1133      *      must be escaped within one entry
    1134      * @param s the string
    1135      */
    1136     private static String[] splitEscaped(char delimiter, String s) {
    1137         if (s == null)
    1138             return new String[0];
    1139         List<String> result = new ArrayList<String>();
    1140         boolean backslash = false;
    1141         StringBuilder item = new StringBuilder();
    1142         for (int i=0; i<s.length(); i++) {
    1143             char ch = s.charAt(i);
    1144             if (backslash) {
    1145                 item.append(ch);
    1146                 backslash = false;
    1147             } else if (ch == '\\') {
    1148                 backslash = true;
    1149             } else if (ch == delimiter) {
    1150                 result.add(item.toString());
    1151                 item.setLength(0);
    1152             } else {
    1153                 item.append(ch);
    1154             }
    1155         }
    1156         if (item.length() > 0) {
    1157             result.add(item.toString());
    1158         }
    1159         return result.toArray(new String[result.size()]);
    1160     }
    1161 
    1162     public static class Label extends Item {
    1163 
    1164         public String text;
    1165         public String text_context;
    1166         public String locale_text;
    1167 
    1168         @Override
    1169         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1170             if (locale_text == null) {
    1171                 if (text_context != null) {
    1172                     locale_text = trc(text_context, fixPresetString(text));
    1173                 } else {
    1174                     locale_text = tr(fixPresetString(text));
    1175                 }
    1176             }
    1177             p.add(new JLabel(locale_text), GBC.eol());
    1178             return false;
    1179         }
    1180 
    1181         @Override
    1182         public void addCommands(List<Tag> changedTags) {
    1183         }
    1184     }
    1185 
    1186     public static class Link extends Item {
    1187 
    1188         public String href;
    1189         public String text;
    1190         public String text_context;
    1191         public String locale_text;
    1192         public String locale_href;
    1193 
    1194         @Override
    1195         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1196             if (locale_text == null) {
    1197                 if (text == null) {
    1198                     locale_text = tr("More information about this feature");
    1199                 } else if (text_context != null) {
    1200                     locale_text = trc(text_context, fixPresetString(text));
    1201                 } else {
    1202                     locale_text = tr(fixPresetString(text));
    1203                 }
    1204             }
    1205             String url = locale_href;
    1206             if (url == null) {
    1207                 url = href;
    1208             }
    1209             if (url != null) {
    1210                 p.add(new UrlLabel(url, locale_text, 2), GBC.eol().anchor(GBC.WEST));
    1211             }
    1212             return false;
    1213         }
    1214 
    1215         @Override
    1216         public void addCommands(List<Tag> changedTags) {
    1217         }
    1218     }
    1219 
    1220     public static class Role {
    1221         public EnumSet<PresetType> types;
    1222         public String key;
    1223         public String text;
    1224         public String text_context;
    1225         public String locale_text;
    1226         public Match memberExpression;
    1227 
    1228         public boolean required = false;
    1229         public long count = 0;
    1230 
    1231         public void setType(String types) throws SAXException {
    1232             this.types = TaggingPreset.getType(types);
    1233         }
    1234 
    1235         public void setRequisite(String str) throws SAXException {
    1236             if("required".equals(str)) {
    1237                 required = true;
    1238             } else if(!"optional".equals(str))
    1239                 throw new SAXException(tr("Unknown requisite: {0}", str));
    1240         }
    1241 
    1242         public void setMember_expression(String member_expression) throws SAXException {
    1243             try {
    1244                 this.memberExpression = SearchCompiler.compile(member_expression, true, true);
    1245             } catch (SearchCompiler.ParseError ex) {
    1246                 throw new SAXException(tr("Illegal member expression: {0}", ex.getMessage()), ex);
    1247             }
    1248         }
    1249 
    1250         /* return either argument, the highest possible value or the lowest
    1251            allowed value */
    1252         public long getValidCount(long c)
    1253         {
    1254             if(count > 0 && !required)
    1255                 return c != 0 ? count : 0;
    1256             else if(count > 0)
    1257                 return count;
    1258             else if(!required)
    1259                 return c != 0  ? c : 0;
    1260             else
    1261                 return c != 0  ? c : 1;
    1262         }
    1263         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1264             String cstring;
    1265             if(count > 0 && !required) {
    1266                 cstring = "0,"+String.valueOf(count);
    1267             } else if(count > 0) {
    1268                 cstring = String.valueOf(count);
    1269             } else if(!required) {
    1270                 cstring = "0-...";
    1271             } else {
    1272                 cstring = "1-...";
    1273             }
    1274             if(locale_text == null) {
    1275                 if (text != null) {
    1276                     if(text_context != null) {
    1277                         locale_text = trc(text_context, fixPresetString(text));
    1278                     } else {
    1279                         locale_text = tr(fixPresetString(text));
    1280                     }
    1281                 }
    1282             }
    1283             p.add(new JLabel(locale_text+":"), GBC.std().insets(0,0,10,0));
    1284             p.add(new JLabel(key), GBC.std().insets(0,0,10,0));
    1285             p.add(new JLabel(cstring), types == null ? GBC.eol() : GBC.std().insets(0,0,10,0));
    1286             if(types != null){
    1287                 JPanel pp = new JPanel();
    1288                 for(PresetType t : types) {
    1289                     pp.add(new JLabel(ImageProvider.get(t.getIconName())));
    1290                 }
    1291                 p.add(pp, GBC.eol());
    1292             }
    1293             return true;
    1294         }
    1295     }
    1296 
    1297     public static class Roles extends Item {
    1298 
    1299         public final List<Role> roles = new LinkedList<Role>();
    1300 
    1301         @Override
    1302         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1303             p.add(new JLabel(" "), GBC.eol()); // space
    1304             if (roles.size() > 0) {
    1305                 JPanel proles = new JPanel(new GridBagLayout());
    1306                 proles.add(new JLabel(tr("Available roles")), GBC.std().insets(0, 0, 10, 0));
    1307                 proles.add(new JLabel(tr("role")), GBC.std().insets(0, 0, 10, 0));
    1308                 proles.add(new JLabel(tr("count")), GBC.std().insets(0, 0, 10, 0));
    1309                 proles.add(new JLabel(tr("elements")), GBC.eol());
    1310                 for (Role i : roles) {
    1311                     i.addToPanel(proles, sel);
    1312                 }
    1313                 p.add(proles, GBC.eol());
    1314             }
    1315             return false;
    1316         }
    1317 
    1318         @Override
    1319         public void addCommands(List<Tag> changedTags) {
    1320         }
    1321     }
    1322 
    1323     public static class Optional extends Item {
    1324 
    1325         // TODO: Draw a box around optional stuff
    1326         @Override
    1327         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1328             p.add(new JLabel(" "), GBC.eol()); // space
    1329             p.add(new JLabel(tr("Optional Attributes:")), GBC.eol());
    1330             p.add(new JLabel(" "), GBC.eol()); // space
    1331             return false;
    1332         }
    1333 
    1334         @Override
    1335         public void addCommands(List<Tag> changedTags) {
    1336         }
    1337     }
    1338 
    1339     public static class Space extends Item {
    1340 
    1341         @Override
    1342         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1343             p.add(new JLabel(" "), GBC.eol()); // space
    1344             return false;
    1345         }
    1346 
    1347         @Override
    1348         public void addCommands(List<Tag> changedTags) {
    1349         }
    1350     }
    1351 
    1352     public static class Key extends KeyedItem {
    1353 
    1354         public String value;
    1355 
    1356         @Override
    1357         public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
    1358             return false;
    1359         }
    1360 
    1361         @Override
    1362         public void addCommands(List<Tag> changedTags) {
    1363             changedTags.add(new Tag(key, value));
    1364         }
    1365 
    1366         @Override
    1367         public MatchType getDefaultMatch() {
    1368             return MatchType.KEY_VALUE;
    1369         }
    1370 
    1371         @Override
    1372         public Collection<String> getValues() {
    1373             return Collections.singleton(value);
    1374         }
    1375 
    1376         @Override
    1377         public String toString() {
    1378             return "Key [key=" + key + ", value=" + value + ", text=" + text
    1379                     + ", text_context=" + text_context + ", match=" + match
    1380                     + "]";
    1381         }
    1382     }
    1383 
     76   public final static String OPTIONAL_TOOLTIP_TEXT = "Optional tooltip text";
     77   
    138478    /**
    138579     * The types as preparsed collection.
    138680     */
    1387     public EnumSet<PresetType> types;
    1388     public List<Item> data = new LinkedList<Item>();
     81    public EnumSet<TaggingPresetType> types;
     82    public List<TaggingPresetItem> data = new LinkedList<TaggingPresetItem>();
    138983    public Roles roles;
    139084    public TemplateEntry nameTemplate;
    139185    public Match nameTemplateFilter;
    1392     private static final HashMap<String,String> lastValue = new HashMap<String,String>();
    1393     private static int auto_increment_selected = 0;
    1394 
     86   
    139587    /**
    139688     * Create an empty tagging preset. This will not have any items and
     
    1417109        if(locale_name == null) {
    1418110            if(name_context != null) {
    1419                 locale_name = trc(name_context, fixPresetString(name));
     111                locale_name = trc(name_context, TaggingPresetItems.fixPresetString(name));
    1420112            } else {
    1421                 locale_name = tr(fixPresetString(name));
     113                locale_name = tr(TaggingPresetItems.fixPresetString(name));
    1422114            }
    1423115        }
     
    1430122    public String getRawName() {
    1431123        return group != null ? group.getRawName() + "/" + name : name;
    1432     }
    1433 
    1434     protected static ImageIcon loadImageIcon(String iconName, File zipIcons, Integer maxSize) {
    1435         final Collection<String> s = Main.pref.getCollection("taggingpreset.icon.sources", null);
    1436         ImageProvider imgProv = new ImageProvider(iconName).setDirs(s).setId("presets").setArchive(zipIcons).setOptional(true);
    1437         if (maxSize != null) {
    1438             imgProv.setMaxSize(maxSize);
    1439         }
    1440         return imgProv.get();
    1441124    }
    1442125
     
    1453136        imgProv.setDirs(s);
    1454137        imgProv.setId("presets");
    1455         imgProv.setArchive(TaggingPreset.zipIcons);
     138        imgProv.setArchive(TaggingPresetReader.getZipIcons());
    1456139        imgProv.setOptional(true);
    1457140        imgProv.setMaxWidth(16).setMaxHeight(16);
     
    1473156    }
    1474157
    1475     // cache the parsing of types using a LRU cache (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
    1476     private static final Map<String,EnumSet<PresetType>> typeCache =
    1477             new LinkedHashMap<String, EnumSet<PresetType>>(16, 1.1f, true);
    1478 
    1479     static public EnumSet<PresetType> getType(String types) throws SAXException {
    1480         if (typeCache.containsKey(types))
    1481             return typeCache.get(types);
    1482         EnumSet<PresetType> result = EnumSet.noneOf(PresetType.class);
    1483         for (String type : Arrays.asList(types.split(","))) {
    1484             try {
    1485                 PresetType presetType = PresetType.fromString(type);
    1486                 result.add(presetType);
    1487             } catch (IllegalArgumentException e) {
    1488                 throw new SAXException(tr("Unknown type: {0}", type));
    1489             }
    1490         }
    1491         typeCache.put(types, result);
    1492         return result;
    1493     }
    1494 
    1495158    /*
    1496159     * Called from the XML parser to set the types this preset affects.
    1497160     */
    1498161    public void setType(String types) throws SAXException {
    1499         this.types = getType(types);
     162        this.types = TaggingPresetItems.getType(types);
    1500163    }
    1501164
     
    1518181    }
    1519182
    1520 
    1521     public static List<TaggingPreset> readAll(Reader in, boolean validate) throws SAXException {
    1522         XmlObjectParser parser = new XmlObjectParser();
    1523         parser.mapOnStart("item", TaggingPreset.class);
    1524         parser.mapOnStart("separator", TaggingPresetSeparator.class);
    1525         parser.mapBoth("group", TaggingPresetMenu.class);
    1526         parser.map("text", Text.class);
    1527         parser.map("link", Link.class);
    1528         parser.mapOnStart("optional", Optional.class);
    1529         parser.mapOnStart("roles", Roles.class);
    1530         parser.map("role", Role.class);
    1531         parser.map("check", Check.class);
    1532         parser.map("combo", Combo.class);
    1533         parser.map("multiselect", MultiSelect.class);
    1534         parser.map("label", Label.class);
    1535         parser.map("space", Space.class);
    1536         parser.map("key", Key.class);
    1537         parser.map("list_entry", PresetListEntry.class);
    1538         LinkedList<TaggingPreset> all = new LinkedList<TaggingPreset>();
    1539         TaggingPresetMenu lastmenu = null;
    1540         Roles lastrole = null;
    1541         List<PresetListEntry> listEntries = new LinkedList<PresetListEntry>();
    1542 
    1543         if (validate) {
    1544             parser.startWithValidation(in, "http://josm.openstreetmap.de/tagging-preset-1.0", "resource://data/tagging-preset.xsd");
    1545         } else {
    1546             parser.start(in);
    1547         }
    1548         while(parser.hasNext()) {
    1549             Object o = parser.next();
    1550             if (o instanceof TaggingPresetMenu) {
    1551                 TaggingPresetMenu tp = (TaggingPresetMenu) o;
    1552                 if(tp == lastmenu) {
    1553                     lastmenu = tp.group;
    1554                 } else
    1555                 {
    1556                     tp.group = lastmenu;
    1557                     tp.setDisplayName();
    1558                     lastmenu = tp;
    1559                     all.add(tp);
    1560 
    1561                 }
    1562                 lastrole = null;
    1563             } else if (o instanceof TaggingPresetSeparator) {
    1564                 TaggingPresetSeparator tp = (TaggingPresetSeparator) o;
    1565                 tp.group = lastmenu;
    1566                 all.add(tp);
    1567                 lastrole = null;
    1568             } else if (o instanceof TaggingPreset) {
    1569                 TaggingPreset tp = (TaggingPreset) o;
    1570                 tp.group = lastmenu;
    1571                 tp.setDisplayName();
    1572                 all.add(tp);
    1573                 lastrole = null;
    1574             } else {
    1575                 if (all.size() != 0) {
    1576                     if (o instanceof Roles) {
    1577                         all.getLast().data.add((Item) o);
    1578                         if (all.getLast().roles != null) {
    1579                             throw new SAXException(tr("Roles cannot appear more than once"));
    1580                         }
    1581                         all.getLast().roles = (Roles) o;
    1582                         lastrole = (Roles) o;
    1583                     } else if (o instanceof Role) {
    1584                         if (lastrole == null)
    1585                             throw new SAXException(tr("Preset role element without parent"));
    1586                         lastrole.roles.add((Role) o);
    1587                     } else if (o instanceof PresetListEntry) {
    1588                         listEntries.add((PresetListEntry) o);
    1589                     } else {
    1590                         all.getLast().data.add((Item) o);
    1591                         if (o instanceof ComboMultiSelect) {
    1592                             ((ComboMultiSelect) o).addListEntries(listEntries);
    1593                         } else if (o instanceof Key) {
    1594                             if (((Key) o).value == null) {
    1595                                 ((Key) o).value = ""; // Fix #8530
    1596                             }
    1597                         }
    1598                         listEntries = new LinkedList<PresetListEntry>();
    1599                         lastrole = null;
    1600                     }
    1601                 } else
    1602                     throw new SAXException(tr("Preset sub element without parent"));
    1603             }
    1604         }
    1605         return all;
    1606     }
    1607 
    1608     public static Collection<TaggingPreset> readAll(String source, boolean validate) throws SAXException, IOException {
    1609         Collection<TaggingPreset> tp;
    1610         MirroredInputStream s = new MirroredInputStream(source);
    1611         try {
    1612             InputStream zip = s.getZipEntry("xml","preset");
    1613             if(zip != null) {
    1614                 zipIcons = s.getFile();
    1615             }
    1616             InputStreamReader r;
    1617             try {
    1618                 r = new InputStreamReader(zip == null ? s : zip, "UTF-8");
    1619             } catch (UnsupportedEncodingException e) {
    1620                 r = new InputStreamReader(zip == null ? s: zip);
    1621             }
    1622             try {
    1623                 tp = TaggingPreset.readAll(new BufferedReader(r), validate);
    1624             } finally {
    1625                 Utils.close(r);
    1626             }
    1627         } finally {
    1628             Utils.close(s);
    1629         }
    1630         return tp;
    1631     }
    1632 
    1633     public static Collection<TaggingPreset> readAll(Collection<String> sources, boolean validate) {
    1634         LinkedList<TaggingPreset> allPresets = new LinkedList<TaggingPreset>();
    1635         for(String source : sources)  {
    1636             try {
    1637                 allPresets.addAll(TaggingPreset.readAll(source, validate));
    1638             } catch (IOException e) {
    1639                 System.err.println(e.getClass().getName()+": "+e.getMessage());
    1640                 System.err.println(source);
    1641                 JOptionPane.showMessageDialog(
    1642                         Main.parent,
    1643                         tr("Could not read tagging preset source: {0}",source),
    1644                         tr("Error"),
    1645                         JOptionPane.ERROR_MESSAGE
    1646                         );
    1647             } catch (SAXException e) {
    1648                 System.err.println(e.getClass().getName()+": "+e.getMessage());
    1649                 System.err.println(source);
    1650                 JOptionPane.showMessageDialog(
    1651                         Main.parent,
    1652                         tr("Error parsing {0}: ", source)+e.getMessage(),
    1653                         tr("Error"),
    1654                         JOptionPane.ERROR_MESSAGE
    1655                         );
    1656             }
    1657         }
    1658         return allPresets;
    1659     }
    1660 
    1661     public static LinkedList<String> getPresetSources() {
    1662         LinkedList<String> sources = new LinkedList<String>();
    1663 
    1664         for (SourceEntry e : (new PresetPrefHelper()).get()) {
    1665             sources.add(e.url);
    1666         }
    1667 
    1668         return sources;
    1669     }
    1670 
    1671     public static Collection<TaggingPreset> readFromPreferences(boolean validate) {
    1672         return readAll(getPresetSources(), validate);
    1673     }
    1674 
    1675183    private static class PresetPanel extends JPanel {
    1676184        boolean hasElements = false;
     
    1685193            return null;
    1686194        PresetPanel p = new PresetPanel();
    1687         LinkedList<Item> l = new LinkedList<Item>();
     195        LinkedList<TaggingPresetItem> l = new LinkedList<TaggingPresetItem>();
    1688196        if(types != null){
    1689197            JPanel pp = new JPanel();
    1690             for(PresetType t : types){
     198            for(TaggingPresetType t : types){
    1691199                JLabel la = new JLabel(ImageProvider.get(t.getIconName()));
    1692200                la.setToolTipText(tr("Elements of type {0} are supported.", tr(t.getName())));
     
    1697205
    1698206        JPanel items = new JPanel(new GridBagLayout());
    1699         for (Item i : data){
     207        for (TaggingPresetItem i : data){
    1700208            if(i instanceof Link) {
    1701209                l.add(i);
     
    1711219        }
    1712220
    1713         for(Item link : l) {
     221        for(TaggingPresetItem link : l) {
    1714222            link.addToPanel(p, selected);
    1715223        }
     
    1720228    public boolean isShowable()
    1721229    {
    1722         for(Item i : data)
     230        for(TaggingPresetItem i : data)
    1723231        {
    1724             if(!(i instanceof Optional || i instanceof Space || i instanceof Key))
     232            if(!(i instanceof TaggingPresetItems.Optional || i instanceof TaggingPresetItems.Space || i instanceof TaggingPresetItems.Key))
    1725233                return true;
    1726234        }
     
    1732240            for (Role i : roles.roles) {
    1733241                if (i.memberExpression != null && i.memberExpression.match(osm)
    1734                         && (i.types == null || i.types.isEmpty() || i.types.contains(PresetType.forPrimitive(osm)) )) {
     242                        && (i.types == null || i.types.isEmpty() || i.types.contains(TaggingPresetType.forPrimitive(osm)) )) {
    1735243                    return i.key;
    1736244                }
     
    1740248    }
    1741249
     250    @Override
    1742251    public void actionPerformed(ActionEvent e) {
    1743252        if (Main.main == null) return;
     
    1747256        int answer = showDialog(sel, supportsRelation());
    1748257
    1749         if (sel.size() != 0 && answer == DIALOG_ANSWER_APPLY) {
     258        if (!sel.isEmpty() && answer == DIALOG_ANSWER_APPLY) {
    1750259            Command cmd = createCommand(sel, getChangedTags());
    1751260            if (cmd != null) {
     
    1781290
    1782291        int answer = 1;
    1783         if (p.getComponentCount() != 0 && (sel.size() == 0 || p.hasElements)) {
     292        if (p.getComponentCount() != 0 && (sel.isEmpty() || p.hasElements)) {
    1784293            String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size());
    1785             if(sel.size() == 0) {
     294            if(sel.isEmpty()) {
    1786295                if(originalSelectionEmpty) {
    1787296                    title = tr("Nothing selected!");
     
    1849358                if(osm instanceof Relation)
    1850359                {
    1851                     if(!types.contains(PresetType.RELATION) &&
    1852                             !(types.contains(PresetType.CLOSEDWAY) && ((Relation)osm).isMultipolygon())) {
     360                    if(!types.contains(TaggingPresetType.RELATION) &&
     361                            !(types.contains(TaggingPresetType.CLOSEDWAY) && ((Relation)osm).isMultipolygon())) {
    1853362                        continue;
    1854363                    }
     
    1856365                else if(osm instanceof Node)
    1857366                {
    1858                     if(!types.contains(PresetType.NODE)) {
     367                    if(!types.contains(TaggingPresetType.NODE)) {
    1859368                        continue;
    1860369                    }
     
    1862371                else if(osm instanceof Way)
    1863372                {
    1864                     if(!types.contains(PresetType.WAY) &&
    1865                             !(types.contains(PresetType.CLOSEDWAY) && ((Way)osm).isClosed())) {
     373                    if(!types.contains(TaggingPresetType.WAY) &&
     374                            !(types.contains(TaggingPresetType.CLOSEDWAY) && ((Way)osm).isClosed())) {
    1866375                        continue;
    1867376                    }
     
    1875384    public List<Tag> getChangedTags() {
    1876385        List<Tag> result = new ArrayList<Tag>();
    1877         for (Item i: data) {
     386        for (TaggingPresetItem i: data) {
    1878387            i.addCommands(result);
    1879388        }
    1880389        return result;
    1881     }
    1882 
    1883     private static String fixPresetString(String s) {
    1884         return s == null ? s : s.replaceAll("'","''");
    1885390    }
    1886391
     
    1900405
    1901406    private boolean supportsRelation() {
    1902         return types == null || types.contains(PresetType.RELATION);
     407        return types == null || types.contains(TaggingPresetType.RELATION);
    1903408    }
    1904409
     
    1907412    }
    1908413
     414    @Override
    1909415    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
    1910416        updateEnabledState();
    1911417    }
    1912418
     419    @Override
    1913420    public void layerAdded(Layer newLayer) {
    1914421        updateEnabledState();
    1915422    }
    1916423
     424    @Override
    1917425    public void layerRemoved(Layer oldLayer) {
    1918426        updateEnabledState();
     
    1924432    }
    1925433
    1926     public boolean typeMatches(Collection<PresetType> t) {
     434    public boolean typeMatches(Collection<TaggingPresetType> t) {
    1927435        return t == null || types == null || types.containsAll(t);
    1928436    }
    1929437
    1930     public boolean matches(Collection<PresetType> t, Map<String, String> tags, boolean onlyShowable) {
     438    public boolean matches(Collection<TaggingPresetType> t, Map<String, String> tags, boolean onlyShowable) {
    1931439        if (onlyShowable && !isShowable())
    1932440            return false;
     
    1934442            return false;
    1935443        boolean atLeastOnePositiveMatch = false;
    1936         for (Item item : data) {
     444        for (TaggingPresetItem item : data) {
    1937445            Boolean m = item.matches(tags);
    1938446            if (m != null && !m)
     
    1945453    }
    1946454
    1947     public static Collection<TaggingPreset> getMatchingPresets(final Collection<PresetType> t, final Map<String, String> tags, final boolean onlyShowable) {
     455    public static Collection<TaggingPreset> getMatchingPresets(final Collection<TaggingPresetType> t, final Map<String, String> tags, final boolean onlyShowable) {
    1948456        return Utils.filter(TaggingPresetPreference.taggingPresets, new Predicate<TaggingPreset>() {
    1949457            @Override
  • trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java

    r5954 r6068  
    2222public class TaggingPresetMenu extends TaggingPreset {
    2323    public JMenu menu = null; // set by TaggingPresetPreferences
     24    @Override
    2425    public void setDisplayName() {
    2526        putValue(Action.NAME, getName());
     
    3031        putValue("toolbar", "tagginggroup_" + getRawName());
    3132    }
     33    @Override
    3234    public void setIcon(String iconName) {
    3335        super.setIcon(iconName);
     
    5557    }
    5658
     59    @Override
    5760    public void actionPerformed(ActionEvent e) {
    5861        Object s = e.getSource();
  • trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java

    r5899 r6068  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.BorderLayout;
    7 import java.awt.Component;
    8 import java.awt.Dimension;
    96import java.awt.event.ActionEvent;
    10 import java.awt.event.ItemEvent;
    11 import java.awt.event.ItemListener;
    12 import java.awt.event.KeyAdapter;
    13 import java.awt.event.KeyEvent;
    14 import java.awt.event.MouseAdapter;
    15 import java.awt.event.MouseEvent;
    16 import java.util.ArrayList;
    17 import java.util.Collection;
    18 import java.util.Collections;
    19 import java.util.EnumSet;
    20 import java.util.HashSet;
    21 import java.util.List;
    22 
    23 import javax.swing.AbstractListModel;
    24 import javax.swing.Action;
    25 import javax.swing.BoxLayout;
    26 import javax.swing.DefaultListCellRenderer;
    27 import javax.swing.Icon;
    28 import javax.swing.JCheckBox;
    29 import javax.swing.JLabel;
    30 import javax.swing.JList;
    31 import javax.swing.JPanel;
    32 import javax.swing.JScrollPane;
    33 import javax.swing.event.DocumentEvent;
    34 import javax.swing.event.DocumentListener;
     7import java.awt.event.ActionListener;
    358
    369import org.openstreetmap.josm.Main;
    37 import org.openstreetmap.josm.data.SelectionChangedListener;
    3810import org.openstreetmap.josm.data.osm.DataSet;
    39 import org.openstreetmap.josm.data.osm.Node;
    40 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    41 import org.openstreetmap.josm.data.osm.Relation;
    42 import org.openstreetmap.josm.data.osm.Way;
    43 import org.openstreetmap.josm.data.preferences.BooleanProperty;
    4411import org.openstreetmap.josm.gui.ExtendedDialog;
    45 import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
    46 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Item;
    47 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Key;
    48 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
    49 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Role;
    50 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Roles;
    51 import org.openstreetmap.josm.gui.widgets.JosmTextField;
    5212
    5313
    54 public class TaggingPresetSearchDialog extends ExtendedDialog implements SelectionChangedListener {
     14public class TaggingPresetSearchDialog extends ExtendedDialog {
    5515
    56     private static final int CLASSIFICATION_IN_FAVORITES = 300;
    57     private static final int CLASSIFICATION_NAME_MATCH = 300;
    58     private static final int CLASSIFICATION_GROUP_MATCH = 200;
    59     private static final int CLASSIFICATION_TAGS_MATCH = 100;
    60 
    61     private static final BooleanProperty SEARCH_IN_TAGS = new BooleanProperty("taggingpreset.dialog.search-in-tags", true);
    62     private static final BooleanProperty ONLY_APPLICABLE  = new BooleanProperty("taggingpreset.dialog.only-applicable-to-selection", true);
    63 
    64     private static class ResultListCellRenderer extends DefaultListCellRenderer {
    65         @Override
    66         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
    67                 boolean cellHasFocus) {
    68             JLabel result = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    69             TaggingPreset tp = (TaggingPreset)value;
    70             result.setText(tp.getName());
    71             result.setIcon((Icon) tp.getValue(Action.SMALL_ICON));
    72             return result;
    73         }
    74     }
    75 
    76     private static class ResultListModel extends AbstractListModel {
    77 
    78         private List<PresetClasification> presets = new ArrayList<PresetClasification>();
    79 
    80         public void setPresets(List<PresetClasification> presets) {
    81             this.presets = presets;
    82             fireContentsChanged(this, 0, Integer.MAX_VALUE);
    83         }
    84 
    85         public List<PresetClasification> getPresets() {
    86             return presets;
    87         }
    88 
    89         @Override
    90         public Object getElementAt(int index) {
    91             return presets.get(index).preset;
    92         }
    93 
    94         @Override
    95         public int getSize() {
    96             return presets.size();
    97         }
    98 
    99     }
    100 
    101     private static class PresetClasification implements Comparable<PresetClasification> {
    102         public final TaggingPreset preset;
    103         public int classification;
    104         public int favoriteIndex;
    105         private final Collection<String> groups = new HashSet<String>();
    106         private final Collection<String> names = new HashSet<String>();
    107         private final Collection<String> tags = new HashSet<String>();
    108 
    109         PresetClasification(TaggingPreset preset) {
    110             this.preset = preset;
    111             TaggingPreset group = preset.group;
    112             while (group != null) {
    113                 for (String word: group.getLocaleName().toLowerCase().split("\\s")) {
    114                     groups.add(word);
    115                 }
    116                 group = group.group;
    117             }
    118             for (String word: preset.getLocaleName().toLowerCase().split("\\s")) {
    119                 names.add(word);
    120             }
    121             for (Item item: preset.data) {
    122                 if (item instanceof TaggingPreset.KeyedItem) {
    123                     tags.add(((TaggingPreset.KeyedItem) item).key);
    124                     // Should combo values also be added?
    125                     if (item instanceof Key && ((Key) item).value != null) {
    126                         tags.add(((Key) item).value);
    127                     }
    128                 } else if (item instanceof Roles) {
    129                     for (Role role : ((Roles) item).roles) {
    130                         tags.add(role.key);
    131                     }
    132                 }
    133             }
    134         }
    135 
    136         private int isMatching(Collection<String> values, String[] searchString) {
    137             int sum = 0;
    138             for (String word: searchString) {
    139                 boolean found = false;
    140                 boolean foundFirst = false;
    141                 for (String value: values) {
    142                     int index = value.indexOf(word);
    143                     if (index == 0) {
    144                         foundFirst = true;
    145                         break;
    146                     } else if (index > 0) {
    147                         found = true;
    148                     }
    149                 }
    150                 if (foundFirst) {
    151                     sum += 2;
    152                 } else if (found) {
    153                     sum += 1;
    154                 } else
    155                     return 0;
    156             }
    157             return sum;
    158         }
    159 
    160         int isMatchingGroup(String[] words) {
    161             return isMatching(groups, words);
    162         }
    163 
    164         int isMatchingName(String[] words) {
    165             return isMatching(names, words);
    166         }
    167 
    168         int isMatchingTags(String[] words) {
    169             return isMatching(tags, words);
    170         }
    171 
    172         @Override
    173         public int compareTo(PresetClasification o) {
    174             int result = o.classification - classification;
    175             if (result == 0)
    176                 return preset.getName().compareTo(o.preset.getName());
    177             else
    178                 return result;
    179         }
    180 
    181         @Override
    182         public String toString() {
    183             return classification + " " + preset.toString();
    184         }
    185     }
     16    private TaggingPresetSelector selector;
    18617
    18718    private static TaggingPresetSearchDialog instance;
     
    19223        return instance;
    19324    }
    194 
    195     private JosmTextField edSearchText;
    196     private JList lsResult;
    197     private JCheckBox ckOnlyApplicable;
    198     private JCheckBox ckSearchInTags;
    199     private final EnumSet<PresetType> typesInSelection = EnumSet.noneOf(PresetType.class);
    200     private boolean typesInSelectionDirty = true;
    201     private final List<PresetClasification> classifications = new ArrayList<PresetClasification>();
    202     private ResultListModel lsResultModel = new ResultListModel();
    203 
    20425    private TaggingPresetSearchDialog() {
    20526        super(Main.parent, tr("Presets"), new String[] {tr("Select"), tr("Cancel")});
    206         DataSet.addSelectionListener(this);
    207 
    208         for (TaggingPreset preset: TaggingPresetPreference.taggingPresets) {
    209             if (preset instanceof TaggingPresetSeparator || preset instanceof TaggingPresetMenu) {
    210                 continue;
     27        selector = new TaggingPresetSelector();
     28        setContent(selector);
     29        DataSet.addSelectionListener(selector);
     30        selector.setDblClickListener(new ActionListener() {
     31            @Override
     32            public void actionPerformed(ActionEvent e) {
     33                buttonAction(0, null);
    21134            }
    212 
    213             classifications.add(new PresetClasification(preset));
    214         }
    215 
    216         build();
    217         filterPresets();
    218     }
    219 
    220     @Override
    221     public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    222         typesInSelectionDirty = true;
     35        });
    22336    }
    22437
    22538    @Override
    22639    public ExtendedDialog showDialog() {
    227 
    228         ckOnlyApplicable.setEnabled(!getTypesInSelection().isEmpty());
    229         ckOnlyApplicable.setSelected(!getTypesInSelection().isEmpty() && ONLY_APPLICABLE.get());
    230         edSearchText.setText("");
    231         filterPresets();
    232 
     40        selector.init();
    23341        super.showDialog();
    234         lsResult.getSelectionModel().clearSelection();
     42        selector.clearSelection();
    23543        return this;
    236     }
    237 
    238     private void build() {
    239         JPanel content = new JPanel();
    240         content.setLayout(new BorderLayout());
    241 
    242         edSearchText = new JosmTextField();
    243         edSearchText.getDocument().addDocumentListener(new DocumentListener() {
    244 
    245             @Override
    246             public void removeUpdate(DocumentEvent e) {
    247                 filterPresets();
    248             }
    249 
    250             @Override
    251             public void insertUpdate(DocumentEvent e) {
    252                 filterPresets();
    253 
    254             }
    255 
    256             @Override
    257             public void changedUpdate(DocumentEvent e) {
    258                 filterPresets();
    259 
    260             }
    261         });
    262         edSearchText.addKeyListener(new KeyAdapter() {
    263             @Override
    264             public void keyPressed(KeyEvent e) {
    265                 switch (e.getKeyCode()) {
    266                 case KeyEvent.VK_DOWN:
    267                     selectPreset(lsResult.getSelectedIndex() + 1);
    268                     break;
    269                 case KeyEvent.VK_UP:
    270                     selectPreset(lsResult.getSelectedIndex() - 1);
    271                     break;
    272                 case KeyEvent.VK_PAGE_DOWN:
    273                     selectPreset(lsResult.getSelectedIndex() + 10);
    274                     break;
    275                 case KeyEvent.VK_PAGE_UP:
    276                     selectPreset(lsResult.getSelectedIndex() - 10);
    277                     break;
    278                 case KeyEvent.VK_HOME:
    279                     selectPreset(0);
    280                     break;
    281                 case KeyEvent.VK_END:
    282                     selectPreset(lsResultModel.getSize());
    283                     break;
    284                 }
    285             }
    286         });
    287         content.add(edSearchText, BorderLayout.NORTH);
    288 
    289         lsResult = new JList();
    290         lsResult.setModel(lsResultModel);
    291         lsResult.setCellRenderer(new ResultListCellRenderer());
    292         lsResult.addMouseListener(new MouseAdapter() {
    293             @Override
    294             public void mouseClicked(MouseEvent e) {
    295                 if (e.getClickCount()>1) {
    296                     buttonAction(0, null);
    297                 }
    298             }
    299         });
    300         content.add(new JScrollPane(lsResult), BorderLayout.CENTER);
    301 
    302         JPanel pnChecks = new JPanel();
    303         pnChecks.setLayout(new BoxLayout(pnChecks, BoxLayout.Y_AXIS));
    304 
    305         ckOnlyApplicable = new JCheckBox();
    306         ckOnlyApplicable.setText(tr("Show only applicable to selection"));
    307         pnChecks.add(ckOnlyApplicable);
    308         ckOnlyApplicable.addItemListener(new ItemListener() {
    309             @Override
    310             public void itemStateChanged(ItemEvent e) {
    311                 filterPresets();
    312             }
    313         });
    314 
    315         ckSearchInTags = new JCheckBox();
    316         ckSearchInTags.setText(tr("Search in tags"));
    317         ckSearchInTags.setSelected(SEARCH_IN_TAGS.get());
    318         ckSearchInTags.addItemListener(new ItemListener() {
    319             @Override
    320             public void itemStateChanged(ItemEvent e) {
    321                 filterPresets();
    322             }
    323         });
    324         pnChecks.add(ckSearchInTags);
    325 
    326         content.add(pnChecks, BorderLayout.SOUTH);
    327 
    328         content.setPreferredSize(new Dimension(400, 300));
    329         setContent(content);
    330     }
    331 
    332     private void selectPreset(int newIndex) {
    333         if (newIndex < 0) {
    334             newIndex = 0;
    335         }
    336         if (newIndex > lsResultModel.getSize() - 1) {
    337             newIndex = lsResultModel.getSize() - 1;
    338         }
    339         lsResult.setSelectedIndex(newIndex);
    340         lsResult.ensureIndexIsVisible(newIndex);
    341     }
    342 
    343     /**
    344      * Search expression can be in form: "group1/group2/name" where names can contain multiple words
    345      */
    346     private void filterPresets() {
    347         //TODO Save favorites to file
    348         String text = edSearchText.getText().toLowerCase();
    349 
    350         String[] groupWords;
    351         String[] nameWords;
    352 
    353         if (text.contains("/")) {
    354             groupWords = text.substring(0, text.lastIndexOf('/')).split("[\\s/]");
    355             nameWords = text.substring(text.indexOf('/') + 1).split("\\s");
    356         } else {
    357             groupWords = null;
    358             nameWords = text.split("\\s");
    359         }
    360 
    361         boolean onlyApplicable = ckOnlyApplicable.isSelected();
    362         boolean inTags = ckSearchInTags.isSelected();
    363 
    364         List<PresetClasification> result = new ArrayList<PresetClasification>();
    365         PRESET_LOOP:
    366             for (PresetClasification presetClasification: classifications) {
    367                 TaggingPreset preset = presetClasification.preset;
    368                 presetClasification.classification = 0;
    369 
    370                 if (onlyApplicable && preset.types != null) {
    371                     boolean found = false;
    372                     for (PresetType type: preset.types) {
    373                         if (getTypesInSelection().contains(type)) {
    374                             found = true;
    375                             break;
    376                         }
    377                     }
    378                     if (!found) {
    379                         continue;
    380                     }
    381                 }
    382 
    383 
    384 
    385                 if (groupWords != null && presetClasification.isMatchingGroup(groupWords) == 0) {
    386                     continue PRESET_LOOP;
    387                 }
    388 
    389                 int matchName = presetClasification.isMatchingName(nameWords);
    390 
    391                 if (matchName == 0) {
    392                     if (groupWords == null) {
    393                         int groupMatch = presetClasification.isMatchingGroup(nameWords);
    394                         if (groupMatch > 0) {
    395                             presetClasification.classification = CLASSIFICATION_GROUP_MATCH + groupMatch;
    396                         }
    397                     }
    398                     if (presetClasification.classification == 0 && inTags) {
    399                         int tagsMatch = presetClasification.isMatchingTags(nameWords);
    400                         if (tagsMatch > 0) {
    401                             presetClasification.classification = CLASSIFICATION_TAGS_MATCH + tagsMatch;
    402                         }
    403                     }
    404                 } else {
    405                     presetClasification.classification = CLASSIFICATION_NAME_MATCH + matchName;
    406                 }
    407 
    408                 if (presetClasification.classification > 0) {
    409                     presetClasification.classification += presetClasification.favoriteIndex;
    410                     result.add(presetClasification);
    411                 }
    412             }
    413 
    414         Collections.sort(result);
    415         lsResultModel.setPresets(result);
    416         if (!buttons.isEmpty()) {
    417             buttons.get(0).setEnabled(!result.isEmpty());
    418         }
    419     }
    420 
    421     private EnumSet<PresetType> getTypesInSelection() {
    422         if (typesInSelectionDirty) {
    423             synchronized (typesInSelection) {
    424                 typesInSelectionDirty = false;
    425                 typesInSelection.clear();
    426                 for (OsmPrimitive primitive : Main.main.getCurrentDataSet().getSelected()) {
    427                     if (primitive instanceof Node) {
    428                         typesInSelection.add(PresetType.NODE);
    429                     } else if (primitive instanceof Way) {
    430                         typesInSelection.add(PresetType.WAY);
    431                         if (((Way) primitive).isClosed()) {
    432                             typesInSelection.add(PresetType.CLOSEDWAY);
    433                         }
    434                     } else if (primitive instanceof Relation) {
    435                         typesInSelection.add(PresetType.RELATION);
    436                     }
    437                 }
    438             }
    439         }
    440         return typesInSelection;
    44144    }
    44245
     
    44548        super.buttonAction(buttonIndex, evt);
    44649        if (buttonIndex == 0) {
    447             int selectPreset = lsResult.getSelectedIndex();
    448             if (selectPreset == -1) {
    449                 selectPreset = 0;
    450             }
    451             TaggingPreset preset = lsResultModel.getPresets().get(selectPreset).preset;
    452             for (PresetClasification pc: classifications) {
    453                 if (pc.preset == preset) {
    454                     pc.favoriteIndex = CLASSIFICATION_IN_FAVORITES;
    455                 } else if (pc.favoriteIndex > 0) {
    456                     pc.favoriteIndex--;
    457                 }
    458             }
     50            TaggingPreset preset = selector.getSelectedPreset();
    45951            preset.actionPerformed(null);
    46052        }
    461 
    462         SEARCH_IN_TAGS.put(ckSearchInTags.isSelected());
    463         if (ckOnlyApplicable.isEnabled()) {
    464             ONLY_APPLICABLE.put(ckOnlyApplicable.isSelected());
    465         }
     53        selector.savePreferences();
    46654    }
    467 
    46855}
  • trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSeparator.java

    r3083 r6068  
    33
    44public class TaggingPresetSeparator extends TaggingPreset {
     5    @Override
    56    public void setDisplayName() {}
    67}
  • trunk/src/org/openstreetmap/josm/gui/tagging/ac/AutoCompletionManager.java

    r5926 r6068  
    2626import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
    2727import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     28import org.openstreetmap.josm.gui.tagging.TaggingPresetItem;
     29import org.openstreetmap.josm.gui.tagging.TaggingPresetItems;
    2830import org.openstreetmap.josm.tools.MultiMap;
    2931
     
    147149    public static void cachePresets(Collection<TaggingPreset> presets) {
    148150        for (final TaggingPreset p : presets) {
    149             for (TaggingPreset.Item item : p.data) {
    150                 if (item instanceof TaggingPreset.KeyedItem) {
    151                     TaggingPreset.KeyedItem ki = (TaggingPreset.KeyedItem) item;
     151            for (TaggingPresetItem item : p.data) {
     152                if (item instanceof TaggingPresetItems.KeyedItem) {
     153                    TaggingPresetItems.KeyedItem ki = (TaggingPresetItems.KeyedItem) item;
    152154                    if (ki.key != null && ki.getValues() != null) {
    153155                        try {
     
    157159                        }
    158160                    }
    159                 } else if (item instanceof TaggingPreset.Roles) {
    160                     TaggingPreset.Roles r = (TaggingPreset.Roles) item;
    161                     for (TaggingPreset.Role i : r.roles) {
     161                } else if (item instanceof TaggingPresetItems.Roles) {
     162                    TaggingPresetItems.Roles r = (TaggingPresetItems.Roles) item;
     163                    for (TaggingPresetItems.Role i : r.roles) {
    162164                        if (i.key != null) {
    163165                            presetRoleCache.add(i.key);
     
    288290     **/
    289291
     292    @Override
    290293    public void primitivesAdded(PrimitivesAddedEvent event) {
    291294        if (dirty)
     
    294297    }
    295298
     299    @Override
    296300    public void primitivesRemoved(PrimitivesRemovedEvent event) {
    297301        dirty = true;
    298302    }
    299303
     304    @Override
    300305    public void tagsChanged(TagsChangedEvent event) {
    301306        if (dirty)
     
    319324    }
    320325
     326    @Override
    321327    public void nodeMoved(NodeMovedEvent event) {/* ignored */}
    322328
     329    @Override
    323330    public void wayNodesChanged(WayNodesChangedEvent event) {/* ignored */}
    324331
     332    @Override
    325333    public void relationMembersChanged(RelationMembersChangedEvent event) {
    326334        dirty = true; // TODO: not necessary to rebuid if a member is added
    327335    }
    328336
     337    @Override
    329338    public void otherDatasetChange(AbstractDatasetChangedEvent event) {/* ignored */}
    330339
     340    @Override
    331341    public void dataChanged(DataChangedEvent event) {
    332342        dirty = true;
  • trunk/src/org/openstreetmap/josm/tools/TaggingPresetNameTemplateList.java

    r5169 r6068  
    1010import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
    1111import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    12 import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
     12import org.openstreetmap.josm.gui.tagging.TaggingPresetType;
    1313
    1414/**
     
    4040
    4141        for (TaggingPreset t : presetsWithPattern) {
    42             Collection<PresetType> type = Collections.singleton(PresetType.forPrimitive(primitive));
     42            Collection<TaggingPresetType> type = Collections.singleton(TaggingPresetType.forPrimitive(primitive));
    4343            if (t.typeMatches(type)) {
    4444                if (t.nameTemplateFilter != null) {
Note: See TracChangeset for help on using the changeset viewer.