Changeset 8886 in josm


Ignore:
Timestamp:
2015-10-17T13:14:12+02:00 (3 years ago)
Author:
simon04
Message:

fix #10730 - Way splitting: reuse id/history of existing object for longest split segment and allow expert users to select this segment

File:
1 edited

Legend:

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

    r8846 r8886  
    66import static org.openstreetmap.josm.tools.I18n.trn;
    77
     8import java.awt.Component;
     9import java.awt.GridLayout;
    810import java.awt.event.ActionEvent;
    911import java.awt.event.KeyEvent;
     
    1820import java.util.Set;
    1921
     22import javax.swing.DefaultListCellRenderer;
     23import javax.swing.JLabel;
     24import javax.swing.JList;
    2025import javax.swing.JOptionPane;
     26import javax.swing.JPanel;
     27import javax.swing.ListSelectionModel;
     28import javax.swing.event.ListSelectionEvent;
     29import javax.swing.event.ListSelectionListener;
    2130
    2231import org.openstreetmap.josm.Main;
     
    3140import org.openstreetmap.josm.data.osm.RelationMember;
    3241import org.openstreetmap.josm.data.osm.Way;
     42import org.openstreetmap.josm.data.osm.WaySegment;
    3343import org.openstreetmap.josm.gui.DefaultNameFormatter;
     44import org.openstreetmap.josm.gui.ExtendedDialog;
    3445import org.openstreetmap.josm.gui.Notification;
    3546import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3647import org.openstreetmap.josm.tools.CheckParameterUtil;
    3748import org.openstreetmap.josm.tools.Shortcut;
     49import org.openstreetmap.josm.tools.Utils;
    3850
    3951/**
     
    176188
    177189        // Finally, applicableWays contains only one perfect way
    178         Way selectedWay = applicableWays.get(0);
    179 
    180         List<List<Node>> wayChunks = buildSplitChunks(selectedWay, selectedNodes);
     190        final Way selectedWay = applicableWays.get(0);
     191        final List<List<Node>> wayChunks = buildSplitChunks(selectedWay, selectedNodes);
    181192        if (wayChunks != null) {
    182             List<OsmPrimitive> sel = new ArrayList<>(selectedWays.size() + selectedRelations.size());
     193            final List<OsmPrimitive> sel = new ArrayList<>(selectedWays.size() + selectedRelations.size());
    183194            sel.addAll(selectedWays);
    184195            sel.addAll(selectedRelations);
    185             SplitWayResult result = splitWay(getEditLayer(), selectedWay, wayChunks, sel);
    186             Main.main.undoRedo.add(result.getCommand());
    187             getCurrentDataSet().setSelected(result.getNewSelection());
    188         }
    189     }
    190 
    191     /**
    192      * Determine witch ways to split.
     196
     197            final List<Way> newWays = createNewWaysFromChunks(selectedWay, wayChunks);
     198            final Way wayToKeep = determineWayToKeep(newWays);
     199
     200            if (ExpertToggleAction.isExpert() && !selectedWay.isNew()) {
     201                final ExtendedDialog dialog = new SegmentToKeepSelectionDialog(selectedWay, newWays, wayToKeep, sel);
     202                dialog.setModal(false);
     203                dialog.showDialog();
     204            } else {
     205                final SplitWayResult result = doSplitWay(getEditLayer(), selectedWay, wayToKeep, newWays, sel);
     206                Main.main.undoRedo.add(result.getCommand());
     207                getCurrentDataSet().setSelected(result.getNewSelection());
     208            }
     209        }
     210    }
     211
     212    /**
     213     * A dialog to query which way segment should reuse the history of the way to split.
     214     */
     215    static class SegmentToKeepSelectionDialog extends ExtendedDialog {
     216        final Way selectedWay;
     217        final List<Way> newWays;
     218        final JList<Way> list;
     219        final List<OsmPrimitive> selection;
     220
     221        SegmentToKeepSelectionDialog(Way selectedWay, List<Way> newWays, Way wayToKeep, List<OsmPrimitive> selection) {
     222            super(Main.parent, tr("Which way segment should reuse the history of {0}?", selectedWay.getId()),
     223                    new String[]{tr("Ok"), tr("Cancel")}, true);
     224
     225            this.selectedWay = selectedWay;
     226            this.newWays = newWays;
     227            this.selection = selection;
     228            this.list = new JList<>(newWays.toArray(new Way[newWays.size()]));
     229            buildList();
     230            this.list.setSelectedValue(wayToKeep, true);
     231
     232            setButtonIcons(new String[]{"ok", "cancel"});
     233            final JPanel pane = new JPanel(new GridLayout(2, 1));
     234            pane.add(new JLabel(getTitle()));
     235            pane.add(list);
     236            setContent(pane);
     237        }
     238
     239        private void buildList() {
     240            list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     241            list.addListSelectionListener(new ListSelectionListener() {
     242                @Override
     243                public void valueChanged(ListSelectionEvent e) {
     244                    final Way selected = list.getSelectedValue();
     245                    if (Main.isDisplayingMapView() && selected != null) {
     246                        final List<WaySegment> segments = Utils.transform(selected.getNodes().subList(0, selected.getNodesCount() - 1), new Utils.Function<Node, WaySegment>() {
     247                            @Override
     248                            public WaySegment apply(Node x) {
     249                                return new WaySegment(selectedWay, selectedWay.getNodes().indexOf(x));
     250                            }
     251                        });
     252                        setHighlightedWaySegments(segments);
     253                    }
     254                }
     255            });
     256            list.setCellRenderer(new DefaultListCellRenderer() {
     257                @Override
     258                public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     259                    final Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     260                    ((JLabel) c).setText(tr("Segment {0}: {1}", index + 1, DefaultNameFormatter.getInstance().format((Way) value)));
     261                    return c;
     262                }
     263            });
     264        }
     265
     266        protected void setHighlightedWaySegments(Collection<WaySegment> segments) {
     267            selectedWay.getDataSet().setHighlightedWaySegments(segments);
     268            Main.map.mapView.repaint();
     269        }
     270
     271        @Override
     272        public void setVisible(boolean visible) {
     273            super.setVisible(visible);
     274            if (visible) {
     275                list.setSelectedIndex(list.getSelectedIndex()); // highlight way segments
     276            } else {
     277                setHighlightedWaySegments(Collections.<WaySegment>emptyList());
     278            }
     279        }
     280
     281        @Override
     282        protected void buttonAction(int buttonIndex, ActionEvent evt) {
     283            super.buttonAction(buttonIndex, evt);
     284            if (getValue() == 1) {
     285                final Way wayToKeep = list.getSelectedValue();
     286                final SplitWayResult result = doSplitWay(getEditLayer(), selectedWay, wayToKeep, newWays, selection);
     287                Main.main.undoRedo.add(result.getCommand());
     288                getCurrentDataSet().setSelected(result.getNewSelection());
     289            }
     290        }
     291    }
     292
     293    /**
     294     * Determines which way chunk should reuse the old id and its history. Selects the one with the highest node count.
     295     * @param wayChunks the way chunks
     296     * @return the way to keep
     297     */
     298    protected static Way determineWayToKeep(Iterable<Way> wayChunks) {
     299        Way wayToKeep = null;
     300        for (Way i : wayChunks) {
     301            if (wayToKeep == null || i.getNodesCount() > wayToKeep.getNodesCount()) {
     302                wayToKeep = i;
     303            }
     304        }
     305        return wayToKeep;
     306    }
     307
     308    /**
     309     * Determine which ways to split.
    193310     * @param selectedWays List of user selected ways.
    194311     * @param selectedNodes List of user selected nodes.
     
    329446
    330447    /**
     448     * Creates new way objects for the way chunks and transfers the keys from the original way.
     449     * @param way the original way whose  keys are transferred
     450     * @param wayChunks the way chunks
     451     * @return the new way objects
     452     */
     453    protected static List<Way> createNewWaysFromChunks(Way way, Iterable<List<Node>> wayChunks) {
     454        final List<Way> newWays = new ArrayList<>();
     455        for (List<Node> wayChunk : wayChunks) {
     456            Way wayToAdd = new Way();
     457            wayToAdd.setKeys(way.getKeys());
     458            wayToAdd.setNodes(wayChunk);
     459            newWays.add(wayToAdd);
     460        }
     461        return newWays;
     462    }
     463
     464    /**
    331465     * Splits the way {@code way} into chunks of {@code wayChunks} and replies
    332466     * the result of this process in an instance of {@link SplitWayResult}.
     
    345479            Collection<? extends OsmPrimitive> selection) {
    346480        // build a list of commands, and also a new selection list
    347         Collection<Command> commandList = new ArrayList<>(wayChunks.size());
    348         List<OsmPrimitive> newSelection = new ArrayList<>(selection.size() + wayChunks.size());
     481        final List<OsmPrimitive> newSelection = new ArrayList<>(selection.size() + wayChunks.size());
    349482        newSelection.addAll(selection);
    350483
    351         Iterator<List<Node>> chunkIt = wayChunks.iterator();
     484        // Create all potential new ways
     485        final List<Way> newWays = createNewWaysFromChunks(way, wayChunks);
     486
     487        // Determine which part reuses the existing way
     488        final Way wayToKeep = determineWayToKeep(newWays);
     489
     490        return doSplitWay(layer, way, wayToKeep, newWays, newSelection);
     491    }
     492
     493    static SplitWayResult doSplitWay(OsmDataLayer layer, Way way, Way wayToKeep, List<Way> newWays,
     494                                   List<OsmPrimitive> newSelection) {
     495
     496        Collection<Command> commandList = new ArrayList<>(newWays.size());
    352497        Collection<String> nowarnroles = Main.pref.getCollection("way.split.roles.nowarn",
    353498                Arrays.asList("outer", "inner", "forward", "backward", "north", "south", "east", "west"));
    354499
    355         // First, change the original way
    356         Way changedWay = new Way(way);
    357         changedWay.setNodes(chunkIt.next());
     500        // Change the original way
     501        final Way changedWay = new Way(way);
     502        changedWay.setNodes(wayToKeep.getNodes());
    358503        commandList.add(new ChangeCommand(way, changedWay));
    359504        if (!newSelection.contains(way)) {
    360505            newSelection.add(way);
    361506        }
    362 
    363         List<Way> newWays = new ArrayList<>();
    364         // Second, create new ways
    365         while (chunkIt.hasNext()) {
    366             Way wayToAdd = new Way();
    367             wayToAdd.setKeys(way.getKeys());
    368             newWays.add(wayToAdd);
    369             wayToAdd.setNodes(chunkIt.next());
     507        newWays.remove(wayToKeep);
     508
     509        for (Way wayToAdd : newWays) {
    370510            commandList.add(new AddCommand(layer, wayToAdd));
    371511            newSelection.add(wayToAdd);
    372512        }
     513
    373514        boolean warnmerole = false;
    374515        boolean warnme = false;
     
    509650                new SequenceCommand(
    510651                        /* for correct i18n of plural forms - see #9110 */
    511                         trn("Split way {0} into {1} part", "Split way {0} into {1} parts", wayChunks.size(),
    512                                 way.getDisplayName(DefaultNameFormatter.getInstance()), wayChunks.size()),
     652                        trn("Split way {0} into {1} part", "Split way {0} into {1} parts", newWays.size(),
     653                                way.getDisplayName(DefaultNameFormatter.getInstance()), newWays.size()),
    513654                        commandList
    514655                        ),
Note: See TracChangeset for help on using the changeset viewer.