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


Ignore:
Timestamp:
2008-10-05T17:14:00+02:00 (16 years ago)
Author:
stoecker
Message:

close #1625 - unglue action update

File:
1 edited

Legend:

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

    r1023 r1024  
    2929
    3030/**
    31  * Dupe a node that is used my multiple ways, so each way has its own node.
     31 * Duplicate nodes that are used by multiple ways.
    3232 *
    3333 * Resulting nodes are identical, up to their position.
     
    3636 */
    3737
    38 public class UnGlueAction extends JosmAction implements SelectionChangedListener {
     38public class UnGlueAction extends JosmAction { //implements SelectionChangedListener {
    3939
    4040        private Node selectedNode;
    4141        private Way selectedWay;
    42 
    43         /**
    44          * Create a new SplitWayAction.
     42        private ArrayList<Node> selectedNodes;
     43
     44        /**
     45         * Create a new UnGlueAction.
    4546         */
    4647        public UnGlueAction() {
    47                 super(tr("UnGlue Ways"), "unglueways", tr("Duplicate the selected node so each way using it has its own copy."),
     48                super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."),
    4849                ShortCut.registerShortCut("tools:unglue", tr("Tool: Unglue"), KeyEvent.VK_G, ShortCut.GROUP_EDIT), true);
    49                 DataSet.selListeners.add(this);
     50                //DataSet.selListeners.add(this);
    5051        }
    5152
     
    5354         * Called when the action is executed.
    5455         *
    55          * This method just collects the single node selected and calls the unGlueWay method.
     56         * This method does some checking on the selection and calls the matching unGlueWay method.
    5657         */
    5758        public void actionPerformed(ActionEvent e) {
     
    5960                Collection<OsmPrimitive> selection = Main.ds.getSelected();
    6061
    61                 if (!checkSelection(selection)) {
    62                         JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for unglueing."));
    63                         return;
    64                 }
    65 
    66                 int count = 0;
    67                 for (Way w : Main.ds.ways) {
    68                         if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    69                         if (!w.nodes.contains(selectedNode)) continue;
    70                         count++;
    71                 }
    72                 if (count < 2) {
    73                         JOptionPane.showMessageDialog(Main.parent, tr("You must select a node that is used by at least 2 ways."));
    74                         return;
    75                 }
    76 
    77                 // and then do the work.
    78                 unglueWays();
     62                if (checkSelection(selection)) {
     63                        int count = 0;
     64                        for (Way w : Main.ds.ways) {
     65                                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     66                                if (!w.nodes.contains(selectedNode)) continue;
     67                                count++;
     68                        }
     69                        if (count < 2) {
     70                                JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else."));
     71                        } else {
     72                                // and then do the work.
     73                                unglueWays();
     74                        }
     75                } else if (checkSelection2(selection)) {
     76                        ArrayList<Node> tmpNodes = new ArrayList<Node>();
     77                        for (Node n : selectedNodes) {
     78                                int count = 0;
     79                                for (Way w : Main.ds.ways) {
     80                                        if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     81                                        if (!w.nodes.contains(n)) continue;
     82                                        count++;
     83                                }
     84                                if (count >= 2) {
     85                                        tmpNodes.add(n);
     86                                }
     87                        }
     88                        if (tmpNodes.size() < 1) {
     89                                if (selection.size() > 1) {
     90                                        JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else."));
     91                                } else {
     92                                        JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else."));
     93                                }
     94                        } else {
     95                                // and then do the work.
     96                                selectedNodes = tmpNodes;
     97                                unglueWays2();
     98                        }
     99                } else {
     100                        JOptionPane.showMessageDialog(Main.parent,
     101                                tr("The current selection cannot be used for unglueing.")+"\n"+
     102                                "\n"+
     103                                tr("Select either:")+"\n"+
     104                                tr("* One node that is used by more than one way, or")+"\n"+
     105                                tr("* One node that is used by more than one way and one of those ways, or")+"\n"+
     106                                tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+
     107                                tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+
     108                                "\n"+
     109                                tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+
     110                                   "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+
     111                                   "own copy and all nodes will be selected.")
     112                        );
     113                }
     114                selectedNode = null;
     115                selectedWay = null;
     116                selectedNodes = null;
    79117        }
    80118
     
    85123         * input for splitting (this would be too expensive to be carried
    86124         * out from the selectionChanged listener).
     125         *
     126         * If this method returns "true", selectedNode and selectedWay will
     127         * be set.
     128         *
     129         * Returns true if either one node is selected or one node and one
     130         * way are selected and the node is part of the way.
     131         *
     132         * The way will be put into the object variable "selectedWay", the
     133         * node into "selectedNode".
    87134         */
    88135        private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
     
    110157        }
    111158
    112         private boolean modifyWay(boolean firstway, Way w, List<Command> cmds,
    113                         List<Node> newNodes) {
     159        /**
     160         * Checks if the selection consists of something we can work with.
     161         * Checks only if the number and type of items selected looks good;
     162         * does not check whether the selected items are really a valid
     163         * input for splitting (this would be too expensive to be carried
     164         * out from the selectionChanged listener).
     165         *
     166         * Returns true if one way and any number of nodes that are part of
     167         * that way are selected. Note: "any" can be none, then all nodes of
     168         * the way are used.
     169         *
     170         * The way will be put into the object variable "selectedWay", the
     171         * nodes into "selectedNodes".
     172         */
     173        private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) {
     174                if (selection.size() < 1)
     175                        return false;
     176
     177                selectedWay = null;
     178                for (OsmPrimitive p : selection) {
     179                        if (p instanceof Way) {
     180                                if (selectedWay != null) {
     181                                        return false;
     182                                }
     183                                selectedWay = (Way) p;
     184                        }
     185                }
     186                if (selectedWay == null) {
     187                        return false;
     188                }
     189
     190                selectedNodes = new ArrayList<Node>();
     191                for (OsmPrimitive p : selection) {
     192                        if (p instanceof Node) {
     193                                Node n = (Node) p;
     194                                if (!selectedWay.nodes.contains(n)) {
     195                                        return false;
     196                                }
     197                                selectedNodes.add(n);
     198                        }
     199                }
     200
     201                if (selectedNodes.size() < 1) {
     202                        selectedNodes.addAll(selectedWay.nodes);
     203                }
     204
     205                return true;
     206        }
     207
     208        /**
     209         * dupe the given node of the given way
     210         *
     211         * -> the new node will be put into the parameter newNodes.
     212         * -> the add-node command will be put into the parameter cmds.
     213         * -> the changed way will be returned and must be put into cmds by the caller!
     214         */
     215        private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
    114216                ArrayList<Node> nn = new ArrayList<Node>();
    115217                for (Node pushNode : w.nodes) {
    116                         if (selectedNode == pushNode) {
    117                                 if (firstway) {
    118                                         // reuse the old node for the first (==a random) way
    119                                         firstway = false;
    120                                 } else {
    121                                         // clone the node for all other ways
    122                                         pushNode = new Node(selectedNode);
    123                                         pushNode.id = 0;
    124                                         newNodes.add(pushNode);
    125                                         cmds.add(new AddCommand(pushNode));
    126                                 }
     218                        if (originalNode == pushNode) {
     219                                // clone the node for all other ways
     220                                pushNode = new Node(pushNode);
     221                                pushNode.id = 0;
     222                                newNodes.add(pushNode);
     223                                cmds.add(new AddCommand(pushNode));
    127224                        }
    128225                        nn.add(pushNode);
     
    131228                newWay.nodes.clear();
    132229                newWay.nodes.addAll(nn);
    133                 cmds.add(new ChangeCommand(w, newWay));
    134 
    135                 return firstway;
    136         }
    137 
    138         /**
    139          * see above
    140          */
    141         private void unglueWays() {
    142 
    143                 LinkedList<Command> cmds = new LinkedList<Command>();
    144                 List<Node> newNodes = new LinkedList<Node>();
    145 
    146                 if (selectedWay == null) {
    147 
    148                         boolean firstway = true;
    149                         // modify all ways containing the nodes
    150                         for (Way w : Main.ds.ways) {
    151                                 if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
    152                                 if (!w.nodes.contains(selectedNode)) continue;
    153 
    154                                 firstway = modifyWay(firstway, w, cmds, newNodes);
    155                         }
    156                 } else {
    157                         modifyWay(false, selectedWay, cmds, newNodes);
    158                 }
    159 
     230
     231                return newWay;
     232        }
     233
     234        /**
     235         * put all newNodes into the same relation(s) that originalNode is in
     236         */
     237        private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
    160238                // modify all relations containing the node
    161239                Relation newRel = null;
     
    167245                        for (RelationMember rm : r.members) {
    168246                                if (rm.member instanceof Node) {
    169                                         if (rm.member == selectedNode) {
     247                                        if (rm.member == originalNode) {
    170248                                                if (newRel == null) {
    171249                                                        newRel = new Relation(r);
     
    191269                        }
    192270                }
    193 
    194                 newNodes.add(selectedNode); // just for the next 2 lines
    195                 Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()), cmds));
     271        }
     272
     273
     274        /**
     275         * dupe a single node into as many nodes as there are ways using it, OR
     276         *
     277         * dupe a single node once, and put the copy on the selected way
     278         */
     279        private void unglueWays() {
     280                LinkedList<Command> cmds = new LinkedList<Command>();
     281                List<Node> newNodes = new LinkedList<Node>();
     282
     283                if (selectedWay == null) {
     284                        boolean firstway = true;
     285                        // modify all ways containing the nodes
     286                        for (Way w : Main.ds.ways) {
     287                                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
     288                                if (!w.nodes.contains(selectedNode)) continue;
     289                                if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
     290                                firstway = false;
     291                        }
     292                } else {
     293                        cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));
     294                }
     295
     296                fixRelations(selectedNode, cmds, newNodes);
     297
     298                Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds));
     299                if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes
     300                        newNodes.add(selectedNode);
     301                } // if a node and a way has been selected, new selection is only the new node that was added to the selected way
    196302                Main.ds.setSelected(newNodes);
    197 
    198         }
    199 
    200         /**
    201          * Enable the "split way" menu option if the selection looks like we could use it.
    202          */
    203         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    204                 setEnabled(checkSelection(newSelection));
    205         }
     303        }
     304
     305        /**
     306         * dupe all nodes that are selected, and put the copies on the selected way
     307         *
     308         */
     309        private void unglueWays2() {
     310                LinkedList<Command> cmds = new LinkedList<Command>();
     311                List<Node> allNewNodes = new LinkedList<Node>();
     312                Way tmpWay = selectedWay;
     313
     314                for (Node n : selectedNodes) {
     315                        List<Node> newNodes = new LinkedList<Node>();
     316                        tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
     317                        fixRelations(n, cmds, newNodes);
     318                        allNewNodes.addAll(newNodes);
     319                }
     320                cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen
     321
     322                Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
     323                Main.ds.setSelected(allNewNodes);
     324        }
     325
     326// Disabled because we have such a nice help text that would not be shown otherwise.
     327//
     328//      /**
     329//       * Enable the menu option if the selection looks like we could use it.
     330//       */
     331//      public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
     332//              setEnabled(checkSelection(newSelection) || checkSelection2(newSelection));
     333//              selectedNode = null;
     334//              selectedWay = null;
     335//              selectedNodes = null;
     336//      }
    206337}
Note: See TracChangeset for help on using the changeset viewer.