Ignore:
Timestamp:
2016-08-05T20:09:55+02:00 (4 years ago)
Author:
Don-vip
Message:

fix #12900 - Conflicts in pasted tags cannot be resolved, cannot be resolved to "none" (patch by michael2402) - gsoc-core

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java

    r10692 r10737  
    44import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    55import static org.openstreetmap.josm.tools.I18n.tr;
    6 import static org.openstreetmap.josm.tools.I18n.trn;
    76
    87import java.awt.event.ActionEvent;
    98import java.awt.event.KeyEvent;
    10 import java.util.ArrayList;
    119import java.util.Collection;
    12 import java.util.EnumMap;
    13 import java.util.List;
    14 import java.util.Map;
    15 import java.util.Map.Entry;
    1610
    17 import org.openstreetmap.josm.Main;
    18 import org.openstreetmap.josm.command.ChangePropertyCommand;
    19 import org.openstreetmap.josm.command.Command;
    20 import org.openstreetmap.josm.command.SequenceCommand;
    2111import org.openstreetmap.josm.data.osm.DataSet;
    2212import org.openstreetmap.josm.data.osm.OsmPrimitive;
    23 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    24 import org.openstreetmap.josm.data.osm.PrimitiveData;
    25 import org.openstreetmap.josm.data.osm.Tag;
    26 import org.openstreetmap.josm.data.osm.TagCollection;
    27 import org.openstreetmap.josm.gui.conflict.tags.PasteTagsConflictResolverDialog;
    2813import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
    29 import org.openstreetmap.josm.tools.I18n;
    3014import org.openstreetmap.josm.tools.Shortcut;
    31 import org.openstreetmap.josm.tools.TextTagParser;
    3215
    3316/**
     
    5538    }
    5639
    57     /**
    58      * Used to update the tags.
    59      */
    60     public static class TagPaster {
    61 
    62         private final Collection<PrimitiveData> source;
    63         private final Collection<OsmPrimitive> target;
    64         private final List<Tag> tags = new ArrayList<>();
    65 
    66         /**
    67          * Constructs a new {@code TagPaster}.
    68          * @param source source primitives
    69          * @param target target primitives
    70          */
    71         public TagPaster(Collection<PrimitiveData> source, Collection<OsmPrimitive> target) {
    72             this.source = source;
    73             this.target = target;
    74         }
    75 
    76         /**
    77          * Determines if the source for tag pasting is heterogeneous, i.e. if it doesn't consist of
    78          * {@link OsmPrimitive}s of exactly one type
    79          * @return true if the source for tag pasting is heterogeneous
    80          */
    81         protected boolean isHeterogeneousSource() {
    82             int count = 0;
    83             count = !getSourcePrimitivesByType(OsmPrimitiveType.NODE).isEmpty() ? (count + 1) : count;
    84             count = !getSourcePrimitivesByType(OsmPrimitiveType.WAY).isEmpty() ? (count + 1) : count;
    85             count = !getSourcePrimitivesByType(OsmPrimitiveType.RELATION).isEmpty() ? (count + 1) : count;
    86             return count > 1;
    87         }
    88 
    89         /**
    90          * Replies all primitives of type <code>type</code> in the current selection.
    91          *
    92          * @param type  the type
    93          * @return all primitives of type <code>type</code> in the current selection.
    94          */
    95         protected Collection<? extends PrimitiveData> getSourcePrimitivesByType(OsmPrimitiveType type) {
    96             return PrimitiveData.getFilteredList(source, type);
    97         }
    98 
    99         /**
    100          * Replies the collection of tags for all primitives of type <code>type</code> in the current
    101          * selection
    102          *
    103          * @param type  the type
    104          * @return the collection of tags for all primitives of type <code>type</code> in the current
    105          * selection
    106          */
    107         protected TagCollection getSourceTagsByType(OsmPrimitiveType type) {
    108             return TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(type));
    109         }
    110 
    111         /**
    112          * Replies true if there is at least one tag in the current selection for primitives of
    113          * type <code>type</code>
    114          *
    115          * @param type the type
    116          * @return true if there is at least one tag in the current selection for primitives of
    117          * type <code>type</code>
    118          */
    119         protected boolean hasSourceTagsByType(OsmPrimitiveType type) {
    120             return !getSourceTagsByType(type).isEmpty();
    121         }
    122 
    123         protected void buildTags(TagCollection tc) {
    124             for (String key : tc.getKeys()) {
    125                 tags.add(new Tag(key, tc.getValues(key).iterator().next()));
    126             }
    127         }
    128 
    129         protected Map<OsmPrimitiveType, Integer> getSourceStatistics() {
    130             Map<OsmPrimitiveType, Integer> ret = new EnumMap<>(OsmPrimitiveType.class);
    131             for (OsmPrimitiveType type: OsmPrimitiveType.dataValues()) {
    132                 if (!getSourceTagsByType(type).isEmpty()) {
    133                     ret.put(type, getSourcePrimitivesByType(type).size());
    134                 }
    135             }
    136             return ret;
    137         }
    138 
    139         protected Map<OsmPrimitiveType, Integer> getTargetStatistics() {
    140             Map<OsmPrimitiveType, Integer> ret = new EnumMap<>(OsmPrimitiveType.class);
    141             for (OsmPrimitiveType type: OsmPrimitiveType.dataValues()) {
    142                 int count = OsmPrimitive.getFilteredList(target, type.getOsmClass()).size();
    143                 if (count > 0) {
    144                     ret.put(type, count);
    145                 }
    146             }
    147             return ret;
    148         }
    149 
    150         /**
    151          * Pastes the tags from a homogeneous source (the selection consisting
    152          * of one type of {@link OsmPrimitive}s only).
    153          *
    154          * Tags from a homogeneous source can be pasted to a heterogeneous target. All target primitives,
    155          * regardless of their type, receive the same tags.
    156          */
    157         protected void pasteFromHomogeneousSource() {
    158             TagCollection tc = null;
    159             for (OsmPrimitiveType type : OsmPrimitiveType.dataValues()) {
    160                 TagCollection tc1 = getSourceTagsByType(type);
    161                 if (!tc1.isEmpty()) {
    162                     tc = tc1;
    163                 }
    164             }
    165             if (tc == null)
    166                 // no tags found to paste. Abort.
    167                 return;
    168 
    169             if (!tc.isApplicableToPrimitive()) {
    170                 PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
    171                 dialog.populate(tc, getSourceStatistics(), getTargetStatistics());
    172                 dialog.setVisible(true);
    173                 if (dialog.isCanceled())
    174                     return;
    175                 buildTags(dialog.getResolution());
    176             } else {
    177                 // no conflicts in the source tags to resolve. Just apply the tags to the target primitives
    178                 buildTags(tc);
    179             }
    180         }
    181 
    182         /**
    183          * Replies true if there is at least one primitive of type <code>type</code>
    184          * is in the target collection
    185          *
    186          * @param type  the type to look for
    187          * @return true if there is at least one primitive of type <code>type</code> in the collection
    188          * <code>selection</code>
    189          */
    190         protected boolean hasTargetPrimitives(Class<? extends OsmPrimitive> type) {
    191             return !OsmPrimitive.getFilteredList(target, type).isEmpty();
    192         }
    193 
    194         /**
    195          * Replies true if this a heterogeneous source can be pasted without conflict to targets
    196          *
    197          * @return true if this a heterogeneous source can be pasted without conflicts to targets
    198          */
    199         protected boolean canPasteFromHeterogeneousSourceWithoutConflict() {
    200             for (OsmPrimitiveType type : OsmPrimitiveType.dataValues()) {
    201                 if (hasTargetPrimitives(type.getOsmClass())) {
    202                     TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(type));
    203                     if (!tc.isEmpty() && !tc.isApplicableToPrimitive())
    204                         return false;
    205                 }
    206             }
    207             return true;
    208         }
    209 
    210         /**
    211          * Pastes the tags in the current selection of the paste buffer to a set of target primitives.
    212          */
    213         protected void pasteFromHeterogeneousSource() {
    214             if (canPasteFromHeterogeneousSourceWithoutConflict()) {
    215                 for (OsmPrimitiveType type : OsmPrimitiveType.dataValues()) {
    216                     if (hasSourceTagsByType(type) && hasTargetPrimitives(type.getOsmClass())) {
    217                         buildTags(getSourceTagsByType(type));
    218                     }
    219                 }
    220             } else {
    221                 PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
    222                 dialog.populate(
    223                         getSourceTagsByType(OsmPrimitiveType.NODE),
    224                         getSourceTagsByType(OsmPrimitiveType.WAY),
    225                         getSourceTagsByType(OsmPrimitiveType.RELATION),
    226                         getSourceStatistics(),
    227                         getTargetStatistics()
    228                 );
    229                 dialog.setVisible(true);
    230                 if (dialog.isCanceled())
    231                     return;
    232                 for (OsmPrimitiveType type : OsmPrimitiveType.dataValues()) {
    233                     if (hasSourceTagsByType(type) && hasTargetPrimitives(type.getOsmClass())) {
    234                         buildTags(dialog.getResolution(type));
    235                     }
    236                 }
    237             }
    238         }
    239 
    240         /**
    241          * Performs the paste operation.
    242          * @return list of tags
    243          */
    244         public List<Tag> execute() {
    245             tags.clear();
    246             if (isHeterogeneousSource()) {
    247                 pasteFromHeterogeneousSource();
    248             } else {
    249                 pasteFromHomogeneousSource();
    250             }
    251             return tags;
    252         }
    253 
    254     }
    255 
    25640    @Override
    25741    public void actionPerformed(ActionEvent e) {
     
    26246
    26347        transferHandler.pasteTags(selection);
    264     }
    265 
    266     /**
    267      * Paste tags from arbitrary text, not using JOSM buffer
    268      * @param selection selected primitives
    269      * @param text text containing tags
    270      * @return true if action was successful
    271      * @see TextTagParser#readTagsFromText
    272      */
    273     public static boolean pasteTagsFromText(Collection<OsmPrimitive> selection, String text) {
    274         Map<String, String> tags = TextTagParser.readTagsFromText(text);
    275         if (tags == null || tags.isEmpty()) {
    276             TextTagParser.showBadBufferMessage(help);
    277             return false;
    278         }
    279         if (!TextTagParser.validateTags(tags)) return false;
    280 
    281         List<Command> commands = new ArrayList<>(tags.size());
    282         for (Entry<String, String> entry: tags.entrySet()) {
    283             String v = entry.getValue();
    284             commands.add(new ChangePropertyCommand(selection, entry.getKey(), "".equals(v) ? null : v));
    285         }
    286         commitCommands(selection, commands);
    287         return !commands.isEmpty();
    288     }
    289 
    290     /**
    291      * Create and execute SequenceCommand with descriptive title
    292      * @param selection selected primitives
    293      * @param commands the commands to perform in a sequential command
    294      */
    295     private static void commitCommands(Collection<OsmPrimitive> selection, List<Command> commands) {
    296         if (!commands.isEmpty()) {
    297             String title1 = trn("Pasting {0} tag", "Pasting {0} tags", commands.size(), commands.size());
    298             String title2 = trn("to {0} object", "to {0} objects", selection.size(), selection.size());
    299             @I18n.QuirkyPluralString
    300             final String title = title1 + ' ' + title2;
    301             Main.main.undoRedo.add(
    302                     new SequenceCommand(
    303                             title,
    304                             commands
    305                     ));
    306         }
    30748    }
    30849
Note: See TracChangeset for help on using the changeset viewer.