Ignore:
Timestamp:
2012-04-01T19:48:01+02:00 (12 years ago)
Author:
simon04
Message:

fix #5933 - tagging presets: allow to change the matching process (match=none|key|key!|keyvalue), remove delete_if_empty, default defaults to "", adapted comments in defaultpresets.xml, refactoring of the matching process (removes some duplicate code and some magical arithmetic)

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java

    r4968 r5155  
    1111import java.util.Collection;
    1212import java.util.Collections;
    13 import java.util.Hashtable;
    1413import java.util.List;
    1514import java.util.Map;
     
    2423import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
    2524import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    26 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Check;
    27 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Combo;
    2825import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
    29 import org.openstreetmap.josm.gui.tagging.TaggingPreset.Text;
    3026import org.openstreetmap.josm.tools.GBC;
    3127
     
    8278    }
    8379
    84     public void updatePresets(int nodes, int ways, int relations, int closedways, Map<String, Map<String, Integer>> valueCount, PresetHandler presetHandler) {
     80    public void updatePresets(final Collection<PresetType> types, final Map<String, String> tags, PresetHandler presetHandler) {
    8581
    8682        removeAll();
    87         int total = nodes+ways+relations+closedways;
    88         if(total == 0) {
     83        if (types.isEmpty()) {
    8984            setVisible(false);
    9085            return;
    9186        }
    9287
    93         for(TaggingPreset t : TaggingPresetPreference.taggingPresets) {
    94             if(
    95                     (       t.types == null
    96                             || (relations > 0 && t.types.contains(PresetType.RELATION))
    97                             || (nodes > 0 && t.types.contains(PresetType.NODE))
    98                             || (ways+closedways > 0 && t.types.contains(PresetType.WAY))
    99                             || (closedways > 0 && t.types.contains(PresetType.CLOSEDWAY))
    100                     )
    101                     && t.isShowable())
    102             {
    103                 int found = 0;
    104                 for(TaggingPreset.Item i : t.data) {
    105                     if(i instanceof TaggingPreset.Key) {
    106                         String val = ((TaggingPreset.Key)i).value;
    107                         String key = ((TaggingPreset.Key)i).key;
    108                         // we subtract 100 if not found and add 1 if found
    109                         found -= 100;
    110                         if(key == null || !valueCount.containsKey(key)) {
    111                             continue;
    112                         }
     88        for (TaggingPreset t : TaggingPresetPreference.taggingPresets) {
     89            if (!t.matches(types, tags)) {
     90                continue;
     91            }
    11392
    114                         Map<String, Integer> v = valueCount.get(key);
    115                         if(v.size() == 1 && val != null && v.containsKey(val) && v.get(val) == total) {
    116                             found += 101;
    117                         }
    118                     } else {
    119                         String key = null;
    120                         if ((i instanceof Text) && ((Text)i).required) {
    121                             key = ((Text)i).key;
    122                         } else if ((i instanceof Combo) && ((Combo)i).required) {
    123                             key = ((Combo)i).key;
    124                         } else if ((i instanceof Check) && ((Check)i).required) {
    125                             key = ((Check)i).key;
    126                         }
    127                         if (key != null) {
    128                             if (valueCount.get(key) != null) {
    129                                 found += 1;
    130                             } else {
    131                                 found -= 100;
    132                             }
    133                         }
    134                     }
    135                 }
    136 
    137                 if(found <= 0) {
    138                     continue;
    139                 }
    140 
    141                 JLabel lbl = new JLabel(t.getName() + " …");
    142                 lbl.setIcon((Icon) t.getValue(Action.SMALL_ICON));
    143                 lbl.addMouseListener(new PresetLabelML(lbl, t, presetHandler));
    144                 add(lbl, GBC.eol().fill(GBC.HORIZONTAL));
    145             }
     93            JLabel lbl = new JLabel(t.getName() + " …");
     94            lbl.setIcon((Icon) t.getValue(Action.SMALL_ICON));
     95            lbl.addMouseListener(new PresetLabelML(lbl, t, presetHandler));
     96            add(lbl, GBC.eol().fill(GBC.HORIZONTAL));
    14697        }
    14798
    148         if(getComponentCount() > 0) {
     99        if (getComponentCount() > 0) {
    149100            setVisible(true);
    150101            // This ensures the presets are exactly as high as needed.
     
    157108        }
    158109    }
    159 
    160110}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java

    r5109 r5155  
    3131import java.util.Collections;
    3232import java.util.Comparator;
     33import java.util.EnumSet;
    3334import java.util.HashMap;
    3435import java.util.HashSet;
     
    104105import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    105106import org.openstreetmap.josm.gui.tagging.TaggingPreset;
     107import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
    106108import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
    107109import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
     
    261263                        index, isSelected, cellHasFocus);
    262264                if (c instanceof JLabel) {
    263                     String str = null;
    264                     str=((AutoCompletionListItem) value).getValue();
    265                     if (valueCount.containsKey(objKey)){
    266                         Map<String, Integer> m=valueCount.get(objKey);
     265                    String str = ((AutoCompletionListItem) value).getValue();
     266                    if (valueCount.containsKey(objKey)) {
     267                        Map<String, Integer> m = valueCount.get(objKey);
    267268                        if (m.containsKey(str)) {
    268                             str+="("+m.get(str)+")";
    269                             c.setFont(c.getFont().deriveFont(Font.ITALIC+Font.BOLD));
     269                            str = tr("{0} ({1})", str, m.get(str));
     270                            c.setFont(c.getFont().deriveFont(Font.ITALIC + Font.BOLD));
    270271                        }
    271272                    }
    272                     ((JLabel)c).setText(str);
     273                    ((JLabel) c).setText(str);
    273274                }
    274275                return c;
     
    947948        // re-load property data
    948949        propertyData.setRowCount(0);
    949         int nodes = 0;
    950         int ways = 0;
    951         int relations = 0;
    952         int closedways = 0;
    953 
    954         Map<String, Integer> keyCount = new HashMap<String, Integer>();
     950
     951        final Map<String, Integer> keyCount = new HashMap<String, Integer>();
     952        final Map<String, String> tags = new HashMap<String, String>();
    955953        valueCount.clear();
     954        EnumSet<PresetType> types = EnumSet.noneOf(TaggingPreset.PresetType.class);
    956955        for (OsmPrimitive osm : newSelection) {
    957             if(osm instanceof Node) {
    958                 ++nodes;
    959             } else if(osm instanceof Relation) {
    960                 ++relations;
    961             } else if(((Way)osm).isClosed()) {
    962                 ++closedways;
    963             } else {
    964                 ++ways;
    965             }
    966             for (String key: osm.keySet()) {
     956            types.add(PresetType.forPrimitive(osm));
     957            for (String key : osm.keySet()) {
    967958                String value = osm.get(key);
    968959                keyCount.put(key, keyCount.containsKey(key) ? keyCount.get(key) + 1 : 1);
    969960                if (valueCount.containsKey(key)) {
    970961                    Map<String, Integer> v = valueCount.get(key);
    971                     v.put(value, v.containsKey(value)? v.get(value) + 1 : 1 );
     962                    v.put(value, v.containsKey(value) ? v.get(value) + 1 : 1);
    972963                } else {
    973                     TreeMap<String,Integer> v = new TreeMap<String, Integer>();
     964                    TreeMap<String, Integer> v = new TreeMap<String, Integer>();
    974965                    v.put(value, 1);
    975966                    valueCount.put(key, v);
     
    978969        }
    979970        for (Entry<String, Map<String, Integer>> e : valueCount.entrySet()) {
    980             int count=0;
    981             for (Entry<String, Integer> e1: e.getValue().entrySet()) {
    982                 count+=e1.getValue();
     971            int count = 0;
     972            for (Entry<String, Integer> e1 : e.getValue().entrySet()) {
     973                count += e1.getValue();
    983974            }
    984975            if (count < newSelection.size()) {
    985                 e.getValue().put("", newSelection.size()-count);
     976                e.getValue().put("", newSelection.size() - count);
    986977            }
    987978            propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
     979            tags.put(e.getKey(), e.getValue().size() == 1
     980                    ? e.getValue().keySet().iterator().next() : tr("<different>"));
    988981        }
    989982
     
    10261019        }
    10271020
    1028         presets.updatePresets(nodes, ways, relations, closedways, valueCount, presetHandler);
     1021        presets.updatePresets(types, tags, presetHandler);
    10291022
    10301023        membershipTable.getTableHeader().setVisible(membershipData.getRowCount() > 0);
  • trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorPanel.java

    r4191 r5155  
    66import java.awt.GridBagLayout;
    77import java.awt.Insets;
    8 import java.util.HashMap;
    9 import java.util.Map;
    10 import java.util.Map.Entry;
     8import java.util.EnumSet;
    119
    1210import javax.swing.BoxLayout;
     
    181179
    182180    private void updatePresets() {
    183         Map<String, Map<String, Integer>> valuesCount = new HashMap<String, Map<String,Integer>>();
    184         for (Entry<String, String> entry: model.getTags().entrySet()) {
    185             Map<String, Integer> values = new HashMap<String, Integer>();
    186             values.put(entry.getValue(), 1);
    187             valuesCount.put(entry.getKey(), values);
    188         }
    189         presetListPanel.updatePresets(0, 0, 1, 0, valuesCount, presetHandler);
     181        presetListPanel.updatePresets(
     182                EnumSet.of(TaggingPreset.PresetType.RELATION),
     183                model.getTags(), presetHandler);
    190184        validate();
    191185    }
  • trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java

    r5147 r5155  
    108108            return name().toLowerCase();
    109109        }
     110
     111        public static PresetType forPrimitive(OsmPrimitive p) {
     112            return forPrimitiveType(p.getDisplayType());
     113        }
     114
     115        public static PresetType forPrimitiveType(org.openstreetmap.josm.data.osm.OsmPrimitiveType type) {
     116            switch (type) {
     117                case NODE:
     118                    return NODE;
     119                case WAY:
     120                    return WAY;
     121                case CLOSEDWAY:
     122                    return CLOSEDWAY;
     123                case RELATION:
     124                    return RELATION;
     125                default:
     126                    throw new IllegalArgumentException();
     127            }
     128        }
     129    }
     130
     131    /**
     132     * Enum denoting how a match (see {@link Item#matches}) is performed.
     133     */
     134    private enum MatchType {
     135
     136        /**
     137         * Neutral, i.e., do not consider this item for matching.
     138         */
     139        NONE("none"),
     140        /**
     141         * Positive if key matches, neutral otherwise.
     142         */
     143        KEY("key"),
     144        /**
     145         * Positive if key matches, negative otherwise.
     146         */
     147        KEY_REQUIRED("key!"),
     148        /**
     149         * Positive if key and value matches, negative otherwise.
     150         */
     151        KEY_VALUE("keyvalue");
     152
     153        private final String value;
     154
     155        private MatchType(String value) {
     156            this.value = value;
     157        }
     158
     159        public String getValue() {
     160            return value;
     161        }
     162
     163        public static MatchType ofString(String type) {
     164            for (MatchType i : EnumSet.allOf(MatchType.class)) {
     165                if (i.getValue().equals(type)) {
     166                    return i;
     167                }
     168            }
     169            throw new IllegalArgumentException(type + " is not allowed");
     170        }
    110171    }
    111172
     
    140201            return false;
    141202        }
     203
     204        /**
     205         * Tests whether the tags match this item.
     206         * Note that for a match, at least one positive and no negative is required.
     207         * @param tags the tags of an {@link OsmPrimitive}
     208         * @return {@code true} if matches (positive), {@code null} if neutral, {@code false} if mismatches (negative).
     209         */
     210        abstract Boolean matches(Map<String, String> tags);
    142211    }
    143212
     
    248317        public String originalValue;
    249318        public String use_last_as_default = "false";
    250         public boolean delete_if_empty = false;
    251         public boolean required = false;
     319        public String match = MatchType.NONE.getValue();
    252320
    253321        private JComponent value;
     
    316384                        return;
    317385
    318                     if (delete_if_empty && v.length() == 0) {
    319                         v = null;
    320                     }
    321386                    changedTags.add(new Tag(key, v));
    322387        }
     
    325390        boolean requestFocusInWindow() {
    326391            return value.requestFocusInWindow();
     392        }
     393
     394        @Override
     395        Boolean matches(Map<String, String> tags) {
     396            switch (MatchType.ofString(match)) {
     397                case NONE:
     398                    return null;
     399                case KEY:
     400                    return tags.containsKey(key) ? true : null;
     401                case KEY_REQUIRED:
     402                    return tags.containsKey(key);
     403                default:
     404                    throw new IllegalArgumentException("key_value matching not supported for <text>: " + text);
     405            }
    327406        }
    328407    }
     
    337416        public String value_off = OsmUtils.falseval;
    338417        public boolean default_ = false; // only used for tagless objects
    339         public boolean required = false;
     418        public String match = MatchType.NONE.getValue();
    340419
    341420        private QuadStateCheckBox check;
     
    411490        }
    412491        @Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
     492
     493        @Override
     494        Boolean matches(Map<String, String> tags) {
     495            switch (MatchType.ofString(match)) {
     496                case NONE:
     497                    return null;
     498                case KEY:
     499                    return tags.containsKey(key) ? true : null;
     500                case KEY_REQUIRED:
     501                    return tags.containsKey(key);
     502                case KEY_VALUE:
     503                    return value_off.equals(tags.get(key)) || value_on.equals(tags.get(key));
     504                default:
     505                    throw new IllegalStateException();
     506            }
     507        }
    413508    }
    414509
     
    427522        public String default_;
    428523        public String delimiter = ";";
    429         public boolean delete_if_empty = false;
    430524        public String use_last_as_default = "false";
    431         public boolean required = false;
     525        public String match = MatchType.NONE.getValue();
    432526
    433527        protected List<String> short_description_list;
     
    440534        protected abstract void addToPanelAnchor(JPanel p, String def, String[] display_array);
    441535
     536        protected char getDelChar() {
     537            return delimiter.isEmpty() ? ';' : delimiter.charAt(0);
     538        }
     539
    442540        @Override
    443541        public boolean addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
     
    447545            String def = default_;
    448546
    449             char delChar = ';';
    450             if (!delimiter.isEmpty()) {
    451                 delChar = delimiter.charAt(0);
    452             }
     547            char delChar = getDelChar();
    453548
    454549            String[] value_array = splitEscaped(delChar, values);
     
    552647                return;
    553648
    554             if (delete_if_empty && value.length() == 0) {
    555                 value = null;
    556             }
    557649            if (!"false".equals(use_last_as_default)) {
    558650                lastValue.put(key, value);
     
    607699                }
    608700            };
     701        }
     702
     703        @Override
     704        Boolean matches(Map<String, String> tags) {
     705            switch (MatchType.ofString(match)) {
     706                case NONE:
     707                    return null;
     708                case KEY:
     709                    return tags.containsKey(key) ? true : null;
     710                case KEY_REQUIRED:
     711                    return tags.containsKey(key);
     712                case KEY_VALUE:
     713                    return tags.containsKey(key)
     714                            && Arrays.asList(splitEscaped(getDelChar(), values)).contains(tags.get(key));
     715                default:
     716                    throw new IllegalStateException();
     717            }
    609718        }
    610719    }
     
    828937        public void addCommands(List<Tag> changedTags) {
    829938        }
     939
     940        @Override
     941        Boolean matches(Map<String, String> tags) {
     942            return null;
     943        }
    830944    }
    831945
     
    862976        public void addCommands(List<Tag> changedTags) {
    863977        }
     978
     979        @Override
     980        Boolean matches(Map<String, String> tags) {
     981            return null;
     982        }
    864983    }
    865984
     
    871990        public String locale_text;
    872991
    873         public boolean required=false;
     992        public boolean required = false;
    874993        public long count = 0;
    875994
     
    9561075        public void addCommands(List<Tag> changedTags) {
    9571076        }
     1077
     1078        @Override
     1079        Boolean matches(Map<String, String> tags) {
     1080            return null;
     1081        }
    9581082    }
    9591083
     
    9721096        public void addCommands(List<Tag> changedTags) {
    9731097        }
     1098
     1099        @Override
     1100        Boolean matches(Map<String, String> tags) {
     1101            return null;
     1102        }
    9741103    }
    9751104
     
    9851114        public void addCommands(List<Tag> changedTags) {
    9861115        }
     1116
     1117        @Override
     1118        Boolean matches(Map<String, String> tags) {
     1119            return null;
     1120        }
    9871121    }
    9881122
     
    9911125        public String key;
    9921126        public String value;
     1127        public String match = MatchType.KEY_VALUE.getValue();
    9931128
    9941129        @Override
     
    10001135        public void addCommands(List<Tag> changedTags) {
    10011136            changedTags.add(new Tag(key, value));
     1137        }
     1138
     1139        @Override
     1140        Boolean matches(Map<String, String> tags) {
     1141            switch (MatchType.ofString(match)) {
     1142                case NONE:
     1143                    return null;
     1144                case KEY:
     1145                    return tags.containsKey(key) ? true : null;
     1146                case KEY_REQUIRED:
     1147                    return tags.containsKey(key);
     1148                case KEY_VALUE:
     1149                    return value.equals(tags.get(key));
     1150                default:
     1151                    throw new IllegalStateException();
     1152            }
    10021153        }
    10031154    }
     
    15011652        return (types == null?"":types) + " " + name;
    15021653    }
     1654
     1655    public boolean matches(Collection<PresetType> t, Map<String, String> tags) {
     1656        if (!isShowable()) {
     1657            return false;
     1658        } else if (t != null && types != null && !types.containsAll(t)) {
     1659            return false;
     1660        }
     1661        boolean atLeastOnePositiveMatch = false;
     1662        for (Item item : data) {
     1663            Boolean m = item.matches(tags);
     1664            if (m != null && !m) {
     1665                return false;
     1666            } else if (m != null) {
     1667                atLeastOnePositiveMatch = true;
     1668            }
     1669        }
     1670        return atLeastOnePositiveMatch;
     1671    }
    15031672}
Note: See TracChangeset for help on using the changeset viewer.