Changeset 10737 in josm
- Timestamp:
- 2016-08-05T20:09:55+02:00 (9 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 1 deleted
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java
r10692 r10737 4 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 import static org.openstreetmap.josm.tools.I18n.trn;7 6 8 7 import java.awt.event.ActionEvent; 9 8 import java.awt.event.KeyEvent; 10 import java.util.ArrayList;11 9 import java.util.Collection; 12 import java.util.EnumMap;13 import java.util.List;14 import java.util.Map;15 import java.util.Map.Entry;16 10 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;21 11 import org.openstreetmap.josm.data.osm.DataSet; 22 12 import 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;28 13 import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler; 29 import org.openstreetmap.josm.tools.I18n;30 14 import org.openstreetmap.josm.tools.Shortcut; 31 import org.openstreetmap.josm.tools.TextTagParser;32 15 33 16 /** … … 55 38 } 56 39 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 primitives69 * @param target target primitives70 */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 of78 * {@link OsmPrimitive}s of exactly one type79 * @return true if the source for tag pasting is heterogeneous80 */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 type93 * @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 current101 * selection102 *103 * @param type the type104 * @return the collection of tags for all primitives of type <code>type</code> in the current105 * selection106 */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 of113 * type <code>type</code>114 *115 * @param type the type116 * @return true if there is at least one tag in the current selection for primitives of117 * 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 consisting152 * 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 primitives178 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 collection185 *186 * @param type the type to look for187 * @return true if there is at least one primitive of type <code>type</code> in the collection188 * <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 targets196 *197 * @return true if this a heterogeneous source can be pasted without conflicts to targets198 */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 tags243 */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 256 40 @Override 257 41 public void actionPerformed(ActionEvent e) { … … 262 46 263 47 transferHandler.pasteTags(selection); 264 }265 266 /**267 * Paste tags from arbitrary text, not using JOSM buffer268 * @param selection selected primitives269 * @param text text containing tags270 * @return true if action was successful271 * @see TextTagParser#readTagsFromText272 */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 title292 * @param selection selected primitives293 * @param commands the commands to perform in a sequential command294 */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.QuirkyPluralString300 final String title = title1 + ' ' + title2;301 Main.main.undoRedo.add(302 new SequenceCommand(303 title,304 commands305 ));306 }307 48 } 308 49 -
trunk/src/org/openstreetmap/josm/data/osm/Tag.java
r10716 r10737 2 2 package org.openstreetmap.josm.data.osm; 3 3 4 import java.io.Serializable; 4 5 import java.util.Collection; 5 6 import java.util.Collections; … … 17 18 * the modifying methods throw an {@link UnsupportedOperationException}. 18 19 */ 19 public class Tag implements Tagged, Entry<String, String> { 20 public class Tag implements Tagged, Entry<String, String>, Serializable { 21 22 private static final long serialVersionUID = 1; 20 23 21 24 private final String key; -
trunk/src/org/openstreetmap/josm/gui/conflict/tags/PasteTagsConflictResolverDialog.java
r10593 r10737 290 290 } 291 291 292 protectedvoid updateEnabledState() {292 void updateEnabledState() { 293 293 if (mode == null) { 294 294 setEnabled(false); … … 296 296 setEnabled(allPrimitivesResolver.getModel().isResolvedCompletely()); 297 297 } else { 298 boolean enabled = true; 299 for (TagConflictResolver val: resolvers.values()) { 300 enabled &= val.getModel().isResolvedCompletely(); 301 } 302 setEnabled(enabled); 298 setEnabled(resolvers.values().stream().allMatch(val -> val.getModel().isResolvedCompletely())); 303 299 } 304 300 } … … 346 342 if (model == resolver.getModel()) { 347 343 tpResolvers.setIconAt(i, 348 (Boolean) evt.getNewValue() ? iconResolved : iconUnresolved 349 344 (Integer) evt.getNewValue() == 0 ? iconResolved : iconUnresolved 350 345 ); 351 346 } -
trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverModel.java
r10619 r10737 22 22 private transient TagCollection tags; 23 23 private List<String> displayedKeys; 24 private Set<String> keysWithConflicts; 24 private Set<String> keysWithConflicts = new HashSet<>(); 25 25 private transient Map<String, MultiValueResolutionDecision> decisions; 26 26 private int numConflicts; … … 54 54 55 55 protected void refreshNumConflicts() { 56 int count = 0; 57 for (MultiValueResolutionDecision d : decisions.values()) { 58 if (!d.isDecided()) { 59 count++; 60 } 61 } 62 setNumConflicts(count); 56 setNumConflicts((int) decisions.values().stream().filter(d -> !d.isDecided()).count()); 63 57 } 64 58 … … 122 116 this.tags = tags; 123 117 displayedKeys = new ArrayList<>(); 124 this.keysWithConflicts = keysWithConflicts == null ? new HashSet<>() : keysWithConflicts; 118 if (keysWithConflicts != null) { 119 this.keysWithConflicts.addAll(keysWithConflicts); 120 } 125 121 decisions = new HashMap<>(); 126 122 rebuild(); … … 183 179 */ 184 180 public boolean isResolvedCompletely() { 185 return numConflicts == 0 && keysWithConflicts != null && keysWithConflicts.isEmpty(); 186 } 187 181 return numConflicts == 0; 182 } 183 184 /** 185 * Gets the number of reamining conflicts. 186 * @return The number 187 */ 188 188 public int getNumConflicts() { 189 189 return numConflicts; 190 190 } 191 191 192 /** 193 * Gets the number of decisions the user can take 194 * @return The number of decisions 195 */ 192 196 public int getNumDecisions() { 193 197 return decisions == null ? 0 : decisions.size(); -
trunk/src/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandler.java
r10639 r10737 17 17 import org.openstreetmap.josm.gui.datatransfer.importers.FilePaster; 18 18 import org.openstreetmap.josm.gui.datatransfer.importers.PrimitiveDataPaster; 19 import org.openstreetmap.josm.gui.datatransfer.importers.PrimitiveTagTransferPaster; 19 20 import org.openstreetmap.josm.gui.datatransfer.importers.TagTransferPaster; 20 21 import org.openstreetmap.josm.gui.datatransfer.importers.TextTagPaster; … … 30 31 private static final Collection<AbstractOsmDataPaster> SUPPORTED = Arrays.asList( 31 32 new FilePaster(), new PrimitiveDataPaster(), 33 new PrimitiveTagTransferPaster(), 32 34 new TagTransferPaster(), new TextTagPaster()); 33 35 -
trunk/src/org/openstreetmap/josm/gui/datatransfer/PrimitiveTransferable.java
r10605 r10737 12 12 import org.openstreetmap.josm.data.osm.PrimitiveData; 13 13 import org.openstreetmap.josm.gui.datatransfer.data.OsmLayerTransferData; 14 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTagTransferData; 14 15 import org.openstreetmap.josm.gui.datatransfer.data.PrimitiveTransferData; 15 16 import org.openstreetmap.josm.gui.datatransfer.data.TagTransferData; … … 75 76 } else if (PrimitiveTransferData.DATA_FLAVOR.equals(flavor)) { 76 77 return primitives; 78 } else if (PrimitiveTagTransferData.FLAVOR.equals(flavor)) { 79 return new PrimitiveTagTransferData(primitives); 77 80 } else if (TagTransferData.FLAVOR.equals(flavor)) { 78 81 return new TagTransferData(primitives.getDirectlyAdded()); -
trunk/src/org/openstreetmap/josm/gui/datatransfer/data/TagTransferData.java
r10637 r10737 14 14 * This is a special transfer type that only transfers tag data. 15 15 * <p> 16 * It c urrently contains all tags contained in the selection that was copied.16 * It contains all tags contained in the selection that was copied. For conflicting tags, any of the values may be used. 17 17 * @author Michael Zangl 18 18 * @since 10604 -
trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/AbstractTagPaster.java
r10604 r10737 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import static org.openstreetmap.josm.tools.I18n.trn; 3 5 4 6 import java.awt.datatransfer.DataFlavor; … … 6 8 import java.io.IOException; 7 9 import java.util.Collection; 10 import java.util.Collections; 11 import java.util.List; 8 12 import java.util.Map; 9 13 … … 12 16 import org.openstreetmap.josm.Main; 13 17 import org.openstreetmap.josm.command.ChangePropertyCommand; 18 import org.openstreetmap.josm.command.Command; 19 import org.openstreetmap.josm.command.SequenceCommand; 14 20 import org.openstreetmap.josm.data.coor.EastNorth; 15 21 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 22 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 23 import org.openstreetmap.josm.tools.I18n; 17 24 18 25 /** … … 42 49 throws UnsupportedFlavorException, IOException { 43 50 ChangePropertyCommand command = new ChangePropertyCommand(selection, getTags(support)); 44 Main.main.undoRedo.add(command);51 commitCommands(selection, Collections.singletonList(command)); 45 52 return true; 53 } 54 55 /** 56 * Create and execute SequenceCommand with descriptive title 57 * @param selection selected primitives 58 * @param commands the commands to perform in a sequential command 59 * @since 10737 60 */ 61 protected static void commitCommands(Collection<? extends OsmPrimitive> selection, List<Command> commands) { 62 if (!commands.isEmpty()) { 63 String title1 = trn("Pasting {0} tag", "Pasting {0} tags", commands.size(), commands.size()); 64 String title2 = trn("to {0} object", "to {0} objects", selection.size(), selection.size()); 65 @I18n.QuirkyPluralString 66 final String title = title1 + ' ' + title2; 67 Main.main.undoRedo.add(new SequenceCommand(title, commands)); 68 } 46 69 } 47 70 -
trunk/src/org/openstreetmap/josm/gui/datatransfer/importers/TextTagPaster.java
r10604 r10737 1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.datatransfer.importers; 3 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 3 5 4 6 import java.awt.datatransfer.DataFlavor; … … 18 20 */ 19 21 public final class TextTagPaster extends AbstractTagPaster { 22 private static final String help = ht("/Action/PasteTags"); 20 23 21 24 /** … … 29 32 public boolean supports(TransferSupport support) { 30 33 try { 31 return super.supports(support) && getTags(support)!= null;34 return super.supports(support) && containsValidTags(support); 32 35 } catch (UnsupportedFlavorException | IOException e) { 33 36 Main.warn(e); … … 36 39 } 37 40 41 private boolean containsValidTags(TransferSupport support) throws UnsupportedFlavorException, IOException { 42 Map<String, String> tags = getTagsImpl(support); 43 return tags != null && !tags.isEmpty(); 44 } 45 38 46 @Override 39 47 protected Map<String, String> getTags(TransferSupport support) throws UnsupportedFlavorException, IOException { 48 Map<String, String> tags = getTagsImpl(support); 49 if (tags == null || tags.isEmpty()) { 50 TextTagParser.showBadBufferMessage(help); 51 throw new IOException("Invalid tags to paste."); 52 } 53 if (!TextTagParser.validateTags(tags)) { 54 throw new IOException("Tags to paste are not valid."); 55 } 56 return tags; 57 } 58 59 private Map<String, String> getTagsImpl(TransferSupport support) throws UnsupportedFlavorException, IOException { 40 60 return TextTagParser.readTagsFromText((String) support.getTransferable().getTransferData(df)); 41 61 }
Note:
See TracChangeset
for help on using the changeset viewer.