Changeset 6564 in josm


Ignore:
Timestamp:
2013-12-29T20:31:47+01:00 (6 years ago)
Author:
simon04
Message:

fix 9492 - Tools>"Create Multipolygon": updates multipolygon if a multipolygon relation is selected

Location:
trunk
Files:
2 added
2 edited

Legend:

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

    r6336 r6564  
    1010import java.util.Collection;
    1111import java.util.HashMap;
     12import java.util.HashSet;
    1213import java.util.List;
    1314import java.util.Map;
     
    3334import org.openstreetmap.josm.gui.Notification;
    3435import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
     36import org.openstreetmap.josm.tools.Pair;
    3537import org.openstreetmap.josm.tools.Shortcut;
     38import org.openstreetmap.josm.tools.Utils;
    3639
    3740/**
     
    5659     */
    5760    public CreateMultipolygonAction() {
    58         super(tr("Create multipolygon"), "multipoly_create", tr("Create multipolygon."),
     61        super(tr("Create multipolygon"), "multipoly_create", tr("Create multipolygon"),
    5962            Shortcut.registerShortcut("tools:multipoly", tr("Tool: {0}", tr("Create multipolygon")),
    6063            KeyEvent.VK_A, Shortcut.ALT_CTRL), true);
     
    7679        }
    7780
    78         Collection<Way> selectedWays = Main.main.getCurrentDataSet().getSelectedWays();
     81        final Collection<Way> selectedWays = Main.main.getCurrentDataSet().getSelectedWays();
     82        final Collection<Relation> selectedRelations = Main.main.getCurrentDataSet().getSelectedRelations();
    7983
    8084        if (selectedWays.size() < 1) {
     
    8993        }
    9094
    91         MultipolygonCreate polygon = this.analyzeWays(selectedWays);
    92 
    93         if (polygon == null)
    94             return;                   //could not make multipolygon.
    95 
    96         final Relation relation = this.createRelation(polygon);
    97 
    98         if (Main.pref.getBoolean("multipoly.show-relation-editor", false)) {
    99             //Open relation edit window, if set up in preferences
    100             RelationEditor editor = RelationEditor.getEditor(Main.main.getEditLayer(), relation, null);
    101 
    102             editor.setModal(true);
    103             editor.setVisible(true);
    104 
    105             //TODO: cannot get the resulting relation from RelationEditor :(.
    106             /*
    107             if (relationCountBefore < relationCountAfter) {
    108                 //relation saved, clean up the tags
    109                 List<Command> list = this.removeTagsFromInnerWays(relation);
    110                 if (list.size() > 0)
    111                 {
    112                     Main.main.undoRedo.add(new SequenceCommand(tr("Remove tags from multipolygon inner ways"), list));
    113                 }
    114             }
    115              */
    116 
     95        final Pair<SequenceCommand, Relation> commandAndRelation = createMultipolygonCommand(selectedWays, selectedRelations);
     96        final Command command = commandAndRelation.a;
     97        final Relation relation = commandAndRelation.b;
     98        if (command == null) {
     99            return;
     100        }
     101        Main.main.undoRedo.add(command);
     102
     103        // Use 'SwingUtilities.invokeLater' to make sure the relationListDialog
     104        // knows about the new relation before we try to select it.
     105        // (Yes, we are already in event dispatch thread. But DatasetEventManager
     106        // uses 'SwingUtilities.invokeLater' to fire events so we have to do
     107        // the same.)
     108        SwingUtilities.invokeLater(new Runnable() {
     109            @Override
     110            public void run() {
     111                Main.map.relationListDialog.selectRelation(relation);
     112                if (Main.pref.getBoolean("multipoly.show-relation-editor", false)) {
     113                    //Open relation edit window, if set up in preferences
     114                    RelationEditor editor = RelationEditor.getEditor(Main.main.getEditLayer(), relation, null);
     115
     116                    editor.setModal(true);
     117                    editor.setVisible(true);
     118                }
     119            }
     120        });
     121
     122    }
     123
     124    private static Relation getSelectedMultipolygonRelation(Collection<Relation> selectedRelations) {
     125        return  selectedRelations.size() == 1 && "multipolygon".equals(selectedRelations.iterator().next().get("type"))
     126                ? selectedRelations.iterator().next()
     127                : null;
     128    }
     129
     130    /**
     131     * Returns a {@link Pair} of the old multipolygon {@link Relation} (or null) and the newly created/modified multipolygon {@link Relation}.
     132     */
     133    public static Pair<Relation, Relation> createMultipolygonRelation(Collection<Way> selectedWays, Collection<Relation> selectedRelations) {
     134
     135        final Relation selectedMultipolygonRelation = getSelectedMultipolygonRelation(selectedRelations);
     136        if (selectedMultipolygonRelation != null) {
     137            // add ways of existing relation to include them in polygon analysis
     138            selectedWays = new HashSet<Way>(selectedWays);
     139            selectedWays.addAll(Utils.filteredCollection(selectedMultipolygonRelation.getMemberPrimitives(), Way.class));
     140        }
     141
     142        final MultipolygonCreate polygon = analyzeWays(selectedWays);
     143        if (polygon == null) {
     144            return null; //could not make multipolygon.
     145        }
     146
     147        if (selectedMultipolygonRelation != null) {
     148            return Pair.create(selectedMultipolygonRelation, createRelation(polygon, new Relation(selectedMultipolygonRelation)));
    117149        } else {
    118             //Just add the relation
    119             List<Command> list = this.removeTagsFromWaysIfNeeded(relation);
     150            return Pair.create(null, createRelation(polygon, new Relation()));
     151        }
     152    }
     153
     154    /**
     155     * Returns a pair of a multipolygon creating/modifying {@link Command} as well as the multipolygon {@link Relation}.
     156     */
     157    public static Pair<SequenceCommand, Relation> createMultipolygonCommand(Collection<Way> selectedWays, Collection<Relation> selectedRelations) {
     158
     159        final Pair<Relation, Relation> rr = createMultipolygonRelation(selectedWays, selectedRelations);
     160        if (rr == null) {
     161            return null;
     162        }
     163        final Relation existingRelation = rr.a;
     164        final Relation relation = rr.b;
     165
     166        final List<Command> list = removeTagsFromWaysIfNeeded(relation);
     167        final String commandName;
     168        if (existingRelation == null) {
    120169            list.add(new AddCommand(relation));
    121             Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));
    122             // Use 'SwingUtilities.invokeLater' to make sure the relationListDialog
    123             // knows about the new relation before we try to select it.
    124             // (Yes, we are already in event dispatch thread. But DatasetEventManager
    125             // uses 'SwingUtilities.invokeLater' to fire events so we have to do
    126             // the same.)
    127             SwingUtilities.invokeLater(new Runnable() {
    128                 @Override
    129                 public void run() {
    130                     Main.map.relationListDialog.selectRelation(relation);
    131                 }
    132             });
    133         }
    134 
    135 
     170            commandName = tr("Create multipolygon");
     171        } else {
     172            list.add(new ChangeCommand(existingRelation, relation));
     173            commandName = tr("Update multipolygon");
     174        }
     175        return Pair.create(new SequenceCommand(commandName, list), relation);
    136176    }
    137177
     
    152192    @Override protected void updateEnabledState(Collection < ? extends OsmPrimitive > selection) {
    153193        setEnabled(selection != null && !selection.isEmpty());
     194        putValue(NAME, getSelectedMultipolygonRelation(getCurrentDataSet().getSelectedRelations()) != null
     195                ? tr("Update multipolygon")
     196                : tr("Create multipolygon")
     197        );
    154198    }
    155199
     
    159203     * @return <code>null</code>, if there was a problem with the ways.
    160204     */
    161     private MultipolygonCreate analyzeWays(Collection < Way > selectedWays) {
     205    private static MultipolygonCreate analyzeWays(Collection < Way > selectedWays) {
    162206
    163207        MultipolygonCreate pol = new MultipolygonCreate();
     
    179223     * @return multipolygon relation
    180224     */
    181     private Relation createRelation(MultipolygonCreate pol) {
     225    private static Relation createRelation(MultipolygonCreate pol, final Relation rel) {
    182226        // Create new relation
    183         Relation rel = new Relation();
    184227        rel.put("type", "multipolygon");
    185228        // Add ways to it
    186229        for (JoinedPolygon jway:pol.outerWays) {
    187             for (Way way:jway.ways) {
    188                 rel.addMember(new RelationMember("outer", way));
    189             }
     230            addMembers(jway, rel, "outer");
    190231        }
    191232
    192233        for (JoinedPolygon jway:pol.innerWays) {
    193             for (Way way:jway.ways) {
    194                 rel.addMember(new RelationMember("inner", way));
    195             }
     234            addMembers(jway, rel, "inner");
    196235        }
    197236        return rel;
     237    }
     238
     239    private static void addMembers(JoinedPolygon polygon, Relation rel, String role) {
     240        final int count = rel.getMembersCount();
     241        final HashSet<Way> ways = new HashSet<Way>(polygon.ways);
     242        for (int i = 0; i < count; i++) {
     243            final RelationMember m = rel.getMember(i);
     244            if (ways.contains(m.getMember()) && !role.equals(m.getRole())) {
     245                rel.setMember(i, new RelationMember(role, m.getMember()));
     246            }
     247        }
     248        ways.removeAll(rel.getMemberPrimitives());
     249        for (final Way way : ways) {
     250            rel.addMember(new RelationMember(role, way));
     251        }
    198252    }
    199253
     
    206260     * @return a list of commands to execute
    207261     */
    208     private List<Command> removeTagsFromWaysIfNeeded( Relation relation ) {
     262    private static List<Command> removeTagsFromWaysIfNeeded( Relation relation ) {
    209263        Map<String, String> values = new HashMap<String, String>();
    210264
  • trunk/src/org/openstreetmap/josm/data/osm/Relation.java

    r6491 r6564  
    55import java.util.Arrays;
    66import java.util.Collection;
     7import java.util.Collections;
    78import java.util.HashSet;
    89import java.util.List;
     
    1415import org.openstreetmap.josm.data.osm.visitor.Visitor;
    1516import org.openstreetmap.josm.tools.CopyList;
     17import org.openstreetmap.josm.tools.Predicate;
    1618import org.openstreetmap.josm.tools.Utils;
    1719
     
    319321     */
    320322    public void removeMembersFor(OsmPrimitive primitive) {
    321         if (primitive == null)
    322             return;
    323 
    324         boolean locked = writeLock();
    325         try {
    326             List<RelationMember> todelete = new ArrayList<RelationMember>();
    327             for (RelationMember member: members) {
    328                 if (member.getMember() == primitive) {
    329                     todelete.add(member);
    330                 }
    331             }
    332             List<RelationMember> members = getMembers();
    333             members.removeAll(todelete);
    334             setMembers(members);
    335         } finally {
    336             writeUnlock(locked);
    337         }
     323        removeMembersFor(Collections.singleton(primitive));
    338324    }
    339325
     
    356342
    357343    /**
     344     * Obtains all members with member.member == primitive
     345     * @param primitives the primitives to check for
     346     */
     347    public Collection<RelationMember> getMembersFor(final Collection<? extends OsmPrimitive> primitives) {
     348        return Utils.filter(getMembers(), new Predicate<RelationMember>() {
     349            @Override
     350            public boolean evaluate(RelationMember member) {
     351                return primitives.contains(member.getMember());
     352            }
     353        });
     354    }
     355
     356    /**
    358357     * removes all members with member.member == primitive
    359358     *
     
    367366        boolean locked = writeLock();
    368367        try {
    369             List<RelationMember> todelete = new ArrayList<RelationMember>();
    370             for (RelationMember member: members) {
    371                 if (primitives.contains(member.getMember())) {
    372                     todelete.add(member);
    373                 }
    374             }
    375368            List<RelationMember> members = getMembers();
    376             members.removeAll(todelete);
     369            members.removeAll(getMembersFor(primitives));
    377370            setMembers(members);
    378371        } finally {
Note: See TracChangeset for help on using the changeset viewer.