Changeset 3362 in josm


Ignore:
Timestamp:
Jul 3, 2010 10:08:57 PM (3 years ago)
Author:
stoecker
Message:

fix #5182 - Conflict system simplification - patch by Upliner

Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/command/PurgePrimitivesCommand.java

    r3335 r3362  
    4040 * 
    4141 */ 
     42@Deprecated 
    4243public class PurgePrimitivesCommand extends ConflictResolveCommand{ 
    4344 
  • trunk/src/org/openstreetmap/josm/command/UndeletePrimitivesCommand.java

    r3262 r3362  
    2626 * 
    2727 */ 
     28@Deprecated 
    2829public class UndeletePrimitivesCommand extends ConflictResolveCommand { 
    2930    //static private final Logger logger = Logger.getLogger(UndeletePrimitivesCommand.class.getName()); 
  • trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java

    r3262 r3362  
    5151        super.executeCommand(); 
    5252        if (!conflict.getMy().isNew()) { 
     53            long myVersion = conflict.getMy().getVersion(); 
     54            long theirVersion = conflict.getTheir().getVersion(); 
    5355            conflict.getMy().setOsmId( 
    5456                    conflict.getMy().getId(), 
    55                     (int)Math.max(conflict.getMy().getVersion(), conflict.getTheir().getVersion()) 
     57                    (int)Math.max(myVersion, theirVersion) 
    5658            ); 
     59            // update visiblity state 
     60            if (theirVersion >= myVersion) { 
     61                conflict.getMy().setVisible(conflict.getTheir().isVisible()); 
     62            } 
    5763        } 
    5864        getLayer().getConflicts().remove(conflict); 
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r3348 r3362  
    997997        } 
    998998    } 
     999 
     1000    /** 
     1001     * Marks all "invisible" objects as deleted. These objects should be always marked as 
     1002     * deleted when downloaded from the server. They can be undeleted later if necessary. 
     1003     *  
     1004     */ 
     1005    public void deleteInvisible() { 
     1006        for (OsmPrimitive primitive:allPrimitives) { 
     1007            if (!primitive.isVisible()) { 
     1008                primitive.setDeleted(true); 
     1009            } 
     1010        } 
     1011    } 
    9991012} 
  • trunk/src/org/openstreetmap/josm/data/osm/DataSetMerger.java

    r3336 r3362  
    1111import java.util.Map; 
    1212import java.util.Set; 
    13 import java.util.logging.Logger; 
    1413 
    1514import org.openstreetmap.josm.data.conflict.Conflict; 
     
    2322 */ 
    2423public class DataSetMerger { 
    25     private static Logger logger = Logger.getLogger(DataSetMerger.class.getName()); 
    2624 
    2725    /** the collection of conflicts created during merging */ 
     
    244242            // target.version > source.version => keep target version 
    245243            return true; 
    246         if (! target.isVisible() && source.isVisible() && target.getVersion() == source.getVersion()) { 
    247             // should not happen 
    248             conflicts.add(target,source); 
    249         } else if (target.isVisible() && ! source.isVisible()) { 
    250             // this is always a conflict because the user has to decide whether 
    251             // he wants to create a clone of its target primitive or whether he 
    252             // wants to purge the target from the local dataset. He can't keep it unchanged 
    253             // because it was deleted on the server. 
    254             // 
    255             conflicts.add(target,source); 
    256         } else if (target.isIncomplete() && !source.isIncomplete()) { 
     244 
     245        if (target.isIncomplete() && !source.isIncomplete()) { 
    257246            // target is incomplete, source completes it 
    258247            // => merge source into target 
  • trunk/src/org/openstreetmap/josm/gui/conflict/pair/ConflictResolver.java

    r3083 r3362  
    2626import org.openstreetmap.josm.gui.conflict.pair.nodes.NodeListMergeModel; 
    2727import org.openstreetmap.josm.gui.conflict.pair.nodes.NodeListMerger; 
    28 import org.openstreetmap.josm.gui.conflict.pair.properties.OperationCancelledException; 
    2928import org.openstreetmap.josm.gui.conflict.pair.properties.PropertiesMergeModel; 
    3029import org.openstreetmap.josm.gui.conflict.pair.properties.PropertiesMerger; 
     
    235234        this.conflict = conflict; 
    236235        propertiesMerger.populate(conflict); 
    237         if (propertiesMerger.getModel().hasVisibleStateConflict()) { 
    238             tabbedPane.setEnabledAt(1, false); 
    239             tabbedPane.setEnabledAt(2, false); 
    240             tabbedPane.setEnabledAt(3, false); 
    241             return; 
    242         } 
     236 
    243237        tabbedPane.setEnabledAt(0, true); 
    244238        tagMerger.populate(conflict); 
     
    270264     * @return the resolution command 
    271265     */ 
    272     public Command buildResolveCommand() throws OperationCancelledException { 
     266    public Command buildResolveCommand() { 
    273267        ArrayList<Command> commands = new ArrayList<Command>(); 
    274         if (propertiesMerger.getModel().hasVisibleStateConflict()) { 
    275             if (propertiesMerger.getModel().isDecidedVisibleState()) { 
    276                 commands.addAll(propertiesMerger.getModel().buildResolveCommand(conflict)); 
    277             } 
    278         } else { 
    279             if (tagMerger.getModel().getNumResolvedConflicts() > 0) { 
    280                 commands.add(tagMerger.getModel().buildResolveCommand(conflict)); 
    281             } 
    282             commands.addAll(propertiesMerger.getModel().buildResolveCommand(conflict)); 
    283             if (my instanceof Way && nodeListMerger.getModel().isFrozen()) { 
    284                 NodeListMergeModel model  =(NodeListMergeModel)nodeListMerger.getModel(); 
    285                 commands.add(model.buildResolveCommand(conflict)); 
    286             } else if (my instanceof Relation && relationMemberMerger.getModel().isFrozen()) { 
    287                 RelationMemberListMergeModel model  =(RelationMemberListMergeModel)relationMemberMerger.getModel(); 
    288                 commands.add(model.buildResolveCommand((Relation)my, (Relation)their)); 
    289             } 
    290             if (isResolvedCompletely()) { 
    291                 commands.add(new VersionConflictResolveCommand(conflict)); 
    292                 commands.add(new ModifiedConflictResolveCommand(conflict)); 
    293             } 
     268 
     269        if (tagMerger.getModel().getNumResolvedConflicts() > 0) { 
     270            commands.add(tagMerger.getModel().buildResolveCommand(conflict)); 
     271        } 
     272        commands.addAll(propertiesMerger.getModel().buildResolveCommand(conflict)); 
     273        if (my instanceof Way && nodeListMerger.getModel().isFrozen()) { 
     274            NodeListMergeModel model = (NodeListMergeModel) nodeListMerger.getModel(); 
     275            commands.add(model.buildResolveCommand(conflict)); 
     276        } else if (my instanceof Relation && relationMemberMerger.getModel().isFrozen()) { 
     277            RelationMemberListMergeModel model = (RelationMemberListMergeModel) relationMemberMerger.getModel(); 
     278            commands.add(model.buildResolveCommand((Relation) my, (Relation) their)); 
     279        } 
     280        if (isResolvedCompletely()) { 
     281            commands.add(new VersionConflictResolveCommand(conflict)); 
     282            commands.add(new ModifiedConflictResolveCommand(conflict)); 
    294283        } 
    295284        return new SequenceCommand(tr("Conflict Resolution"), commands); 
  • trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/PropertiesMergeModel.java

    r3083 r3362  
    33 
    44import static org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType.UNDECIDED; 
    5 import static org.openstreetmap.josm.tools.I18n.tr; 
    6 import static org.openstreetmap.josm.tools.I18n.trn; 
    75 
    86import java.beans.PropertyChangeListener; 
     
    108import java.util.ArrayList; 
    119import java.util.Collections; 
    12 import java.util.HashMap; 
    1310import java.util.List; 
    1411import java.util.Observable; 
    1512 
    16 import javax.swing.JOptionPane; 
    17  
    18 import org.openstreetmap.josm.Main; 
    1913import org.openstreetmap.josm.command.Command; 
    2014import org.openstreetmap.josm.command.CoordinateConflictResolveCommand; 
    2115import org.openstreetmap.josm.command.DeletedStateConflictResolveCommand; 
    22 import org.openstreetmap.josm.command.PurgePrimitivesCommand; 
    23 import org.openstreetmap.josm.command.UndeletePrimitivesCommand; 
    2416import org.openstreetmap.josm.data.conflict.Conflict; 
    2517import org.openstreetmap.josm.data.coor.LatLon; 
    26 import org.openstreetmap.josm.data.osm.DataSet; 
    2718import org.openstreetmap.josm.data.osm.Node; 
    2819import org.openstreetmap.josm.data.osm.OsmPrimitive; 
    29 import org.openstreetmap.josm.data.osm.Relation; 
    30 import org.openstreetmap.josm.data.osm.RelationMember; 
    31 import org.openstreetmap.josm.data.osm.Way; 
    3220import org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType; 
    33 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 
    34 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 
    35 import org.openstreetmap.josm.io.OsmTransferException; 
    3621import org.openstreetmap.josm.tools.CheckParameterUtil; 
    3722 
     
    6550    private boolean myDeletedState; 
    6651    private boolean theirDeletedState; 
    67     private boolean myVisibleState; 
    68     private boolean theirVisibleState; 
    6952    private List<OsmPrimitive> myReferrers; 
    7053    private List<OsmPrimitive> theirReferrers; 
    7154    private MergeDecisionType deletedMergeDecision; 
    72     private MergeDecisionType visibleMergeDecision; 
    7355    private final PropertyChangeSupport support; 
    7456    private boolean resolvedCompletely; 
     
    118100 
    119101    /** 
    120      * replies true if there is a  conflict in the visible state and if this conflict is 
    121      * resolved 
    122      * 
    123      * @return true if there is a conflict in the visible state and if this conflict is 
    124      * resolved; false, otherwise 
    125      */ 
    126     public boolean isDecidedVisibleState() { 
    127         return ! visibleMergeDecision.equals(UNDECIDED); 
    128     } 
    129  
    130     /** 
    131102     * replies true if the current decision for the coordinate conflict is <code>decision</code> 
    132103     * 
     
    148119    } 
    149120 
    150     /** 
    151      * replies true if the current decision for the visible state conflict is <code>decision</code> 
    152      * 
    153      * @return true if the current decision for the visible state conflict is <code>decision</code>; 
    154      *  false, otherwise 
    155      */ 
    156     public boolean isVisibleStateDecision(MergeDecisionType decision) { 
    157         return visibleMergeDecision.equals(decision); 
    158     } 
    159121    /** 
    160122     * populates the model with the differences between my and their version 
     
    177139        theirDeletedState = their.isDeleted(); 
    178140 
    179         myVisibleState = my.isVisible(); 
    180         theirVisibleState = their.isVisible(); 
    181  
    182141        myReferrers = my.getDataSet() == null?Collections.<OsmPrimitive>emptyList():my.getReferrers(); 
    183142        theirReferrers = their.getDataSet() == null?Collections.<OsmPrimitive>emptyList():their.getReferrers(); 
     
    185144        coordMergeDecision = UNDECIDED; 
    186145        deletedMergeDecision = UNDECIDED; 
    187         visibleMergeDecision = UNDECIDED; 
    188146        setChanged(); 
    189147        notifyObservers(); 
     
    265223 
    266224    /** 
    267      * replies my visible state, 
    268      * @return my visible state 
    269      */ 
    270     public Boolean getMyVisibleState() { 
    271         return myVisibleState; 
    272     } 
    273  
    274     /** 
    275      * replies their visible state, 
    276      * @return their visible state 
    277      */ 
    278     public  Boolean getTheirVisibleState() { 
    279         return theirVisibleState; 
    280     } 
    281  
    282     /** 
    283225     * returns my referrers, 
    284226     * @return my referrers 
     
    294236    public List<OsmPrimitive> getTheirReferrers() { 
    295237        return theirReferrers; 
    296     } 
    297  
    298     /** 
    299      * replies the merged visible state; null, if the merge decision is 
    300      * {@see MergeDecisionType#UNDECIDED}. 
    301      * 
    302      * @return the merged visible state 
    303      */ 
    304     public Boolean getMergedVisibleState() { 
    305         switch(visibleMergeDecision) { 
    306         case KEEP_MINE: return myVisibleState; 
    307         case KEEP_THEIR: return theirVisibleState; 
    308         case UNDECIDED: return null; 
    309         } 
    310         // should not happen 
    311         return null; 
    312238    } 
    313239 
     
    346272 
    347273    /** 
    348      * decides the conflict between two visible states 
    349      * @param decision the decision (must not be null) 
    350      * 
    351      * @throws IllegalArgumentException thrown, if decision is null 
    352      */ 
    353     public void decideVisibleStateConflict(MergeDecisionType decision) throws IllegalArgumentException { 
    354         CheckParameterUtil.ensureParameterNotNull(decision, "decision"); 
    355         this.visibleMergeDecision = decision; 
    356         setChanged(); 
    357         notifyObservers(); 
    358         fireCompletelyResolved(); 
    359     } 
    360  
    361     /** 
    362274     * replies true if my and their primitive have a conflict between 
    363275     * their coordinate values 
     
    385297 
    386298    /** 
    387      * replies true if my and their primitive have a conflict between 
    388      * their visible states 
    389      * 
    390      * @return true if my and their primitive have a conflict between 
    391      * their visible states 
    392      */ 
    393     public boolean hasVisibleStateConflict() { 
    394         return myVisibleState != theirVisibleState; 
    395     } 
    396  
    397     /** 
    398299     * replies true if all conflict in this model are resolved 
    399300     * 
     
    408309            ret = ret && ! deletedMergeDecision.equals(UNDECIDED); 
    409310        } 
    410         if (hasVisibleStateConflict()) { 
    411             ret = ret && ! visibleMergeDecision.equals(UNDECIDED); 
    412         } 
    413311        return ret; 
    414312    } 
     
    421319     * @return the list of commands 
    422320     */ 
    423     public List<Command> buildResolveCommand(Conflict<? extends OsmPrimitive> conflict) throws OperationCancelledException{ 
    424         OsmPrimitive my = conflict.getMy(); 
     321    public List<Command> buildResolveCommand(Conflict<? extends OsmPrimitive> conflict) { 
    425322        List<Command> cmds = new ArrayList<Command>(); 
    426         if (hasVisibleStateConflict() && isDecidedVisibleState()) { 
    427             if (isVisibleStateDecision(MergeDecisionType.KEEP_MINE)) { 
    428                 try { 
    429                     UndeletePrimitivesCommand cmd = createUndeletePrimitiveCommand(my); 
    430                     if (cmd == null) 
    431                         throw new OperationCancelledException(); 
    432                     cmds.add(cmd); 
    433                 } catch(OsmTransferException e) { 
    434                     handleExceptionWhileBuildingCommand(e); 
    435                     throw new OperationCancelledException(e); 
    436                 } 
    437             } else if (isVisibleStateDecision(MergeDecisionType.KEEP_THEIR)) { 
    438                 cmds.add(new PurgePrimitivesCommand(my)); 
    439             } 
    440         } 
    441323        if (hasCoordConflict() && isDecidedCoord()) { 
    442324            cmds.add(new CoordinateConflictResolveCommand(conflict, coordMergeDecision)); 
     
    452334    } 
    453335 
    454     /** 
    455      * 
    456      * @param id 
    457      */ 
    458     protected void handleExceptionWhileBuildingCommand(Exception e) { 
    459         e.printStackTrace(); 
    460         String msg = e.getMessage() != null ? e.getMessage() : e.toString(); 
    461         msg = msg.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;"); 
    462         JOptionPane.showMessageDialog( 
    463                 Main.parent, 
    464                 tr("<html>An error occurred while communicating with the server<br>" 
    465                         + "Details: {0}</html>", 
    466                         msg 
    467                 ), 
    468                 tr("Communication with server failed"), 
    469                 JOptionPane.ERROR_MESSAGE 
    470         ); 
    471     } 
    472  
    473     /** 
    474      * User has decided to keep his local version of a primitive which had been deleted 
    475      * on the server 
    476      * 
    477      * @param id the primitive id 
    478      */ 
    479     protected UndeletePrimitivesCommand createUndeletePrimitiveCommand(OsmPrimitive my) throws OsmTransferException { 
    480         if (my instanceof Node) 
    481             return createUndeleteNodeCommand((Node)my); 
    482         else if (my instanceof Way) 
    483             return createUndeleteWayCommand((Way)my); 
    484         else if (my instanceof Relation) 
    485             return createUndeleteRelationCommand((Relation)my); 
    486         return null; 
    487     } 
    488     /** 
    489      * Undelete a node which is already deleted on the server. The API 
    490      * doesn't offer a call for "undeleting" a node. We therefore create 
    491      * a clone of the node which we flag as new. On the next upload the 
    492      * server will assign the node a new id. 
    493      * 
    494      * @param node the node to undelete 
    495      */ 
    496     protected UndeletePrimitivesCommand  createUndeleteNodeCommand(Node node) { 
    497         return new UndeletePrimitivesCommand(node); 
    498     } 
    499  
    500     /** 
    501      * displays a confirmation message. The user has to confirm that additional dependent 
    502      * nodes should be undeleted too. 
    503      * 
    504      * @param way  the way 
    505      * @param dependent a list of dependent nodes which have to be undelete too 
    506      * @return true, if the user confirms; false, otherwise 
    507      */ 
    508     protected boolean confirmUndeleteDependentPrimitives(Way way, ArrayList<OsmPrimitive> dependent) { 
    509         String [] options = { 
    510                 tr("Yes, undelete them too"), 
    511                 tr("No, cancel operation") 
    512         }; 
    513         int ret = JOptionPane.showOptionDialog( 
    514                 Main.parent, 
    515                 "<html>" + trn("There is {0} additional node used by way {1}<br>" 
    516                         + "which is deleted on the server." 
    517                         + "<br><br>" 
    518                         + "Do you want to undelete this node too?", 
    519                         "There are {0} additional nodes used by way {1}<br>" 
    520                         + "which are deleted on the server." 
    521                         + "<br><br>" 
    522                         + "Do you want to undelete these nodes too?", 
    523                         dependent.size(), dependent.size(), way.getId()) 
    524                         + "</html>", 
    525                         tr("Undelete additional nodes?"), 
    526                         JOptionPane.YES_NO_OPTION, 
    527                         JOptionPane.QUESTION_MESSAGE, 
    528                         null, 
    529                         options, 
    530                         options[0] 
    531         ); 
    532  
    533         switch(ret) { 
    534         case JOptionPane.CLOSED_OPTION: return false; 
    535         case JOptionPane.YES_OPTION: return true; 
    536         case JOptionPane.NO_OPTION: return false; 
    537         } 
    538         return false; 
    539  
    540     } 
    541  
    542     protected boolean confirmUndeleteDependentPrimitives(Relation r, ArrayList<OsmPrimitive> dependent) { 
    543         String [] options = { 
    544                 tr("Yes, undelete them too"), 
    545                 tr("No, cancel operation") 
    546         }; 
    547         int ret = JOptionPane.showOptionDialog( 
    548                 Main.parent, 
    549                 "<html>" + trn("There is {0} additional primitive referred to by relation {1}<br>" 
    550                         + "which is deleted on the server." 
    551                         + "<br><br>" 
    552                         + "Do you want to undelete this too?", 
    553                         "There are {0} additional primitives referred to by relation {1}<br>" 
    554                         + "which are deleted on the server." 
    555                         + "<br><br>" 
    556                         + "Do you want to undelete these too?", 
    557                         dependent.size(), dependent.size(), r.getId()) 
    558                         + "</html>", 
    559                         tr("Undelete dependent primitives?"), 
    560                         JOptionPane.YES_NO_OPTION, 
    561                         JOptionPane.QUESTION_MESSAGE, 
    562                         null, 
    563                         options, 
    564                         options[0] 
    565         ); 
    566  
    567         switch(ret) { 
    568         case JOptionPane.CLOSED_OPTION: return false; 
    569         case JOptionPane.YES_OPTION: return true; 
    570         case JOptionPane.NO_OPTION: return false; 
    571         } 
    572         return false; 
    573  
    574     } 
    575  
    576     /** 
    577      * Creates the undelete command for a way which is already deleted on the server. 
    578      * 
    579      * This method also checks whether there are additional nodes referred to by 
    580      * this way which are deleted on the server too. 
    581      * 
    582      * @param way the way to undelete 
    583      * @return the undelete command 
    584      * @see #createUndeleteNodeCommand(Node) 
    585      */ 
    586     protected UndeletePrimitivesCommand createUndeleteWayCommand(final Way way) throws OsmTransferException { 
    587  
    588         HashMap<Long,OsmPrimitive> candidates = new HashMap<Long,OsmPrimitive>(); 
    589         for (Node n : way.getNodes()) { 
    590             if (!n.isNew() && !candidates.values().contains(n)) { 
    591                 candidates.put(n.getId(), n); 
    592             } 
    593         } 
    594         MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader(); 
    595         reader.append(candidates.values()); 
    596         DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE); 
    597  
    598         ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>(); 
    599         for (OsmPrimitive their : ds.allPrimitives()) { 
    600             if (candidates.keySet().contains(their.getId()) && ! their.isVisible()) { 
    601                 toDelete.add(candidates.get(their.getId())); 
    602             } 
    603         } 
    604         if (!toDelete.isEmpty()) { 
    605             if (! confirmUndeleteDependentPrimitives(way, toDelete)) 
    606                 // FIXME: throw exception ? 
    607                 return null; 
    608         } 
    609         toDelete.add(way); 
    610         return new UndeletePrimitivesCommand(toDelete); 
    611     } 
    612  
    613     /** 
    614      * Creates an undelete command for a relation which is already deleted on the server. 
    615      * 
    616      * This method  checks whether there are additional primitives referred to by 
    617      * this relation which are already deleted on the server. 
    618      * 
    619      * @param r the relation 
    620      * @return the undelete command 
    621      * @see #createUndeleteNodeCommand(Node) 
    622      */ 
    623     protected UndeletePrimitivesCommand createUndeleteRelationCommand(final Relation r) throws OsmTransferException { 
    624  
    625         HashMap<Long,OsmPrimitive> candidates = new HashMap<Long, OsmPrimitive>(); 
    626         for (RelationMember m : r.getMembers()) { 
    627             if (!m.getMember().isNew() && !candidates.values().contains(m.getMember())) { 
    628                 candidates.put(m.getMember().getId(), m.getMember()); 
    629             } 
    630         } 
    631  
    632         MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader(); 
    633         reader.append(candidates.values()); 
    634         DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE); 
    635  
    636         ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>(); 
    637         for (OsmPrimitive their : ds.allPrimitives()) { 
    638             if (candidates.keySet().contains(their.getId()) && ! their.isVisible()) { 
    639                 toDelete.add(candidates.get(their.getId())); 
    640             } 
    641         } 
    642         if (!toDelete.isEmpty()) { 
    643             if (! confirmUndeleteDependentPrimitives(r, toDelete)) 
    644                 // FIXME: throw exception ? 
    645                 return null; 
    646         } 
    647         toDelete.add(r); 
    648         return new UndeletePrimitivesCommand(toDelete); 
    649     } 
    650  
    651336} 
  • trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/PropertiesMerger.java

    r3218 r3362  
    1919import javax.swing.JButton; 
    2020import javax.swing.JLabel; 
    21 import javax.swing.JOptionPane; 
    2221import javax.swing.JPanel; 
    2322 
     
    5453    private JLabel lblTheirDeletedState; 
    5554 
    56     private JLabel lblMyVisibleState; 
    57     private JLabel lblMergedVisibleState; 
    58     private JLabel lblTheirVisibleState; 
    59  
    6055    private JLabel lblMyReferrers; 
    6156    private JLabel lblTheirReferrers; 
     
    251246    } 
    252247 
    253     protected void buildVisibleStateRows() { 
    254         GridBagConstraints gc = new GridBagConstraints(); 
    255  
    256         gc.gridx = 0; 
    257         gc.gridy = 5; 
    258         gc.gridwidth = 1; 
    259         gc.gridheight = 1; 
    260         gc.fill = GridBagConstraints.BOTH; 
    261         gc.anchor = GridBagConstraints.LINE_START; 
    262         gc.weightx = 0.0; 
    263         gc.weighty = 0.0; 
    264         gc.insets = new Insets(0,5,0,5); 
    265         add(new JLabel(tr("Visible State:")), gc); 
    266  
    267         gc.gridx = 1; 
    268         gc.gridy = 5; 
    269         gc.fill = GridBagConstraints.BOTH; 
    270         gc.anchor = GridBagConstraints.CENTER; 
    271         gc.weightx = 0.33; 
    272         gc.weighty = 0.0; 
    273         add(lblMyVisibleState = buildValueLabel("label.myvisiblestate"), gc); 
    274  
    275         gc.gridx = 2; 
    276         gc.gridy = 5; 
    277         gc.fill = GridBagConstraints.NONE; 
    278         gc.anchor = GridBagConstraints.CENTER; 
    279         gc.weightx = 0.0; 
    280         gc.weighty = 0.0; 
    281         KeepMyVisibleStateAction actKeepMyVisibleState = new KeepMyVisibleStateAction(); 
    282         model.addObserver(actKeepMyVisibleState); 
    283         JButton btnKeepMyVisibleState = new JButton(actKeepMyVisibleState); 
    284         btnKeepMyVisibleState.setName("button.keepmyvisiblestate"); 
    285         add(btnKeepMyVisibleState, gc); 
    286  
    287         gc.gridx = 3; 
    288         gc.gridy = 5; 
    289         gc.fill = GridBagConstraints.BOTH; 
    290         gc.anchor = GridBagConstraints.CENTER; 
    291         gc.weightx = 0.33; 
    292         gc.weighty = 0.0; 
    293         add(lblMergedVisibleState = buildValueLabel("label.mergedvisiblestate"), gc); 
    294  
    295         gc.gridx = 4; 
    296         gc.gridy = 5; 
    297         gc.fill = GridBagConstraints.NONE; 
    298         gc.anchor = GridBagConstraints.CENTER; 
    299         gc.weightx = 0.0; 
    300         gc.weighty = 0.0; 
    301         KeepTheirVisibleStateAction actKeepTheirVisibleState = new KeepTheirVisibleStateAction(); 
    302         model.addObserver(actKeepTheirVisibleState); 
    303         JButton btnKeepTheirVisibleState = new JButton(actKeepTheirVisibleState); 
    304         btnKeepTheirVisibleState.setName("button.keeptheirvisiblestate"); 
    305         add(btnKeepTheirVisibleState, gc); 
    306  
    307         gc.gridx = 5; 
    308         gc.gridy = 5; 
    309         gc.fill = GridBagConstraints.BOTH; 
    310         gc.anchor = GridBagConstraints.CENTER; 
    311         gc.weightx = 0.33; 
    312         gc.weighty = 0.0; 
    313         add(lblTheirVisibleState = buildValueLabel("label.theirvisiblestate"), gc); 
    314  
    315         // --------------------------------------------------- 
    316         gc.gridx = 3; 
    317         gc.gridy = 6; 
    318         gc.fill = GridBagConstraints.NONE; 
    319         gc.anchor = GridBagConstraints.CENTER; 
    320         gc.weightx = 0.0; 
    321         gc.weighty = 0.0; 
    322         UndecideVisibleStateConflictAction actUndecideVisibleState = new UndecideVisibleStateConflictAction(); 
    323         model.addObserver(actUndecideVisibleState); 
    324         JButton btnUndecideVisibleState = new JButton(actUndecideVisibleState); 
    325         btnUndecideVisibleState.setName("button.undecidevisiblestate"); 
    326         add(btnUndecideVisibleState, gc); 
    327     } 
    328  
    329248    protected void buildReferrersRow() { 
    330249        GridBagConstraints gc = new GridBagConstraints(); 
     
    363282        buildCoordinateConflictRows(); 
    364283        buildDeletedStateConflictRows(); 
    365         buildVisibleStateRows(); 
    366284        buildReferrersRow(); 
    367285    } 
     
    392310        else 
    393311            return tr("not deleted"); 
    394     } 
    395  
    396     public String visibleStateToString(Boolean visible) { 
    397         if (visible == null) 
    398             return tr("(none)"); 
    399         if (visible) 
    400             return tr("visible (on the server)"); 
    401         else 
    402             return tr("not visible (on the server)"); 
    403     } 
    404  
    405     public String visibleStateToStringMerged(Boolean visible) { 
    406         if (visible == null) 
    407             return tr("(none)"); 
    408         if (visible) 
    409             return tr("Keep a clone of the local version"); 
    410         else 
    411             return tr("Physically delete from local dataset"); 
    412312    } 
    413313 
     
    478378    } 
    479379 
    480     protected void updateVisibleState() { 
    481         lblMyVisibleState.setText(visibleStateToString(model.getMyVisibleState())); 
    482         lblMergedVisibleState.setText(visibleStateToStringMerged(model.getMergedVisibleState())); 
    483         lblTheirVisibleState.setText(visibleStateToString(model.getTheirVisibleState())); 
    484  
    485         if (! model.hasVisibleStateConflict()) { 
    486             lblMyVisibleState.setBackground(BGCOLOR_NO_CONFLICT); 
    487             lblMergedVisibleState.setBackground(BGCOLOR_NO_CONFLICT); 
    488             lblTheirVisibleState.setBackground(BGCOLOR_NO_CONFLICT); 
    489         } else { 
    490             if (!model.isDecidedVisibleState()) { 
    491                 lblMyVisibleState.setBackground(BGCOLOR_UNDECIDED); 
    492                 lblMergedVisibleState.setBackground(BGCOLOR_NO_CONFLICT); 
    493                 lblTheirVisibleState.setBackground(BGCOLOR_UNDECIDED); 
    494             } else { 
    495                 lblMyVisibleState.setBackground( 
    496                         model.isVisibleStateDecision(MergeDecisionType.KEEP_MINE) 
    497                         ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT 
    498                 ); 
    499                 lblMergedVisibleState.setBackground(BGCOLOR_DECIDED); 
    500                 lblTheirVisibleState.setBackground( 
    501                         model.isVisibleStateDecision(MergeDecisionType.KEEP_THEIR) 
    502                         ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT 
    503                 ); 
    504             } 
    505         } 
    506     } 
    507  
    508380    protected void updateReferrers() { 
    509381        lblMyReferrers.setText(referrersToString(model.getMyReferrers())); 
     
    516388        updateCoordinates(); 
    517389        updateDeletedState(); 
    518         updateVisibleState(); 
    519390        updateReferrers(); 
    520391    } 
     
    611482        public void update(Observable o, Object arg) { 
    612483            setEnabled(model.hasDeletedStateConflict() && model.isDecidedDeletedState()); 
    613         } 
    614     } 
    615  
    616     class KeepMyVisibleStateAction extends AbstractAction implements Observer { 
    617         public KeepMyVisibleStateAction() { 
    618             putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeepmine")); 
    619             putValue(Action.SHORT_DESCRIPTION, tr("Keep my visible state")); 
    620         } 
    621  
    622         public void actionPerformed(ActionEvent e) { 
    623             if (confirmKeepMine()) { 
    624                 model.decideVisibleStateConflict(MergeDecisionType.KEEP_MINE); 
    625             } 
    626         } 
    627  
    628         public void update(Observable o, Object arg) { 
    629             setEnabled(model.hasVisibleStateConflict() && ! model.isDecidedVisibleState()); 
    630         } 
    631  
    632         protected boolean confirmKeepMine() { 
    633             String [] options = { 
    634                     tr("Yes, reset the id"), 
    635                     tr("No, abort") 
    636             }; 
    637             int ret = JOptionPane.showOptionDialog( 
    638                     null, 
    639                     tr("<html>To keep your local version, JOSM<br>" 
    640                             + "has to reset the id of primitive {0} to 0.<br>" 
    641                             + "On the next upload the server will assign<br>" 
    642                             + "it a new id.<br>" 
    643                             + "Do you agree?</html>", 
    644                             model.getMyPrimitive().getId() 
    645                     ), 
    646                     tr("Reset id to 0"), 
    647                     JOptionPane.YES_NO_OPTION, 
    648                     JOptionPane.QUESTION_MESSAGE, 
    649                     null, 
    650                     options, 
    651                     options[1] 
    652             ); 
    653             return ret == JOptionPane.YES_OPTION; 
    654         } 
    655     } 
    656  
    657     class KeepTheirVisibleStateAction extends AbstractAction implements Observer { 
    658         public KeepTheirVisibleStateAction() { 
    659             putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeeptheir")); 
    660             putValue(Action.SHORT_DESCRIPTION, tr("Keep their visible state")); 
    661         } 
    662  
    663         public void actionPerformed(ActionEvent e) { 
    664             if (confirmKeepTheir()){ 
    665                 model.decideVisibleStateConflict(MergeDecisionType.KEEP_THEIR); 
    666             } 
    667         } 
    668  
    669         public void update(Observable o, Object arg) { 
    670             setEnabled(model.hasVisibleStateConflict() && ! model.isDecidedVisibleState()); 
    671         } 
    672  
    673         protected boolean confirmKeepTheir() { 
    674             String [] options = { 
    675                     tr("Yes, purge it"), 
    676                     tr("No, abort") 
    677             }; 
    678             int ret = JOptionPane.showOptionDialog( 
    679                     null, 
    680                     tr("<html>JOSM will have to remove your local primitive with id {0}<br>" 
    681                             + "from the dataset.<br>" 
    682                             + "Do you agree?</html>", 
    683                             model.getMyPrimitive().getId() 
    684                     ), 
    685                     tr("Remove from dataset"), 
    686                     JOptionPane.YES_NO_OPTION, 
    687                     JOptionPane.QUESTION_MESSAGE, 
    688                     null, 
    689                     options, 
    690                     options[1] 
    691             ); 
    692             return ret == JOptionPane.YES_OPTION; 
    693         } 
    694     } 
    695  
    696     class UndecideVisibleStateConflictAction extends AbstractAction implements Observer { 
    697         public UndecideVisibleStateConflictAction() { 
    698             putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagundecide")); 
    699             putValue(Action.SHORT_DESCRIPTION, tr("Undecide conflict between visible state")); 
    700         } 
    701  
    702         public void actionPerformed(ActionEvent e) { 
    703             model.decideVisibleStateConflict(MergeDecisionType.UNDECIDED); 
    704         } 
    705  
    706         public void update(Observable o, Object arg) { 
    707             setEnabled(model.hasVisibleStateConflict() && model.isDecidedVisibleState()); 
    708484        } 
    709485    } 
  • trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java

    r3083 r3362  
    2828import org.openstreetmap.josm.gui.DefaultNameFormatter; 
    2929import org.openstreetmap.josm.gui.conflict.pair.ConflictResolver; 
    30 import org.openstreetmap.josm.gui.conflict.pair.properties.OperationCancelledException; 
    3130import org.openstreetmap.josm.gui.help.HelpBrowser; 
    3231import org.openstreetmap.josm.gui.help.HelpUtil; 
     
    262261                } 
    263262            } 
    264             try { 
    265                 Command cmd = resolver.buildResolveCommand(); 
    266                 Main.main.undoRedo.add(cmd); 
    267                 closeDialog(); 
    268             } catch(OperationCancelledException e) { 
    269                 // do nothing. Exception already reported 
    270             } 
     263            Command cmd = resolver.buildResolveCommand(); 
     264            Main.main.undoRedo.add(cmd); 
     265            closeDialog(); 
    271266        } 
    272267 
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/DownloadRelationMemberTask.java

    r3102 r3362  
    121121            if (dataSet == null) 
    122122                return; 
     123            dataSet.deleteInvisible(); 
    123124            synchronized (this) { 
    124125                if (cancelled) return; 
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r3245 r3362  
    3939import org.openstreetmap.josm.Main; 
    4040import org.openstreetmap.josm.actions.RenameLayerAction; 
    41 import org.openstreetmap.josm.command.PurgePrimitivesCommand; 
    4241import org.openstreetmap.josm.data.Bounds; 
    4342import org.openstreetmap.josm.data.SelectionChangedListener; 
     
    326325            } 
    327326        } 
    328         PurgePrimitivesCommand cmd = buildPurgeCommand(); 
    329         if (cmd != null) { 
    330             Main.main.undoRedo.add(cmd); 
    331         } 
    332327        // repaint to make sure new data is displayed properly. 
    333328        Main.map.mapView.repaint(); 
    334         warnNumNewConflicts( 
    335                 numNewConflicts, 
    336                 cmd == null ? 0 : cmd.getPurgedPrimitives().size() 
    337         ); 
     329        warnNumNewConflicts(numNewConflicts); 
    338330    } 
    339331 
     
    342334     * 
    343335     * @param numNewConflicts the number of detected conflicts 
    344      * @param numPurgedPrimitives the number of automatically purged objects 
    345      */ 
    346     protected void warnNumNewConflicts(int numNewConflicts, int numPurgedPrimitives) { 
    347         if (numNewConflicts == 0 && numPurgedPrimitives == 0) return; 
     336     */ 
     337    protected void warnNumNewConflicts(int numNewConflicts) { 
     338        if (numNewConflicts == 0) return; 
    348339 
    349340        String msg1 = trn( 
     
    353344                numNewConflicts 
    354345        ); 
    355         String msg2 = trn( 
    356                 "{0} conflict has been <strong>resolved automatically</strong> by purging {0} object<br>from the local dataset because it is deleted on the server.", 
    357                 "{0} conflicts have been <strong>resolved automatically</strong> by purging {0} objects<br> from the local dataset because they are deleted on the server.", 
    358                 numPurgedPrimitives, 
    359                 numPurgedPrimitives 
    360         ); 
    361         int numRemainingConflicts = numNewConflicts - numPurgedPrimitives; 
    362         String msg3 = ""; 
    363         if (numRemainingConflicts >0) { 
    364             msg3 = trn( 
    365                     "{0} conflict remains to be resolved.<br><br>Please open the Conflict List Dialog and manually resolve it.", 
    366                     "{0} conflicts remain to be resolved.<br><br>Please open the Conflict List Dialog and manually resolve them.", 
    367                     numRemainingConflicts, 
    368                     numRemainingConflicts 
    369             ); 
    370         } 
    371346 
    372347        StringBuffer sb = new StringBuffer(); 
    373         sb.append("<html>").append(msg1); 
    374         if (numPurgedPrimitives > 0) { 
    375             sb.append("<br>").append(msg2); 
    376         } 
    377         if (numRemainingConflicts > 0) { 
    378             sb.append("<br>").append(msg3); 
    379         } 
    380         sb.append("</html>"); 
     348        sb.append("<html>").append(msg1).append("</html>"); 
    381349        if (numNewConflicts > 0) { 
    382350            ButtonSpec[] options = new ButtonSpec[] { 
     
    403371    } 
    404372 
    405     /** 
    406      * Builds the purge command for primitives which can be purged automatically 
    407      * from the local dataset because they've been deleted on the 
    408      * server. 
    409      * 
    410      * @return the purge command. <code>null</code> if no primitives have to 
    411      * be purged 
    412      */ 
    413     protected PurgePrimitivesCommand buildPurgeCommand() { 
    414         ArrayList<OsmPrimitive> toPurge = new ArrayList<OsmPrimitive>(); 
    415         conflictLoop: 
    416             for (Conflict<?> c: conflicts) { 
    417                 if (c.getMy().isDeleted() && !c.getTheir().isVisible()) { 
    418                     // Local and server version of the primitive are deleted. We 
    419                     // can purge it from the local dataset. 
    420                     // 
    421                     toPurge.add(c.getMy()); 
    422                 } else if (!c.getMy().isModified() && ! c.getTheir().isVisible()) { 
    423                     // We purge deleted *ways* and *relations* automatically if they are 
    424                     // deleted on the server and if they aren't modified in the local 
    425                     // dataset. 
    426                     // 
    427                     if (c.getMy() instanceof Way || c.getMy() instanceof Relation) { 
    428                         toPurge.add(c.getMy()); 
    429                         continue conflictLoop; 
    430                     } 
    431                     // We only purge nodes if they aren't part of a modified way. 
    432                     // Otherwise the number of nodes of a modified way could drop 
    433                     // below 2 and we would lose the modified data when the way 
    434                     // gets purged. 
    435                     // 
    436                     for (OsmPrimitive parent: c.getMy().getReferrers()) { 
    437                         if (parent.isModified() && parent instanceof Way) { 
    438                             continue conflictLoop; 
    439                         } 
    440                     } 
    441                     toPurge.add(c.getMy()); 
    442                 } 
    443             } 
    444         if (toPurge.isEmpty()) return null; 
    445         PurgePrimitivesCommand cmd = new PurgePrimitivesCommand(this, toPurge); 
    446         return cmd; 
    447     } 
    448373 
    449374    @Override public boolean isMergable(final Layer other) { 
  • trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

    r3083 r3362  
    456456            if (isCanceled())return null; 
    457457            fetchPrimitives(relations,OsmPrimitiveType.RELATION, progressMonitor); 
     458            if (outputDataSet != null) { 
     459                outputDataSet.deleteInvisible(); 
     460            } 
    458461            return outputDataSet; 
    459462        } finally { 
  • trunk/src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java

    r3083 r3362  
    274274            ret = visitor.getTargetDataSet(); 
    275275            readIncompletePrimitives(ret, progressMonitor.createSubTaskMonitor(1, false)); 
     276            if (ret != null) { 
     277                ret.deleteInvisible(); 
     278            } 
    276279            return ret; 
    277280        } finally { 
  • trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java

    r3283 r3362  
    234234 
    235235    /** 
    236      * My node is visible, their version has a higher version and is not visible 
    237      * => create a conflict 
    238      * 
    239      */ 
    240     @Test 
    241     public void nodeSimple_VisibleConflict() { 
    242         Node n = new Node(new LatLon(0,0)); 
    243         n.setOsmId(1,1); 
    244         n.setModified(false); 
    245         n.setVisible(true); 
    246         my.addPrimitive(n); 
    247  
    248         Node n1 = new Node(new LatLon(0,0)); 
    249         n1.setOsmId(1,2); 
    250  
    251         n1.setModified(false); 
    252         n1.setVisible(false); 
    253         their.addPrimitive(n1); 
    254  
    255  
    256         DataSetMerger visitor = new DataSetMerger(my,their); 
    257         visitor.merge(); 
    258  
    259         Node n2 = (Node)my.getPrimitiveById(1,OsmPrimitiveType.NODE); 
    260         assertEquals(1,visitor.getConflicts().size()); 
    261         assertEquals(true, n2.isVisible()); 
    262         assertTrue(n == n2); 
    263         assertTrue(n1 != n2); 
    264         assertTrue(n1.getDataSet() == their); 
    265     } 
    266  
    267     /** 
    268236     * My node is deleted, their node has the same id and version and is not deleted. 
    269237     * => mine has precedence 
     
    340308        assertTrue(n2 == n); 
    341309        assertTrue(n2.isDeleted()); 
    342     } 
    343  
    344     /** 
    345      * their node is not visible and doesn't exist in my data set 
    346      * => we can't ignore it because we'd run into troubles in case of multi fetch 
    347      * which can return invisible objects 
    348      * 
    349      */ 
    350     @Test 
    351     public void nodeSimple_InvisibleNodeInTheirDataset() { 
    352         Node n = new Node(new LatLon(0,0)); 
    353         n.setOsmId(1,1); 
    354         n.setDeleted(true); 
    355         my.addPrimitive(n); 
    356  
    357         Node n1 = new Node(new LatLon(0,0)); 
    358         n1.setOsmId(2,1); 
    359         n1.setVisible(false); 
    360         their.addPrimitive(n1); 
    361  
    362  
    363         DataSetMerger visitor = new DataSetMerger(my,their); 
    364         visitor.merge(); 
    365  
    366         Node n2 = (Node)my.getPrimitiveById(1,OsmPrimitiveType.NODE); 
    367         assertEquals(0,visitor.getConflicts().size()); 
    368         assertEquals(2, my.getNodes().size()); 
    369         assertEquals(n,n2); 
    370310    } 
    371311 
     
    688628        theirWay.setOsmId(3,2); 
    689629        theirWay.setVisible(false); 
     630        /* Invisible objects fetched from the server should be marked as "deleted". 
     631         * Otherwise it's an error. 
     632         */ 
     633        theirWay.setDeleted(true); 
    690634        their.addPrimitive(theirWay); 
    691635 
Note: See TracChangeset for help on using the changeset viewer.