- Timestamp:
- 2009-09-12T06:21:30+02:00 (15 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 1 added
- 4 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
r2079 r2095 33 33 import org.openstreetmap.josm.data.osm.Way; 34 34 import org.openstreetmap.josm.gui.ExtendedDialog; 35 import org.openstreetmap.josm.gui.conflict.tags.Combine WaysConflictResolverDialog;35 import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog; 36 36 import org.openstreetmap.josm.tools.Pair; 37 37 import org.openstreetmap.josm.tools.Shortcut; … … 166 166 completeTagCollectionWithMissingTags(completeWayTags, ways); 167 167 168 Combine WaysConflictResolverDialog dialog = CombineWaysConflictResolverDialog.getInstance();168 CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance(); 169 169 dialog.getTagConflictResolverModel().populate(completeWayTags); 170 dialog.setTarget Way(targetWay);170 dialog.setTargetPrimitive(targetWay); 171 171 dialog.getRelationMemberConflictResolverModel().populate( 172 172 referringRelations.getRelations(), … … 191 191 cmds.add(new DeleteCommand(deletedWays)); 192 192 cmds.add(new ChangeCommand(targetWay, modifiedTargetWay)); 193 cmds.addAll(dialog.buildResolutionCommands( targetWay));193 cmds.addAll(dialog.buildResolutionCommands()); 194 194 final SequenceCommand sequenceCommand = new SequenceCommand(tr("Combine {0} ways", ways.size()), cmds); 195 195 -
trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java
r2070 r2095 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.GridBagLayout;7 6 import java.awt.event.ActionEvent; 8 7 import java.awt.event.KeyEvent; 9 8 import java.util.ArrayList; 10 9 import java.util.Collection; 11 import java.util.HashMap;12 10 import java.util.HashSet; 13 11 import java.util.LinkedList; 14 import java.util.List;15 import java.util.Map;16 12 import java.util.Set; 17 import java.util.TreeMap; 18 import java.util.TreeSet; 19 import java.util.Map.Entry; 20 21 import javax.swing.Box; 22 import javax.swing.JComboBox; 23 import javax.swing.JLabel; 13 24 14 import javax.swing.JOptionPane; 25 import javax.swing.JPanel;26 15 27 16 import org.openstreetmap.josm.Main; … … 30 19 import org.openstreetmap.josm.command.DeleteCommand; 31 20 import org.openstreetmap.josm.command.SequenceCommand; 21 import org.openstreetmap.josm.data.osm.BackreferencedDataSet; 32 22 import org.openstreetmap.josm.data.osm.Node; 33 23 import org.openstreetmap.josm.data.osm.OsmPrimitive; 34 import org.openstreetmap.josm.data.osm.Relation; 35 import org.openstreetmap.josm.data.osm.RelationMember; 36 import org.openstreetmap.josm.data.osm.TigerUtils; 24 import org.openstreetmap.josm.data.osm.Tag; 25 import org.openstreetmap.josm.data.osm.TagCollection; 37 26 import org.openstreetmap.josm.data.osm.Way; 38 import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor; 39 import org.openstreetmap.josm.gui.ExtendedDialog; 40 import org.openstreetmap.josm.tools.GBC; 41 import org.openstreetmap.josm.tools.Pair; 27 import org.openstreetmap.josm.data.osm.BackreferencedDataSet.RelationToChildReference; 28 import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog; 29 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 42 30 import org.openstreetmap.josm.tools.Shortcut; 43 31 44 32 45 33 /** 46 * Merge two or more nodes into one node. 47 * (based on Combine ways) 48 * 49 * @author Matthew Newton 50 * 34 * Merges a collection of nodes into one node. 35 * 51 36 */ 52 37 public class MergeNodesAction extends JosmAction { … … 60 45 if (!isEnabled()) 61 46 return; 62 63 47 Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected(); 64 LinkedList<Node> selectedNodes = new LinkedList<Node>(); 65 66 // the selection check should stop this procedure starting if 67 // nothing but node are selected - otherwise we don't care 68 // anyway as long as we have at least two nodes 69 for (OsmPrimitive osm : selection) 70 if (osm instanceof Node) { 71 selectedNodes.add((Node)osm); 72 } 73 48 Set<Node> selectedNodes = OsmPrimitive.getFilteredSet(selection, Node.class); 74 49 if (selectedNodes.size() < 2) { 75 50 JOptionPane.showMessageDialog( … … 82 57 } 83 58 59 60 Node targetNode = selectTargetNode(selectedNodes); 61 Command cmd = mergeNodes(Main.main.getEditLayer(), selectedNodes, targetNode); 62 if (cmd != null) { 63 Main.main.undoRedo.add(cmd); 64 Main.main.getEditLayer().data.setSelected(targetNode); 65 } 66 } 67 68 protected void completeTagCollectionWithMissingTags(TagCollection tc, Collection<Node> mergedNodes) { 69 for (String key: tc.getKeys()) { 70 // make sure the empty value is in the tag set if a tag is not present 71 // on all merged nodes 72 // 73 for (Node n: mergedNodes) { 74 if (n.get(key) == null) { 75 tc.add(new Tag(key)); // add a tag with key and empty value 76 } 77 } 78 } 79 // remove irrelevant tags 80 // 81 tc.removeByKey("created_by"); 82 } 83 84 protected void completeTagCollectionForEditing(TagCollection tc) { 85 for (String key: tc.getKeys()) { 86 // make sure the empty value is in the tag set such that we can delete the tag 87 // in the conflict dialog if necessary 88 // 89 tc.add(new Tag(key,"")); 90 } 91 } 92 93 /** 94 * Selects a node out of a collection of candidate nodes. The selected 95 * node will become the target node the remaining nodes are merged to. 96 * 97 * @param candidates the collection of candidate nodes 98 * @return the selected target node 99 */ 100 public Node selectTargetNode(Collection<Node> candidates) { 84 101 // Find which node to merge into (i.e. which one will be left) 85 102 // - this should be combined from two things: … … 93 110 // that the user doesn't know which node will be chosen (so 94 111 // (2) is not implemented yet.) :-( 95 Node useNode = null;96 for (Node n: selectedNodes) {112 Node targetNode = null; 113 for (Node n: candidates) { 97 114 if (n.getId() > 0) { 98 useNode = n;115 targetNode = n; 99 116 break; 100 117 } 101 118 } 102 if (useNode == null) { 103 useNode = selectedNodes.iterator().next(); 104 } 105 106 mergeNodes(selectedNodes, useNode); 107 } 108 109 /** 110 * really do the merging - returns the node that is left 111 */ 112 public Node mergeNodes(LinkedList<Node> allNodes, Node dest) { 113 Node newNode = new Node(dest); 114 115 // Check whether all ways have identical relationship membership. More 116 // specifically: If one of the selected ways is a member of relation X 117 // in role Y, then all selected ways must be members of X in role Y. 118 119 // FIXME: In a later revision, we should display some sort of conflict 120 // dialog like we do for tags, to let the user choose which relations 121 // should be kept. 122 123 // Step 1, iterate over all relations and figure out which of our 124 // selected ways are members of a relation. 125 HashMap<Pair<Relation,String>, HashSet<Node>> backlinks = 126 new HashMap<Pair<Relation,String>, HashSet<Node>>(); 127 HashSet<Relation> relationsUsingNodes = new HashSet<Relation>(); 128 for (Relation r : getCurrentDataSet().relations) { 129 if (r.isDeleted() || r.incomplete) { 130 continue; 131 } 132 for (RelationMember rm : r.getMembers()) { 133 if (rm.isNode()) { 134 for (Node n : allNodes) { 135 if (rm.getMember() == n) { 136 Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.getRole()); 137 HashSet<Node> nodelinks = new HashSet<Node>(); 138 if (backlinks.containsKey(pair)) { 139 nodelinks = backlinks.get(pair); 140 } else { 141 nodelinks = new HashSet<Node>(); 142 backlinks.put(pair, nodelinks); 143 } 144 nodelinks.add(n); 145 146 // this is just a cache for later use 147 relationsUsingNodes.add(r); 148 } 149 } 119 if (targetNode == null) { 120 // an arbitrary node 121 targetNode = candidates.iterator().next(); 122 } 123 return targetNode; 124 } 125 126 127 /** 128 * Merges the nodes in <code>node</code> onto one of the nodes. Uses the dataset 129 * managed by <code>layer</code> as reference. 130 * 131 * @param layer the reference data layer. Must not be null. 132 * @param nodes the collection of nodes. Ignored if null. 133 * @param targetNode the target node the collection of nodes is merged to. Must not be null. 134 * @throws IllegalArgumentException thrown if layer is null 135 * @throws IllegalArgumentException thrown if targetNode is null 136 * 137 */ 138 public Command mergeNodes(OsmDataLayer layer, Collection<Node> nodes, Node targetNode) throws IllegalArgumentException{ 139 if (layer == null) 140 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "nodes")); 141 if (targetNode == null) 142 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "targetNode")); 143 144 if (nodes == null) 145 return null; 146 nodes.remove(null); // just in case 147 BackreferencedDataSet backreferences = new BackreferencedDataSet(layer.data); 148 backreferences.build(); 149 return mergeNodes(layer,backreferences, nodes, targetNode); 150 } 151 152 /** 153 * Merges the nodes in <code>node</code> onto one of the nodes. Uses the dataset 154 * managed by <code>layer</code> as reference. <code>backreferences</code> is precomputed 155 * collection of all parent/child references in the dataset. 156 * 157 * @param layer layer the reference data layer. Must not be null. 158 * @param backreferences if null, backreferneces are first computed from layer.data; otherwise 159 * backreferences.getSource() == layer.data must hold 160 * @param nodes the collection of nodes. Ignored if null. 161 * @param targetNode the target node the collection of nodes is merged to. Must not be null. 162 * @throw IllegalArgumentException thrown if layer is null 163 * @throw IllegalArgumentException thrown if backreferences.getSource() != layer.data 164 */ 165 public Command mergeNodes(OsmDataLayer layer, BackreferencedDataSet backreferences, Collection<Node> nodes, Node targetNode) { 166 if (layer == null) 167 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "nodes")); 168 if (targetNode == null) 169 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "targetNode")); 170 if (nodes == null) 171 return null; 172 if (backreferences == null) { 173 backreferences = new BackreferencedDataSet(layer.data); 174 backreferences.build(); 175 } 176 177 Set<RelationToChildReference> relationToNodeReferences = backreferences.getRelationToChildReferences(nodes); 178 179 // build the tag collection 180 // 181 TagCollection nodeTags = TagCollection.unionOfAllPrimitives(nodes); 182 completeTagCollectionWithMissingTags(nodeTags, nodes); 183 TagCollection nodeTagsToEdit = new TagCollection(nodeTags); 184 completeTagCollectionForEditing(nodeTagsToEdit); 185 186 // launch a conflict resolution dialog, if necessary 187 // 188 CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance(); 189 dialog.getTagConflictResolverModel().populate(nodeTagsToEdit); 190 dialog.getRelationMemberConflictResolverModel().populate(relationToNodeReferences); 191 dialog.setTargetPrimitive(targetNode); 192 dialog.prepareDefaultDecisions(); 193 if (! nodeTags.isApplicableToPrimitive() || relationToNodeReferences.size() > 1) { 194 dialog.setVisible(true); 195 if (dialog.isCancelled()) 196 return null; 197 } 198 LinkedList<Command> cmds = new LinkedList<Command>(); 199 200 // the nodes we will have to delete 201 // 202 Collection<OsmPrimitive> nodesToDelete = new HashSet<OsmPrimitive>(nodes); 203 nodesToDelete.remove(targetNode); 204 205 // change the ways referring to at least one of the merge nodes 206 // 207 Collection<Way> waysToDelete= new HashSet<Way>(); 208 for (Way w : OsmPrimitive.getFilteredList(backreferences.getParents(nodesToDelete), Way.class)) { 209 // OK - this way contains one or more nodes to change 210 ArrayList<Node> newNodes = new ArrayList<Node>(w.getNodesCount()); 211 for (Node n: w.getNodes()) { 212 if (! nodesToDelete.contains(n)) { 213 newNodes.add(n); 150 214 } 151 215 } 152 } 153 154 // Complain to the user if the ways don't have equal memberships. 155 for (HashSet<Node> nodelinks : backlinks.values()) { 156 if (!nodelinks.containsAll(allNodes)) { 157 ExtendedDialog ed = new ExtendedDialog(Main.parent, 158 tr("Merge nodes with different memberships?"), 159 new String[] {tr("Merge Anyway"), tr("Cancel")}); 160 ed.setButtonIcons(new String[] {"mergenodes.png", "cancel.png"}); 161 ed.setContent(tr("The selected nodes have differing relation memberships. " 162 + "Do you still want to merge them?")); 163 ed.showDialog(); 164 165 if (ed.getValue() == 1) { 166 break; 167 } 168 return null; 169 } 170 } 171 172 // collect properties for later conflict resolving 173 Map<String, Set<String>> props = new TreeMap<String, Set<String>>(); 174 for (Node n : allNodes) { 175 for (Entry<String,String> e : n.entrySet()) { 176 if (!props.containsKey(e.getKey())) { 177 props.put(e.getKey(), new TreeSet<String>()); 178 } 179 props.get(e.getKey()).add(e.getValue()); 180 } 181 } 182 183 // display conflict dialog 184 Map<String, JComboBox> components = new HashMap<String, JComboBox>(); 185 JPanel p = new JPanel(new GridBagLayout()); 186 for (Entry<String, Set<String>> e : props.entrySet()) { 187 if (TigerUtils.isTigerTag(e.getKey())) { 188 String combined = TigerUtils.combineTags(e.getKey(), e.getValue()); 189 newNode.put(e.getKey(), combined); 190 } else if (e.getValue().size() > 1) { 191 JComboBox c = new JComboBox(e.getValue().toArray()); 192 c.setEditable(true); 193 p.add(new JLabel(e.getKey()), GBC.std()); 194 p.add(Box.createHorizontalStrut(10), GBC.std()); 195 p.add(c, GBC.eol()); 196 components.put(e.getKey(), c); 197 } else { 198 newNode.put(e.getKey(), e.getValue().iterator().next()); 199 } 200 } 201 202 if (!components.isEmpty()) { 203 ExtendedDialog dialog = new ExtendedDialog( 204 Main.parent, 205 tr("Enter values for all conflicts."), 206 new String[] {tr("Solve Conflicts"), tr("Cancel")} 207 ); 208 dialog.setButtonIcons(new String[] {"dialogs/conflict.png", "cancel.png"}); 209 dialog.setContent(p); 210 dialog.showDialog(); 211 int answer = dialog.getValue(); 212 213 if (answer != 1) 214 return null; 215 for (Entry<String, JComboBox> e : components.entrySet()) { 216 newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString()); 217 } 218 } 219 220 LinkedList<Command> cmds = new LinkedList<Command>(); 221 222 if (!newNode.getKeys().equals(dest.getKeys())) { 223 cmds.add(new ChangeCommand(dest, newNode)); 224 } 225 226 Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>(); 227 228 for (Way w : getCurrentDataSet().ways) { 229 if (w.isDeleted() || w.incomplete || w.getNodesCount() < 1) { 230 continue; 231 } 232 boolean modify = false; 233 for (Node sn : allNodes) { 234 if (sn == dest) { 235 continue; 236 } 237 if (w.containsNode(sn)) { 238 modify = true; 239 } 240 } 241 if (!modify) { 242 continue; 243 } 244 // OK - this way contains one or more nodes to change 245 ArrayList<Node> nn = new ArrayList<Node>(); 246 Node lastNode = null; 247 for (Node pushNode: w.getNodes()) { 248 if (allNodes.contains(pushNode)) { 249 pushNode = dest; 250 } 251 if (pushNode != lastNode) { 252 nn.add(pushNode); 253 } 254 lastNode = pushNode; 255 } 256 if (nn.size() < 2) { 257 CollectBackReferencesVisitor backRefs = 258 new CollectBackReferencesVisitor(getCurrentDataSet(), false); 259 w.visit(backRefs); 260 if (!backRefs.data.isEmpty()) { 216 if (newNodes.size() < 2) { 217 if (backreferences.getParents(w).isEmpty()) { 218 waysToDelete.add(w); 219 } else { 261 220 JOptionPane.showMessageDialog( 262 221 Main.parent, … … 268 227 return null; 269 228 } 270 del.add(w); 229 } else if(newNodes.size() < 2 && backreferences.getParents(w).isEmpty()) { 230 waysToDelete.add(w); 271 231 } else { 272 232 Way newWay = new Way(w); 273 newWay.setNodes(n n);233 newWay.setNodes(newNodes); 274 234 cmds.add(new ChangeCommand(w, newWay)); 275 235 } 276 236 } 277 237 278 // delete any merged nodes 279 del.addAll(allNodes); 280 del.remove(dest); 281 if (!del.isEmpty()) { 282 cmds.add(new DeleteCommand(del)); 283 } 284 285 // modify all relations containing the now-deleted nodes 286 for (Relation r : relationsUsingNodes) { 287 List<RelationMember> newMembers = new ArrayList<RelationMember>(); 288 HashSet<String> rolesToReAdd = new HashSet<String>(); 289 for (RelationMember rm : r.getMembers()) { 290 // Don't copy the member if it points to one of our nodes, 291 // just keep a note to re-add it later on. 292 if (allNodes.contains(rm.getMember())) { 293 rolesToReAdd.add(rm.getRole()); 294 } else { 295 newMembers.add(rm); 296 } 297 } 298 for (String role : rolesToReAdd) { 299 newMembers.add(new RelationMember(role, dest)); 300 } 301 Relation newRel = new Relation(r); 302 newRel.setMembers(newMembers); 303 cmds.add(new ChangeCommand(r, newRel)); 304 } 305 306 Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds)); 307 getCurrentDataSet().setSelected(dest); 308 309 return dest; 238 // build the commands 239 // 240 if (!nodesToDelete.isEmpty()) { 241 cmds.add(new DeleteCommand(nodesToDelete)); 242 } 243 if (!waysToDelete.isEmpty()) { 244 cmds.add(new DeleteCommand(waysToDelete)); 245 } 246 cmds.addAll(dialog.buildResolutionCommands()); 247 Command cmd = new SequenceCommand(tr("Merge {0} nodes", nodes.size()), cmds); 248 return cmd; 310 249 } 311 250 -
trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
r2031 r2095 17 17 import java.util.LinkedList; 18 18 import java.util.List; 19 import java.util.Set; 19 20 import java.util.TreeSet; 20 21 import java.util.logging.Logger; … … 43 44 import org.openstreetmap.josm.gui.SelectionManager; 44 45 import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded; 46 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.MergeAction; 45 47 import org.openstreetmap.josm.gui.layer.Layer; 46 48 import org.openstreetmap.josm.gui.layer.OsmDataLayer; … … 489 491 if (nn != null) { 490 492 Node n = nn.iterator().next(); 491 LinkedList<Node> selNodes = new LinkedList<Node>(); 492 for (OsmPrimitive osm : selection) 493 if (osm instanceof Node) { 494 selNodes.add((Node)osm); 495 } 496 if (selNodes.size() > 0) { 497 selNodes.add(n); 498 new MergeNodesAction().mergeNodes(selNodes, n); 493 Set<Node> selectedNodes = OsmPrimitive.getFilteredSet(selection, Node.class); 494 if (!selectedNodes.isEmpty()) { 495 selectedNodes.add(n); 496 MergeNodesAction mergeAction = new MergeNodesAction(); 497 Node targetNode = mergeAction.selectTargetNode(selectedNodes); 498 mergeAction.mergeNodes(Main.main.getEditLayer(),selectedNodes, targetNode); 499 499 } 500 500 } -
trunk/src/org/openstreetmap/josm/gui/conflict/tags/CombinePrimitiveResolverDialog.java
r2084 r2095 26 26 import org.openstreetmap.josm.command.ChangePropertyCommand; 27 27 import org.openstreetmap.josm.command.Command; 28 import org.openstreetmap.josm.data.osm.Node; 28 29 import org.openstreetmap.josm.data.osm.OsmPrimitive; 29 30 import org.openstreetmap.josm.data.osm.TagCollection; … … 34 35 import org.openstreetmap.josm.tools.WindowGeometry; 35 36 36 public class CombineWaysConflictResolverDialog extends JDialog { 37 38 static private CombineWaysConflictResolverDialog instance; 39 40 public static CombineWaysConflictResolverDialog getInstance() { 37 /** 38 * This dialog helps to resolve conflicts occuring when combining or merging primitives. 39 * 40 * There is a singleton instance of this dialog which can be retrieved using 41 * {@see #getInstance()}. 42 * 43 * The dialog uses two model: one model for resolving tag conflicts, the other model 44 * for resolving conflicts in relation membership. For both models there are accessors, 45 * i.e {@see #getTagConflictResolverModel()} and {@see #getRelationMemberConflictResolverModel()}. 46 * 47 * Models have to be <strong>populated</strong> before the dialog is launched. Example: 48 * <pre> 49 * CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance(); 50 * dialog.getTagConflictResolverModel().populate(aTagCollection); 51 * dialog.getRelationMemberConflictResolverModel().populate(aRelationLinkCollection); 52 * dialog.prepareDefaultDecisions(); 53 * </pre> 54 * 55 * You should also set the target primitive which other primitives (ways or nodes) are 56 * merged to. Use {@see #setTargetPrimitive(OsmPrimitive)}. 57 * 58 * After the dialog closed use {@see #isCancelled()} to check whether the user cancelled 59 * the dialog. If it wasn't cancelled you may build a collection of {@see Command} objects 60 * which reflect the conflict resolution decisions the user made in the dialog: 61 * see {@see #buildResolutionCommands()} 62 * 63 * 64 */ 65 public class CombinePrimitiveResolverDialog extends JDialog { 66 67 static private CombinePrimitiveResolverDialog instance; 68 69 public static CombinePrimitiveResolverDialog getInstance() { 41 70 if (instance == null) { 42 instance = new Combine WaysConflictResolverDialog(Main.parent);71 instance = new CombinePrimitiveResolverDialog(Main.parent); 43 72 } 44 73 return instance; … … 50 79 private boolean cancelled; 51 80 private JPanel pnlButtons; 52 private Way targetWay;53 54 55 56 public Way getTargetWay() {57 return target Way;58 } 59 60 public void setTarget Way(Way targetWay) {61 this.target Way = targetWay;81 private OsmPrimitive targetPrimitive; 82 83 84 85 public OsmPrimitive getTargetPrimitmive() { 86 return targetPrimitive; 87 } 88 89 public void setTargetPrimitive(OsmPrimitive primitive) { 90 this.targetPrimitive = primitive; 62 91 updateTitle(); 63 92 } 64 93 65 94 protected void updateTitle() { 66 if (target Way== null) {67 setTitle(tr("Conflicts when combining ways"));95 if (targetPrimitive == null) { 96 setTitle(tr("Conflicts when combining primitives")); 68 97 return; 69 98 } 70 setTitle( 71 tr( 72 "Conflicts when combining ways - combined way is ''{0}''", 73 targetWay.getDisplayName(DefaultNameFormatter.getInstance()) 74 ) 75 ); 99 if (targetPrimitive instanceof Way) { 100 setTitle( 101 tr( 102 "Conflicts when combining ways - combined way is ''{0}''", 103 targetPrimitive.getDisplayName(DefaultNameFormatter.getInstance()) 104 ) 105 ); 106 } else if (targetPrimitive instanceof Node) { 107 setTitle( 108 tr( 109 "Conflicts when merging nodes - merged node is ''{0}''", 110 targetPrimitive.getDisplayName(DefaultNameFormatter.getInstance()) 111 ) 112 ); 113 } 76 114 } 77 115 … … 113 151 } 114 152 115 public Combine WaysConflictResolverDialog(Component owner) {153 public CombinePrimitiveResolverDialog(Component owner) { 116 154 super(JOptionPane.getFrameForComponent(owner),true /* modal */); 117 155 build(); … … 143 181 } 144 182 145 public List<Command> buildResolutionCommands( Way targetWay) {183 public List<Command> buildResolutionCommands() { 146 184 List<Command> cmds = new LinkedList<Command>(); 147 185 148 186 if (getTagConflictResolverModel().getNumDecisions() >0) { 149 187 TagCollection tc = getTagConflictResolverModel().getResolution(); 150 cmds.addAll(buildTagChangeCommand(target Way, tc));188 cmds.addAll(buildTagChangeCommand(targetPrimitive, tc)); 151 189 } 152 190 153 191 if (getRelationMemberConflictResolverModel().getNumDecisions() >0) { 154 cmds.addAll(getRelationMemberConflictResolverModel().buildResolutionCommands(target Way));192 cmds.addAll(getRelationMemberConflictResolverModel().buildResolutionCommands(targetPrimitive)); 155 193 } 156 194 157 195 Command cmd = pnlRelationMemberConflictResolver.buildTagApplyCommands( 158 getRelationMemberConflictResolverModel().getModifiedRelations(target Way)196 getRelationMemberConflictResolverModel().getModifiedRelations(targetPrimitive) 159 197 ); 160 198 if (cmd != null) { … … 242 280 ) 243 281 ).applySafe(this); 282 setCancelled(false); 244 283 } else { 245 284 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); -
trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverModel.java
r2070 r2095 18 18 import org.openstreetmap.josm.data.osm.Relation; 19 19 import org.openstreetmap.josm.data.osm.RelationMember; 20 20 import org.openstreetmap.josm.data.osm.BackreferencedDataSet.RelationToChildReference; 21 22 /** 23 * This model manages a list of conflicting relation members. 24 * 25 * It can be used as {@see TableModel}. 26 * 27 * 28 */ 21 29 public class RelationMemberConflictResolverModel extends DefaultTableModel { 30 /** the property name for the number conflicts managed by this model */ 22 31 static public final String NUM_CONFLICTS_PROP = RelationMemberConflictResolverModel.class.getName() + ".numConflicts"; 23 32 33 /** the list of conflict decisions */ 24 34 private List<RelationMemberConflictDecision> decisions; 35 /** the collection of relations for which we manage conflicts */ 25 36 private Collection<Relation> relations; 37 /** the number of conflicts */ 26 38 private int numConflicts; 27 39 private PropertyChangeSupport support; 28 40 29 41 42 /** 43 * Replies the current number of conflicts 44 * 45 * @return the current number of conflicts 46 */ 30 47 public int getNumConflicts() { 31 48 return numConflicts; 32 49 } 33 50 51 /** 52 * Updates the current number of conflicts from list of decisions and emits 53 * a property change event if necessary. 54 * 55 */ 34 56 protected void updateNumConflicts() { 35 57 int count = 0; … … 71 93 RelationMemberConflictDecision d = decisions.get(row); 72 94 switch(column) { 73 74 75 76 77 95 case 0: /* relation */ return d.getRelation(); 96 case 1: /* pos */ return Integer.toString(d.getPos() + 1); // position in "user space" starting at 1 97 case 2: /* role */ return d.getRole(); 98 case 3: /* original */ return d.getOriginalPrimitive(); 99 case 4: /* decision */ return d.getDecision(); 78 100 } 79 101 return null; … … 84 106 RelationMemberConflictDecision d = decisions.get(row); 85 107 switch(column) { 86 87 88 89 90 91 92 108 case 2: /* role */ 109 d.setRole((String)value); 110 break; 111 case 4: /* decision */ 112 d.decide((RelationMemberConflictDecisionType)value); 113 refresh(); 114 break; 93 115 } 94 116 fireTableDataChanged(); 95 117 } 96 118 119 /** 120 * Populates the model with the members of the relation <code>relation</code> 121 * referring to <code>primitive</code>. 122 * 123 * @param relation the parent relation 124 * @param primitive the child primitive 125 */ 97 126 protected void populate(Relation relation, OsmPrimitive primitive) { 127 decisions.clear(); 98 128 for (int i =0; i<relation.getMembersCount();i++) { 99 129 if (relation.getMember(i).refersTo(primitive)) { … … 103 133 } 104 134 135 /** 136 * Populates the model with the relation members belonging to one of the relations in <code>relations</code> 137 * and referring to one of the primitives in <code>memberPrimitives</code>. 138 * 139 * @param relations the parent relations. Empty list assumed if null. 140 * @param memberPrimitives the child primitives. Empty list assumed if null. 141 */ 105 142 public void populate(Collection<Relation> relations, Collection<? extends OsmPrimitive> memberPrimitives) { 106 143 decisions.clear(); 144 relations = relations == null ? new LinkedList<Relation>() : relations; 145 memberPrimitives = memberPrimitives == null ? new LinkedList<OsmPrimitive>() : memberPrimitives; 107 146 for (Relation r : relations) { 108 147 for (OsmPrimitive p: memberPrimitives) { … … 114 153 } 115 154 155 /** 156 * Populates the model with the relation members represented as a collection of 157 * {@see RelationToChildReference}s. 158 * 159 * @param references the references. Empty list assumed if null. 160 */ 161 public void populate(Collection<RelationToChildReference> references) { 162 references = references == null ? new LinkedList<RelationToChildReference>() : references; 163 if (references.isEmpty()) { 164 this.relations = new HashSet<Relation>(references.size()); 165 return; 166 } 167 decisions.clear(); 168 this.relations = new HashSet<Relation>(references.size()); 169 for (RelationToChildReference reference: references) { 170 decisions.add(new RelationMemberConflictDecision(reference.getParent(), reference.getPosition())); 171 relations.add(reference.getParent()); 172 } 173 refresh(); 174 } 175 176 /** 177 * Replies the decision at position <code>row</code> 178 * 179 * @param row 180 * @return the decision at position <code>row</code> 181 */ 116 182 public RelationMemberConflictDecision getDecision(int row) { 117 183 return decisions.get(row); 118 184 } 119 185 186 /** 187 * Replies the number of decisions managed by this model 188 * 189 * @return the number of decisions managed by this model 190 */ 120 191 public int getNumDecisions() { 121 192 return getRowCount(); 122 193 } 123 194 195 /** 196 * Refreshes the model state. Invoke this method to trigger necessary change 197 * events after an update of the model data. 198 * 199 */ 124 200 public void refresh() { 125 201 updateNumConflicts(); … … 127 203 } 128 204 205 /** 206 * Apply a role to all member managed by this model. 207 * 208 * @param role the role. Empty string assumed if null. 209 */ 129 210 public void applyRole(String role) { 130 211 role = role == null ? "" : role; … … 154 235 } else { 155 236 switch(decision.getDecision()) { 156 157 158 159 160 161 162 163 164 165 166 167 237 case REPLACE: 238 rmNew = new RelationMember(decision.getRole(),newPrimitive); 239 modifiedRelation.addMember(rmNew); 240 isChanged |= ! rm.equals(rmNew); 241 break; 242 case REMOVE: 243 isChanged = true; 244 // do nothing 245 break; 246 case UNDECIDED: 247 // FIXME: this is an error 248 break; 168 249 } 169 250 } … … 174 255 } 175 256 257 /** 258 * Builds a collection of commands executing the decisions made in this model. 259 * 260 * @param newPrimitive the primitive which members shall refer to if the 261 * decision is {@see RelationMemberConflictDecisionType#REPLACE} 262 * @return a list of commands 263 */ 176 264 public List<Command> buildResolutionCommands(OsmPrimitive newPrimitive) { 177 265 List<Command> command = new LinkedList<Command>(); … … 192 280 } 193 281 switch(decision.getDecision()) { 194 195 196 197 198 199 200 201 282 case REMOVE: return true; 283 case REPLACE: 284 if (!relation.getMember(i).getRole().equals(decision.getRole())) 285 return true; 286 if (relation.getMember(i).getMember() != newPrimitive) 287 return true; 288 case UNDECIDED: 289 // FIXME: handle error 202 290 } 203 291 } … … 205 293 } 206 294 295 /** 296 * Replies the set of relations which have to be modified according 297 * to the decisions managed by this model. 298 * 299 * @param newPrimitive the primitive which members shall refer to if the 300 * decision is {@see RelationMemberConflictDecisionType#REPLACE} 301 * 302 * @return the set of relations which have to be modified according 303 * to the decisions managed by this model 304 */ 207 305 public Set<Relation> getModifiedRelations(OsmPrimitive newPrimitive) { 208 306 HashSet<Relation> ret = new HashSet<Relation>();
Note:
See TracChangeset
for help on using the changeset viewer.