Ignore:
Timestamp:
2009-09-12T06:21:30+02:00 (15 years ago)
Author:
Gubaer
Message:

rewrite of MergeNodesAction
new: new conflict resolution dialog for conflicts during node merging. Can resolve conflicts in relation members too.

Location:
trunk/src/org/openstreetmap/josm/gui/conflict/tags
Files:
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/conflict/tags/CombinePrimitiveResolverDialog.java

    r2084 r2095  
    2626import org.openstreetmap.josm.command.ChangePropertyCommand;
    2727import org.openstreetmap.josm.command.Command;
     28import org.openstreetmap.josm.data.osm.Node;
    2829import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2930import org.openstreetmap.josm.data.osm.TagCollection;
     
    3435import org.openstreetmap.josm.tools.WindowGeometry;
    3536
    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 */
     65public class CombinePrimitiveResolverDialog extends JDialog {
     66
     67    static private CombinePrimitiveResolverDialog instance;
     68
     69    public static CombinePrimitiveResolverDialog getInstance() {
    4170        if (instance == null) {
    42             instance = new CombineWaysConflictResolverDialog(Main.parent);
     71            instance = new CombinePrimitiveResolverDialog(Main.parent);
    4372        }
    4473        return instance;
     
    5079    private boolean cancelled;
    5180    private JPanel pnlButtons;
    52     private Way targetWay;
    53 
    54 
    55 
    56     public Way getTargetWay() {
    57         return targetWay;
    58     }
    59 
    60     public void setTargetWay(Way targetWay) {
    61         this.targetWay = 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;
    6291        updateTitle();
    6392    }
    6493
    6594    protected void updateTitle() {
    66         if (targetWay == null) {
    67             setTitle(tr("Conflicts when combining ways"));
     95        if (targetPrimitive == null) {
     96            setTitle(tr("Conflicts when combining primitives"));
    6897            return;
    6998        }
    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        }
    76114    }
    77115
     
    113151    }
    114152
    115     public CombineWaysConflictResolverDialog(Component owner) {
     153    public CombinePrimitiveResolverDialog(Component owner) {
    116154        super(JOptionPane.getFrameForComponent(owner),true /* modal */);
    117155        build();
     
    143181    }
    144182
    145     public List<Command> buildResolutionCommands(Way targetWay) {
     183    public List<Command> buildResolutionCommands() {
    146184        List<Command> cmds = new LinkedList<Command>();
    147185
    148186        if (getTagConflictResolverModel().getNumDecisions() >0) {
    149187            TagCollection tc = getTagConflictResolverModel().getResolution();
    150             cmds.addAll(buildTagChangeCommand(targetWay, tc));
     188            cmds.addAll(buildTagChangeCommand(targetPrimitive, tc));
    151189        }
    152190
    153191        if (getRelationMemberConflictResolverModel().getNumDecisions() >0) {
    154             cmds.addAll(getRelationMemberConflictResolverModel().buildResolutionCommands(targetWay));
     192            cmds.addAll(getRelationMemberConflictResolverModel().buildResolutionCommands(targetPrimitive));
    155193        }
    156194
    157195        Command cmd = pnlRelationMemberConflictResolver.buildTagApplyCommands(
    158                 getRelationMemberConflictResolverModel().getModifiedRelations(targetWay)
     196                getRelationMemberConflictResolverModel().getModifiedRelations(targetPrimitive)
    159197        );
    160198        if (cmd != null) {
     
    242280                    )
    243281            ).applySafe(this);
     282            setCancelled(false);
    244283        } else {
    245284            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
  • trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverModel.java

    r2070 r2095  
    1818import org.openstreetmap.josm.data.osm.Relation;
    1919import org.openstreetmap.josm.data.osm.RelationMember;
    20 
     20import 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 */
    2129public class RelationMemberConflictResolverModel extends DefaultTableModel {
     30    /** the property name for the number conflicts managed by this model */
    2231    static public final String NUM_CONFLICTS_PROP = RelationMemberConflictResolverModel.class.getName() + ".numConflicts";
    2332
     33    /** the list of conflict decisions */
    2434    private List<RelationMemberConflictDecision> decisions;
     35    /** the collection of relations for which we manage conflicts */
    2536    private Collection<Relation> relations;
     37    /** the number of conflicts */
    2638    private int numConflicts;
    2739    private PropertyChangeSupport support;
    2840
    2941
     42    /**
     43     * Replies the current number of conflicts
     44     *
     45     * @return the current number of conflicts
     46     */
    3047    public int getNumConflicts() {
    3148        return numConflicts;
    3249    }
    3350
     51    /**
     52     * Updates the current number of conflicts from list of decisions and emits
     53     * a property change event if necessary.
     54     *
     55     */
    3456    protected void updateNumConflicts() {
    3557        int count = 0;
     
    7193        RelationMemberConflictDecision d = decisions.get(row);
    7294        switch(column) {
    73             case 0: /* relation */ return d.getRelation();
    74             case 1: /* pos */ return Integer.toString(d.getPos() + 1); // position in "user space" starting at 1
    75             case 2: /* role */ return d.getRole();
    76             case 3: /* original */ return d.getOriginalPrimitive();
    77             case 4: /* decision */ return d.getDecision();
     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();
    78100        }
    79101        return null;
     
    84106        RelationMemberConflictDecision d = decisions.get(row);
    85107        switch(column) {
    86             case 2: /* role */
    87                 d.setRole((String)value);
    88                 break;
    89             case 4: /* decision */
    90                 d.decide((RelationMemberConflictDecisionType)value);
    91                 refresh();
    92                 break;
     108        case 2: /* role */
     109            d.setRole((String)value);
     110            break;
     111        case 4: /* decision */
     112            d.decide((RelationMemberConflictDecisionType)value);
     113            refresh();
     114            break;
    93115        }
    94116        fireTableDataChanged();
    95117    }
    96118
     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     */
    97126    protected void populate(Relation relation, OsmPrimitive primitive) {
     127        decisions.clear();
    98128        for (int i =0; i<relation.getMembersCount();i++) {
    99129            if (relation.getMember(i).refersTo(primitive)) {
     
    103133    }
    104134
     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     */
    105142    public void populate(Collection<Relation> relations, Collection<? extends OsmPrimitive> memberPrimitives) {
    106143        decisions.clear();
     144        relations = relations == null ? new LinkedList<Relation>() : relations;
     145        memberPrimitives = memberPrimitives == null ? new LinkedList<OsmPrimitive>() : memberPrimitives;
    107146        for (Relation r : relations) {
    108147            for (OsmPrimitive p: memberPrimitives) {
     
    114153    }
    115154
     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     */
    116182    public RelationMemberConflictDecision getDecision(int row) {
    117183        return decisions.get(row);
    118184    }
    119185
     186    /**
     187     * Replies the number of decisions managed by this model
     188     *
     189     * @return the number of decisions managed by this model
     190     */
    120191    public int getNumDecisions() {
    121192        return  getRowCount();
    122193    }
    123194
     195    /**
     196     * Refreshes the model state. Invoke this method to trigger necessary change
     197     * events after an update of the model data.
     198     *
     199     */
    124200    public void refresh() {
    125201        updateNumConflicts();
     
    127203    }
    128204
     205    /**
     206     * Apply a role to all member managed by this model.
     207     *
     208     * @param role the role. Empty string assumed if null.
     209     */
    129210    public void applyRole(String role) {
    130211        role = role == null ? "" : role;
     
    154235            } else {
    155236                switch(decision.getDecision()) {
    156                     case REPLACE:
    157                         rmNew = new RelationMember(decision.getRole(),newPrimitive);
    158                         modifiedRelation.addMember(rmNew);
    159                         isChanged |= ! rm.equals(rmNew);
    160                         break;
    161                     case REMOVE:
    162                         isChanged = true;
    163                         // do nothing
    164                         break;
    165                     case UNDECIDED:
    166                         // FIXME: this is an error
    167                         break;
     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;
    168249                }
    169250            }
     
    174255    }
    175256
     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     */
    176264    public List<Command> buildResolutionCommands(OsmPrimitive newPrimitive) {
    177265        List<Command> command = new LinkedList<Command>();
     
    192280            }
    193281            switch(decision.getDecision()) {
    194                 case REMOVE: return true;
    195                 case REPLACE:
    196                     if (!relation.getMember(i).getRole().equals(decision.getRole()))
    197                         return true;
    198                     if (relation.getMember(i).getMember() != newPrimitive)
    199                         return true;
    200                 case UNDECIDED:
    201                     // FIXME: handle error
     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
    202290            }
    203291        }
     
    205293    }
    206294
     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     */
    207305    public Set<Relation> getModifiedRelations(OsmPrimitive newPrimitive) {
    208306        HashSet<Relation> ret = new HashSet<Relation>();
Note: See TracChangeset for help on using the changeset viewer.