Changeset 1642 in josm


Ignore:
Timestamp:
2009-06-06T16:25:25+02:00 (12 years ago)
Author:
Gubaer
Message:

added row numbers and synchronized scrolling in conflict resolution dialog
fixed bugs in conflict resolution

Location:
trunk/src/org/openstreetmap/josm
Files:
15 edited
1 moved

Legend:

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

    r1622 r1642  
    2525 */
    2626public class TagConflictResolveCommand extends Command {
    27    
     27
    2828    /** my primitive (in the local dataset). merge decisions are applied to this
    2929     *  primitive
    3030     */
    31     private OsmPrimitive my;
    32     /** their primitive (in the server dataset) */ 
    33     private OsmPrimitive their;
    34    
     31    private final OsmPrimitive my;
     32    /** their primitive (in the server dataset) */
     33    private final OsmPrimitive their;
     34
    3535    /** the list of merge decisions, represented as {@see TagMergeItem}s */
    36     private List<TagMergeItem> mergeItems;
    37    
     36    private final List<TagMergeItem> mergeItems;
     37
    3838    /**
    3939     * replies the number of decided conflicts
    4040     *
    41      * @return the number of decided conflicts 
     41     * @return the number of decided conflicts
    4242     */
    4343    public int getNumDecidedConflicts() {
     
    4545        for (TagMergeItem item: mergeItems) {
    4646            if (!item.getMergeDecision().equals(MergeDecisionType.UNDECIDED)) {
    47                 n++; 
     47                n++;
    4848            }
    4949        }
    5050        return n;
    5151    }
    52    
     52
    5353    /**
    5454     * replies a (localized) display name for the type of an OSM primitive
     
    6363        return "";
    6464    }
    65    
     65
    6666    /**
    67      * constructor 
     67     * constructor
    6868     *
    6969     * @param my  my primitive
    70      * @param their  their primitive 
     70     * @param their  their primitive
    7171     * @param mergeItems the list of merge decisions, represented as {@see TagMergeItem}s
    7272     */
     
    7676        this.mergeItems = mergeItems;
    7777    }
    78    
    79    
     78
     79
    8080    @Override
    81     public MutableTreeNode description() {               
     81    public MutableTreeNode description() {
    8282        return new DefaultMutableTreeNode(
    83           new JLabel(
    84              tr("Resolve {0} tag conflicts in {1} {2}",getNumDecidedConflicts(), getPrimitiveTypeAsString(my), my.id),
    85              ImageProvider.get("data", "object"),
    86              JLabel.HORIZONTAL
    87           )
    88        );
     83                new JLabel(
     84                        tr("Resolve {0} tag conflicts in {1} {2}",getNumDecidedConflicts(), getPrimitiveTypeAsString(my), my.id),
     85                        ImageProvider.get("data", "object"),
     86                        JLabel.HORIZONTAL
     87                )
     88        );
    8989    }
    9090
     
    9595        //
    9696        super.executeCommand();
    97        
     97
    9898        // apply the merge decisions to OSM primitive 'my'
    9999        //
    100100        for (TagMergeItem item: mergeItems) {
    101             item.applyToMyPrimitive(my);
     101            if (! item.getMergeDecision().equals(MergeDecisionType.UNDECIDED)) {
     102                item.applyToMyPrimitive(my);
     103            }
    102104        }
    103105        return true;
     
    115117        //
    116118        super.undoCommand();
    117        
     119
    118120        // restore a conflict if necessary
    119121        //
     
    123125    }
    124126
    125    
     127
    126128}
  • trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java

    r1622 r1642  
    2424public class VersionConflictResolveCommand extends Command {
    2525
    26     private OsmPrimitive my;
    27     private OsmPrimitive their;
    28    
     26    private final OsmPrimitive my;
     27    private final OsmPrimitive their;
     28
    2929    /**
    30      * constructor 
    31      * @param my  my primitive (i.e. the primitive from the local dataset) 
    32      * @param their their primitive (i.e. the primitive from the server) 
     30     * constructor
     31     * @param my  my primitive (i.e. the primitive from the local dataset)
     32     * @param their their primitive (i.e. the primitive from the server)
    3333     */
    3434    public VersionConflictResolveCommand(OsmPrimitive my, OsmPrimitive their) {
    35       this.my = my;
    36       this.their = their;
     35        this.my = my;
     36        this.their = their;
    3737    }
    38    
     38
    3939    //FIXME copied from TagConflictResolveCommand -> refactor
    4040    /**
     
    5050        return "";
    5151    }
    52    
     52
    5353    @Override
    5454    public MutableTreeNode description() {
    5555        return new DefaultMutableTreeNode(
    56             new JLabel(
    57                tr("Resolve version conflicts for {0} {1}",getPrimitiveTypeAsString(my), my.id),
    58                ImageProvider.get("data", "object"),
    59                JLabel.HORIZONTAL
    60             )
    61          );
     56                new JLabel(
     57                        tr("Resolve version conflicts for {0} {1}",getPrimitiveTypeAsString(my), my.id),
     58                        ImageProvider.get("data", "object"),
     59                        JLabel.HORIZONTAL
     60                )
     61        );
    6262    }
    6363
     
    6666        super.executeCommand();
    6767        my.version = Math.max(my.version, their.version);
    68         Main.map.conflictDialog.conflicts.remove(my);
     68        Main.map.conflictDialog.removeConflictForPrimitive(my);
    6969        return true;
    7070    }
     
    7979    public void undoCommand() {
    8080        super.undoCommand();
    81        
     81
    8282        // restore a conflict if necessary
    8383        //
    8484        if (!Main.map.conflictDialog.conflicts.containsKey(my)) {
    85             Main.map.conflictDialog.conflicts.put(my,their);
     85            Main.map.conflictDialog.addConflict(my, their);
    8686        }
    8787    }
    8888
    89    
     89
    9090}
  • trunk/src/org/openstreetmap/josm/gui/conflict/ConflictResolver.java

    r1631 r1642  
    189189            }
    190190        }
    191 
    192191        return new SequenceCommand(tr("Conflict Resolution"), commands);
    193192    }
     193
     194    public boolean isCompletelyResolved() {
     195        if (my instanceof Node) {
     196            // resolve the version conflict if this is a node and all tag
     197            // conflicts have been resolved
     198            //
     199            if (tagMerger.getModel().isResolvedCompletely())
     200                return true;
     201        } else if (my instanceof Way) {
     202            // resolve the version conflict if this is a way, all tag
     203            // conflicts have been resolved, and conflicts in the node list
     204            // have been resolved
     205            //
     206            if (tagMerger.getModel().isResolvedCompletely() && nodeListMerger.getModel().isFrozen())
     207                return true;
     208        }  else if (my instanceof Relation) {
     209            // resolve the version conflict if this is a relation, all tag
     210            // conflicts and all conflicts in the member list
     211            // have been resolved
     212            //
     213            if (tagMerger.getModel().isResolvedCompletely() && relationMemberMerger.getModel().isFrozen())
     214                return true;
     215        }
     216        return false;
     217    }
    194218}
  • trunk/src/org/openstreetmap/josm/gui/conflict/ListMergeModel.java

    r1631 r1642  
    1111
    1212import javax.swing.DefaultListSelectionModel;
    13 import javax.swing.ListSelectionModel;
    1413import javax.swing.table.DefaultTableModel;
    1514import javax.swing.table.TableModel;
     
    3534 * {@see #PROP_FROZEN}.
    3635 *
    37  * ListMergeModel is an abstract class. There methods have to be implemented by subclasses:
     36 * ListMergeModel is an abstract class. Three methods have to be implemented by subclasses:
    3837 * <ul>
    3938 *   <li>{@see ListMergeModel#cloneEntry(Object)} - clones an entry of type T</li>
     
    6160    protected DefaultTableModel mergedEntriesTableModel;
    6261
    63     protected DefaultListSelectionModel myEntriesSelectionModel;
    64     protected DefaultListSelectionModel theirEntriesSelectionModel;
    65     protected DefaultListSelectionModel mergedEntriesSelectionModel;
     62    protected EntriesSelectionModel<T> myEntriesSelectionModel;
     63    protected EntriesSelectionModel<T> theirEntriesSelectionModel;
     64    protected EntriesSelectionModel<T> mergedEntriesSelectionModel;
    6665
    6766    private final ArrayList<PropertyChangeListener> listeners;
     
    10099
    101100    protected void buildMyEntriesTableModel() {
    102         myEntriesTableModel = new ListTableModel<T>(myEntries);
     101        myEntriesTableModel = new EntriesTableModel<T>(myEntries);
    103102    }
    104103
    105104    protected void buildTheirEntriesTableModel() {
    106         theirEntriesTableModel = new ListTableModel<T>(theirEntries);
     105        theirEntriesTableModel = new EntriesTableModel<T>(theirEntries);
    107106    }
    108107
    109108    protected void buildMergedEntriesTableModel() {
    110         mergedEntriesTableModel = new ListTableModel<T>(mergedEntries);
     109        mergedEntriesTableModel = new EntriesTableModel<T>(mergedEntries);
    111110    }
    112111
     
    120119        buildMergedEntriesTableModel();
    121120
    122         myEntriesSelectionModel = new DefaultListSelectionModel();
    123         theirEntriesSelectionModel = new DefaultListSelectionModel();
    124         mergedEntriesSelectionModel = new DefaultListSelectionModel();
     121        myEntriesSelectionModel = new EntriesSelectionModel<T>(myEntries);
     122        theirEntriesSelectionModel = new EntriesSelectionModel<T>(theirEntries);
     123        mergedEntriesSelectionModel =  new EntriesSelectionModel<T>(mergedEntries);
    125124
    126125        listeners = new ArrayList<PropertyChangeListener>();
     
    177176    }
    178177
    179     public ListSelectionModel getMySelectionModel() {
     178    public EntriesSelectionModel getMySelectionModel() {
    180179        return myEntriesSelectionModel;
    181180    }
    182181
    183     public ListSelectionModel getTheirSelectionModel() {
     182    public EntriesSelectionModel getTheirSelectionModel() {
    184183        return theirEntriesSelectionModel;
    185184    }
    186185
    187     public ListSelectionModel getMergedSelectionModel() {
     186    public EntriesSelectionModel getMergedSelectionModel() {
    188187        return mergedEntriesSelectionModel;
    189188    }
     
    339338            throw new IllegalArgumentException(tr("parameter current out of range: got {0}", current));
    340339        if (current == mergedEntries.size() -1) {
    341             copyMyToEnd(rows);
     340            if (source == myEntries) {
     341                copyMyToEnd(rows);
     342            } else if (source == theirEntries) {
     343                copyTheirToEnd(rows);
     344            }
    342345        } else {
    343346            for (int i=rows.length -1; i>=0; i--) {
     
    461464
    462465
    463 
    464     protected class ListTableModel<T> extends DefaultTableModel {
    465         private final ArrayList<T> entries;
    466 
    467         public ListTableModel(ArrayList<T> nodes) {
     466    protected class EntriesTableModel<T1> extends DefaultTableModel {
     467        private final ArrayList<T1> entries;
     468
     469        public EntriesTableModel(ArrayList<T1> nodes) {
    468470            this.entries = nodes;
    469471        }
     
    471473        @Override
    472474        public int getRowCount() {
    473             return entries == null ? 0 : entries.size();
     475            int count = myEntries.size();
     476            count = Math.max(count, mergedEntries.size());
     477            count = Math.max(count, theirEntries.size());
     478            return count;
    474479        }
    475480
    476481        @Override
    477482        public Object getValueAt(int row, int column) {
    478             return entries.get(row);
     483            if (row < entries.size())
     484                return entries.get(row);
     485            return null;
    479486        }
    480487
     
    490497    }
    491498
    492 
    493 
     499    protected class EntriesSelectionModel<T1> extends DefaultListSelectionModel {
     500        private final ArrayList<T1> entries;
     501
     502        public EntriesSelectionModel(ArrayList<T1> nodes) {
     503            this.entries = nodes;
     504        }
     505
     506        @Override
     507        public void addSelectionInterval(int index0, int index1) {
     508            if (entries.isEmpty()) return;
     509            if (index0 > entries.size() - 1) return;
     510            index0 = Math.min(entries.size()-1, index0);
     511            index1 = Math.min(entries.size()-1, index1);
     512            super.addSelectionInterval(index0, index1);
     513        }
     514
     515        @Override
     516        public void insertIndexInterval(int index, int length, boolean before) {
     517            if (entries.isEmpty()) return;
     518            if (before) {
     519                int newindex = Math.min(entries.size()-1, index);
     520                if (newindex < index - length) return;
     521                length = length - (index - newindex);
     522                super.insertIndexInterval(newindex, length, before);
     523            } else {
     524                if (index > entries.size() -1) return;
     525                length = Math.min(entries.size()-1 - index, length);
     526                super.insertIndexInterval(index, length, before);
     527            }
     528        }
     529
     530        @Override
     531        public void moveLeadSelectionIndex(int leadIndex) {
     532            if (entries.isEmpty()) return;
     533            leadIndex = Math.max(0, leadIndex);
     534            leadIndex = Math.min(entries.size() - 1, leadIndex);
     535            super.moveLeadSelectionIndex(leadIndex);
     536        }
     537
     538        @Override
     539        public void removeIndexInterval(int index0, int index1) {
     540            if (entries.isEmpty()) return;
     541            index0 = Math.max(0, index0);
     542            index0 = Math.min(entries.size() - 1, index0);
     543
     544            index1 = Math.max(0, index1);
     545            index1 = Math.min(entries.size() - 1, index1);
     546            super.removeIndexInterval(index0, index1);
     547        }
     548
     549        @Override
     550        public void removeSelectionInterval(int index0, int index1) {
     551            if (entries.isEmpty()) return;
     552            index0 = Math.max(0, index0);
     553            index0 = Math.min(entries.size() - 1, index0);
     554
     555            index1 = Math.max(0, index1);
     556            index1 = Math.min(entries.size() - 1, index1);
     557            super.removeSelectionInterval(index0, index1);
     558        }
     559
     560        @Override
     561        public void setAnchorSelectionIndex(int anchorIndex) {
     562            if (entries.isEmpty()) return;
     563            anchorIndex = Math.min(entries.size() - 1, anchorIndex);
     564            super.setAnchorSelectionIndex(anchorIndex);
     565        }
     566
     567        @Override
     568        public void setLeadSelectionIndex(int leadIndex) {
     569            if (entries.isEmpty()) return;
     570            leadIndex = Math.min(entries.size() - 1, leadIndex);
     571            super.setLeadSelectionIndex(leadIndex);
     572        }
     573
     574        @Override
     575        public void setSelectionInterval(int index0, int index1) {
     576            if (entries.isEmpty()) return;
     577            index0 = Math.max(0, index0);
     578            index0 = Math.min(entries.size() - 1, index0);
     579
     580            index1 = Math.max(0, index1);
     581            index1 = Math.min(entries.size() - 1, index1);
     582
     583            super.setSelectionInterval(index0, index1);
     584        }
     585    }
    494586}
  • trunk/src/org/openstreetmap/josm/gui/conflict/ListMerger.java

    r1631 r1642  
    33import static org.openstreetmap.josm.tools.I18n.tr;
    44
     5import java.awt.Adjustable;
     6import java.awt.FlowLayout;
    57import java.awt.GridBagConstraints;
    68import java.awt.GridBagLayout;
    79import java.awt.Insets;
    810import java.awt.event.ActionEvent;
     11import java.awt.event.AdjustmentEvent;
     12import java.awt.event.AdjustmentListener;
    913import java.awt.event.ItemEvent;
    1014import java.awt.event.ItemListener;
    1115import java.beans.PropertyChangeEvent;
    1216import java.beans.PropertyChangeListener;
     17import java.util.ArrayList;
     18import java.util.HashMap;
     19import java.util.Observable;
     20import java.util.Observer;
    1321import java.util.logging.Logger;
    1422
     
    1725import javax.swing.ImageIcon;
    1826import javax.swing.JButton;
     27import javax.swing.JCheckBox;
    1928import javax.swing.JLabel;
    2029import javax.swing.JPanel;
     
    5867    private FreezeAction freezeAction;
    5968
    60 
     69    private AdjustmentSynchronizer adjustmentSynchronizer;
     70
     71    private  JCheckBox cbLockMyScrolling;
     72    private  JCheckBox cbLockMergedScrolling;
     73    private  JCheckBox cbLockTheirScrolling;
     74
     75    abstract protected JScrollPane buildMyElementsTable();
     76    abstract protected JScrollPane buildMergedElementsTable();
     77    abstract protected JScrollPane buildTheirElementsTable();
    6178
    6279    protected JScrollPane embeddInScrollPane(JTable table) {
     
    6481        pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    6582        pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
     83        if (adjustmentSynchronizer == null) {
     84            adjustmentSynchronizer = new AdjustmentSynchronizer();
     85        }
    6686        return pane;
    6787    }
    68 
    69     abstract protected JScrollPane buildMyElementsTable();
    70     abstract protected JScrollPane buildMergedElementsTable();
    71     abstract protected JScrollPane buildTheirElementsTable();
    72 
    73 
    7488
    7589    protected void wireActionsToSelectionModels() {
     
    99113        mergedEntriesTable.getSelectionModel().addListSelectionListener(removeMergedAction);
    100114    }
    101 
    102 
    103115
    104116    protected JPanel buildLeftButtonPanel() {
     
    206218    }
    207219
     220    protected JPanel buildAdjustmentLockControlPanel(JCheckBox cb) {
     221        JPanel panel = new JPanel();
     222        panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
     223        panel.add(new JLabel(tr("lock scrolling")));
     224        panel.add(cb);
     225        return panel;
     226    }
     227
    208228    protected void build() {
    209229        setLayout(new GridBagLayout());
    210230        GridBagConstraints gc = new GridBagConstraints();
    211231
     232        // ------------------
    212233        gc.gridx = 0;
    213234        gc.gridy = 0;
     
    225246        gc.gridx = 2;
    226247        gc.gridy = 0;
    227         gc.gridwidth = 1;
    228         gc.gridheight = 1;
    229         gc.fill = GridBagConstraints.NONE;
    230         gc.anchor = GridBagConstraints.CENTER;
    231         gc.weightx = 0.0;
    232         gc.weighty = 0.0;
    233248        lbl = new JLabel(tr("Merged version"));
    234249        lbl.setToolTipText(tr("List of merged elements. They will replace the my elements when the merge decisions are applied."));
     
    237252        gc.gridx = 4;
    238253        gc.gridy = 0;
     254        lbl = new JLabel(tr("Their version"));
     255        lbl.setToolTipText(tr("List of elements in their dataset, i.e. the server dataset"));
     256        add(lbl, gc);
     257
     258        // ------------------------------
     259        gc.gridx = 0;
     260        gc.gridy = 1;
    239261        gc.gridwidth = 1;
    240262        gc.gridheight = 1;
    241         gc.fill = GridBagConstraints.NONE;
    242         gc.anchor = GridBagConstraints.CENTER;
    243         gc.weightx = 0.0;
     263        gc.fill = GridBagConstraints.HORIZONTAL;
     264        gc.anchor = GridBagConstraints.FIRST_LINE_START;
     265        gc.weightx = 0.33;
    244266        gc.weighty = 0.0;
    245         lbl = new JLabel(tr("Their version"));
    246         lbl.setToolTipText(tr("List of elements in their dataset, i.e. the server dataset"));
    247 
    248         add(lbl, gc);
    249 
    250         gc.gridx = 0;
     267        gc.insets = new Insets(0,0,0,0);
     268        cbLockMyScrolling = new JCheckBox();
     269        cbLockMyScrolling.setName("checkbox.lockmyscrolling");
     270        add(buildAdjustmentLockControlPanel(cbLockMyScrolling), gc);
     271
     272        gc.gridx = 2;
    251273        gc.gridy = 1;
     274        cbLockMergedScrolling = new JCheckBox();
     275        cbLockMergedScrolling.setName("checkbox.lockmergedscrolling");
     276        add(buildAdjustmentLockControlPanel(cbLockMergedScrolling), gc);
     277
     278        gc.gridx = 4;
     279        gc.gridy = 1;
     280        cbLockTheirScrolling = new JCheckBox();
     281        cbLockTheirScrolling.setName("checkbox.locktheirscrolling");
     282        add(buildAdjustmentLockControlPanel(cbLockTheirScrolling), gc);
     283
     284        // --------------------------------
     285        gc.gridx = 0;
     286        gc.gridy = 2;
    252287        gc.gridwidth = 1;
    253288        gc.gridheight = 1;
    254289        gc.fill = GridBagConstraints.BOTH;
    255290        gc.anchor = GridBagConstraints.FIRST_LINE_START;
    256         gc.weightx = 0.3;
     291        gc.weightx = 0.33;
    257292        gc.weighty = 1.0;
    258293        gc.insets = new Insets(0,0,0,0);
    259         add(buildMyElementsTable(), gc);
     294        JScrollPane pane = buildMyElementsTable();
     295        adjustmentSynchronizer.adapt(cbLockMyScrolling, pane.getVerticalScrollBar());
     296        add(pane, gc);
    260297
    261298        gc.gridx = 1;
    262         gc.gridy = 1;
    263         gc.gridwidth = 1;
    264         gc.gridheight = 1;
     299        gc.gridy = 2;
    265300        gc.fill = GridBagConstraints.NONE;
    266301        gc.anchor = GridBagConstraints.CENTER;
     
    270305
    271306        gc.gridx = 2;
    272         gc.gridy = 1;
    273         gc.gridwidth = 1;
    274         gc.gridheight = 1;
     307        gc.gridy = 2;
    275308        gc.fill = GridBagConstraints.BOTH;
    276309        gc.anchor = GridBagConstraints.FIRST_LINE_START;
    277         gc.weightx = 0.3;
     310        gc.weightx = 0.33;
    278311        gc.weighty = 0.0;
    279         add(buildMergedElementsTable(), gc);
     312        pane = buildMergedElementsTable();
     313        adjustmentSynchronizer.adapt(cbLockMergedScrolling, pane.getVerticalScrollBar());
     314        add(pane, gc);
    280315
    281316        gc.gridx = 3;
    282         gc.gridy = 1;
    283         gc.gridwidth = 1;
    284         gc.gridheight = 1;
     317        gc.gridy = 2;
    285318        gc.fill = GridBagConstraints.NONE;
    286319        gc.anchor = GridBagConstraints.CENTER;
     
    290323
    291324        gc.gridx = 4;
    292         gc.gridy = 1;
    293         gc.gridwidth = 1;
    294         gc.gridheight = 1;
     325        gc.gridy = 2;
    295326        gc.fill = GridBagConstraints.BOTH;
    296327        gc.anchor = GridBagConstraints.FIRST_LINE_START;
    297         gc.weightx = 0.3;
     328        gc.weightx = 0.33;
    298329        gc.weighty = 0.0;
    299         add(buildTheirElementsTable(), gc);
    300 
     330        pane = buildTheirElementsTable();
     331        adjustmentSynchronizer.adapt(cbLockTheirScrolling, pane.getVerticalScrollBar());
     332        add(pane, gc);
     333
     334        // ----------------------------------
    301335        gc.gridx = 2;
    302         gc.gridy = 2;
     336        gc.gridy = 3;
    303337        gc.gridwidth = 1;
    304338        gc.gridheight = 1;
    305339        gc.fill = GridBagConstraints.BOTH;
    306340        gc.anchor = GridBagConstraints.CENTER;
    307         gc.weightx = 0.3;
     341        gc.weightx = 0.0;
    308342        gc.weighty = 0.0;
    309343        add(buildMergedListControlButtons(), gc);
     
    317351        model.addPropertyChangeListener(this);
    318352    }
    319 
    320353
    321354    /**
     
    666699         */
    667700        public void adapt(final JToggleButton btn) {
    668             //            btn.addItemListener(
    669             //                    new ItemListener() {
    670             //                        public void itemStateChanged(ItemEvent e) {
    671             //                            boolean isSelected = (Boolean)getValue(PROP_SELECTED);
    672             //                            if (isSelected != (e.getStateChange() == ItemEvent.SELECTED)) {
    673             //                                putValue(PROP_SELECTED, e.getStateChange() == ItemEvent.SELECTED);
    674             //                            }
    675             //                            model.setFrozen(e.getStateChange() == ItemEvent.SELECTED);
    676             //                        }
    677             //                    }
    678             //            );
    679701            btn.addItemListener(this);
    680702            addPropertyChangeListener(
     
    728750        return model;
    729751    }
     752
     753
     754
     755    /**
     756     * Synchronizes scrollbar adjustments between a set of
     757     * {@see Adjustable}s. Whenever the adjustment of one of
     758     * the registerd Adjustables is updated the adjustment of
     759     * the other registered Adjustables is adjusted too.
     760     *
     761     */
     762    class AdjustmentSynchronizer implements AdjustmentListener {
     763
     764        private final  ArrayList<Adjustable> synchronizedAdjustables;
     765        private final  HashMap<Adjustable, Boolean> enabledMap;
     766
     767        private final Observable observable;
     768
     769        public AdjustmentSynchronizer() {
     770            synchronizedAdjustables = new ArrayList<Adjustable>();
     771            enabledMap = new HashMap<Adjustable, Boolean>();
     772            observable = new Observable();
     773        }
     774
     775
     776        /**
     777         * registers an {@see Adjustable} for participation in synchronized
     778         * scrolling.
     779         *
     780         * @param adjustable the adjustable
     781         */
     782        public void participateInSynchronizedScrolling(Adjustable adjustable) {
     783            if (adjustable == null)
     784                return;
     785            if (synchronizedAdjustables.contains(adjustable))
     786                return;
     787            synchronizedAdjustables.add(adjustable);
     788            setParticipatingInSynchronizedScrolling(adjustable, true);
     789            adjustable.addAdjustmentListener(this);
     790        }
     791
     792        /**
     793         * event handler for {@see AdjustmentEvent}s
     794         *
     795         */
     796        public void adjustmentValueChanged(AdjustmentEvent e) {
     797            if (! enabledMap.get(e.getAdjustable()))
     798                return;
     799            for (Adjustable a : synchronizedAdjustables) {
     800                if (a != e.getAdjustable() && isParticipatingInSynchronizedScrolling(a)) {
     801                    a.setValue(e.getValue());
     802                }
     803            }
     804        }
     805
     806        /**
     807         * sets whether adjustable participates in adjustment synchronization
     808         * or not
     809         *
     810         * @param adjustable the adjustable
     811         */
     812        protected void setParticipatingInSynchronizedScrolling(Adjustable adjustable, boolean isParticipating) {
     813            if (adjustable == null)
     814                throw new IllegalArgumentException(tr("argument \"adjustable\" must not be null"));
     815
     816            if (! synchronizedAdjustables.contains(adjustable))
     817                throw new IllegalStateException(tr("adjustable {0} not registered yet. Can't set participation in synchronized adjustment",adjustable));
     818
     819            enabledMap.put(adjustable, isParticipating);
     820            observable.notifyObservers();
     821        }
     822
     823        /**
     824         * returns true if an adjustable is participating in synchronized scrolling
     825         *
     826         * @param adjustable the adjustable
     827         * @return true, if the adjustable is participating in synchronized scrolling, false otherwise
     828         * @throws IllegalStateException thrown, if adjustable is not registered for synchronized scrolling
     829         */
     830        protected boolean isParticipatingInSynchronizedScrolling(Adjustable adjustable) throws IllegalStateException {
     831            if (! synchronizedAdjustables.contains(adjustable))
     832                throw new IllegalStateException(tr("adjustable {0} not registered yet",adjustable));
     833
     834            return enabledMap.get(adjustable);
     835        }
     836
     837        /**
     838         * wires a {@see JCheckBox} to  the adjustment synchronizer, in such a way  that:
     839         * <li>
     840         *   <ol>state changes in the checkbox control whether the adjustable participates
     841         *      in synchronized adjustment</ol>
     842         *   <ol>state changes in this {@see AdjustmentSynchronizer} are reflected in the
     843         *      {@see JCheckBox}</ol>
     844         * </li>
     845         *
     846         *
     847         * @param view  the checkbox to control whether an adjustable participates in synchronized
     848         *      adjustment
     849         * @param adjustable the adjustable
     850         * @exception IllegalArgumentException thrown, if view is null
     851         * @exception IllegalArgumentException thrown, if adjustable is null
     852         */
     853        protected void adapt(final JCheckBox view, final Adjustable adjustable) throws IllegalArgumentException, IllegalStateException {
     854            if (adjustable == null)
     855                throw new IllegalArgumentException(tr("argument \"adjustable\" must not be null"));
     856            if (view == null)
     857                throw new IllegalArgumentException(tr("argument \"view\" must not be null"));
     858
     859            if (! synchronizedAdjustables.contains(adjustable)) {
     860                participateInSynchronizedScrolling(adjustable);
     861            }
     862
     863            // register an item lister with the check box
     864            //
     865            view.addItemListener(new ItemListener() {
     866                public void itemStateChanged(ItemEvent e) {
     867                    switch(e.getStateChange()) {
     868                    case ItemEvent.SELECTED:
     869                        if (!isParticipatingInSynchronizedScrolling(adjustable)) {
     870                            setParticipatingInSynchronizedScrolling(adjustable, true);
     871                        }
     872                        break;
     873                    case ItemEvent.DESELECTED:
     874                        if (isParticipatingInSynchronizedScrolling(adjustable)) {
     875                            setParticipatingInSynchronizedScrolling(adjustable, false);
     876                        }
     877                        break;
     878                    }
     879                }
     880            });
     881
     882
     883            observable.addObserver(
     884                    new Observer() {
     885                        public void update(Observable o, Object arg) {
     886                            boolean sync = isParticipatingInSynchronizedScrolling(adjustable);
     887                            if (view.isSelected() != sync) {
     888                                view.setSelected(sync);
     889                            }
     890                        }
     891                    }
     892            );
     893            setParticipatingInSynchronizedScrolling(adjustable, true);
     894            view.setSelected(true);
     895        }
     896    }
    730897}
  • trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListColumnModel.java

    r1631 r1642  
    1414        TableColumn col = null;
    1515
    16         // column 0 - Node
     16        // column 0 - Row num
    1717        col = new TableColumn(0);
     18        col.setHeaderValue("");
     19        col.setResizable(false);
     20        col.setWidth(30);
     21        col.setMaxWidth(30);
     22        col.setCellRenderer(renderer);
     23        addColumn(col);
     24
     25        // column 1 - Node
     26        col = new TableColumn(1);
    1827        col.setHeaderValue(tr("Node"));
    1928        col.setResizable(true);
  • trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListMerger.java

    r1631 r1642  
    3232        );
    3333        myEntriesTable.setName("table.mynodes");
     34        myEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    3435        return embeddInScrollPane(myEntriesTable);
    3536    }
     
    4546        );
    4647        mergedEntriesTable.setName("table.mergednodes");
     48        mergedEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    4749        return embeddInScrollPane(mergedEntriesTable);
    4850    }
     
    5860        );
    5961        theirEntriesTable.setName("table.theirnodes");
     62        theirEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    6063        return embeddInScrollPane(theirEntriesTable);
    6164    }
  • trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListTableCellRenderer.java

    r1640 r1642  
    66import java.awt.Color;
    77import java.awt.Component;
    8 import java.net.URL;
    98import java.text.DecimalFormat;
    109
     10import javax.swing.BorderFactory;
    1111import javax.swing.ImageIcon;
    1212import javax.swing.JLabel;
    1313import javax.swing.JTable;
     14import javax.swing.border.Border;
    1415import javax.swing.table.TableCellRenderer;
    1516
    1617import org.openstreetmap.josm.data.osm.Node;
     18import org.openstreetmap.josm.tools.ImageProvider;
    1719
    1820/**
    1921 * This is the {@see TableCellRenderer} used in the node tables of {@see NodeListMerger}.
    2022 *
    21  *
    2223 */
    2324public  class NodeListTableCellRenderer extends JLabel implements TableCellRenderer {
    2425    private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
    2526    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
     27    public final static Color BGCOLOR_EMPTY_ROW = new Color(234,234,234);
    2628
    27     /**
    28      * Load the image icon for an OSM primitive of type node
    29      *
    30      * @return the icon; null, if not found
    31      */
    32     protected ImageIcon loadIcon() {
    33         URL url = this.getClass().getResource("/images/data/node.png");;
    34         if (url == null) {
    35             System.out.println(tr("Failed to load resource /images/data/node.png"));
    36             return null;
    37         }
    38         return new ImageIcon(url);
    39     }
     29    private ImageIcon icon = null;
     30    private Border rowNumberBorder = null;
    4031
    4132    /**
     
    4334     */
    4435    public NodeListTableCellRenderer() {
    45         setIcon(loadIcon());
     36        icon = ImageProvider.get("data", "node");
     37        rowNumberBorder = BorderFactory.createEmptyBorder(0,4,0,0);
    4638        setOpaque(true);
    4739    }
     
    9082     */
    9183    protected  void renderNode(Node node, boolean isSelected) {
     84        setIcon(icon);
     85        setBorder(null);
    9286        if (isSelected) {
    9387            setBackground(BGCOLOR_SELECTED);
    9488        }
    9589        setText(getDisplayName(node));
     90    }
     91
     92    protected void renderEmptyRow() {
     93        setIcon(null);
     94        setBackground(BGCOLOR_EMPTY_ROW);
     95        setText("");
     96    }
     97
     98    /**
     99     * render the row id
     100     * @param row the row index
     101     * @param isSelected
     102     */
     103    protected  void renderRowId(int row, boolean isSelected) {
     104        setIcon(null);
     105        setBorder(rowNumberBorder);
     106        if (isSelected) {
     107            setBackground(BGCOLOR_SELECTED);
     108        }
     109        setText(Integer.toString(row+1));
    96110    }
    97111
     
    101115        Node node = (Node)value;
    102116        reset();
    103         renderNode(node,isSelected);
     117        switch(column) {
     118        case 0:
     119            renderRowId(row, isSelected);
     120            break;
     121        case 1:
     122            if (node == null) {
     123                renderEmptyRow();
     124            } else {
     125                renderNode(node,isSelected);
     126            }
     127            break;
     128        default:
     129            // should not happen
     130            throw new RuntimeException(tr("unexpected column index. Got {0}", column));
     131        }
    104132        return this;
    105133    }
  • trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListColumnModel.java

    r1631 r1642  
    1515        // column 0 - Role
    1616        col = new TableColumn(0);
     17        col.setHeaderValue("");
     18        col.setResizable(false);
     19        col.setWidth(20);
     20        col.setMaxWidth(20);
     21        col.setCellRenderer(renderer);
     22        addColumn(col);
     23
     24        // column 1 - Role
     25        col = new TableColumn(1);
    1726        col.setHeaderValue(tr("Role"));
    1827        col.setResizable(true);
    1928        col.setCellRenderer(renderer);
     29        col.setMaxWidth(100);
    2030        col.setCellEditor(new RelationMemberTableCellEditor());
    2131        addColumn(col);
    2232
    23         // column 1 - Primitive
    24         col = new TableColumn(1);
     33        // column 2 - Primitive
     34        col = new TableColumn(2);
    2535        col.setHeaderValue(tr("Primitive"));
    2636        col.setResizable(true);
  • trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListMergeModel.java

    r1631 r1642  
    3737        // editing cells in the first column
    3838        //
    39         mergedEntriesTableModel = this.new ListTableModel<RelationMember>(mergedEntries) {
     39        mergedEntriesTableModel = this.new EntriesTableModel<RelationMember>(mergedEntries) {
    4040            @Override
    4141            public boolean isCellEditable(int row, int column) {
    4242                switch(column) {
    43                 case 0: return true;
     43                case 1: return true;
    4444                default: return false;
    4545                }
     
    5050    @Override
    5151    protected void setValueAt(DefaultTableModel model, Object value, int row, int col) {
    52         if (model == getMergedTableModel() && col == 0) {
     52        if (model == getMergedTableModel() && col == 1) {
    5353            RelationMember member = mergedEntries.get(row);
    5454            member.role = (String)value;
  • trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberMerger.java

    r1631 r1642  
    2525        );
    2626        myEntriesTable.setName("table.mynodes");
     27        myEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    2728        return embeddInScrollPane(myEntriesTable);
    2829    }
     
    3031    @Override
    3132    protected JScrollPane buildMergedElementsTable() {
    32         logger.info(model.getMergedTableModel().toString());
    3333        mergedEntriesTable  = new JTable(
    3434                model.getMergedTableModel(),
     
    3838        mergedEntriesTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
    3939        mergedEntriesTable.setName("table.mergednodes");
     40        mergedEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    4041        return embeddInScrollPane(mergedEntriesTable);
    4142    }
     
    4950        );
    5051        theirEntriesTable.setName("table.theirnodes");
     52        theirEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    5153        return embeddInScrollPane(theirEntriesTable);
    5254    }
  • trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberTableCellRenderer.java

    r1640 r1642  
    88import java.text.DecimalFormat;
    99
     10import javax.swing.BorderFactory;
    1011import javax.swing.ImageIcon;
    1112import javax.swing.JLabel;
    1213import javax.swing.JTable;
     14import javax.swing.border.Border;
    1315import javax.swing.table.TableCellRenderer;
    1416
     
    2325 * This is the {@see TableCellRenderer} used in the tables of {@see RelationMemberMerger}.
    2426 *
    25  *
    2627 */
    2728public  class RelationMemberTableCellRenderer extends JLabel implements TableCellRenderer {
    28     private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
     29    private final static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
    2930    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
     31    public final static Color BGCOLOR_EMPTY_ROW = new Color(234,234,234);
    3032
    3133    private ImageIcon nodeIcon;
    3234    private ImageIcon wayIcon;
    3335    private ImageIcon relationIcon;
     36    private  Border rowNumberBorder = null;
    3437
    3538    /**
     
    5154        setOpaque(true);
    5255        loadIcons();
     56        rowNumberBorder = BorderFactory.createEmptyBorder(0,4,0,0);
    5357    }
    5458
     
    100104        setBackground(Color.WHITE);
    101105        setForeground(Color.BLACK);
     106        setBorder(null);
     107        setIcon(null);
     108        setToolTipText(null);
    102109    }
    103110
     
    110117    protected void renderRole(RelationMember member) {
    111118        setText(member.role == null ? "" : member.role);
    112         setIcon(null);
     119        setToolTipText(member.role == null ? "" : member.role);
    113120    }
    114121
     
    129136    }
    130137
     138    /**
     139     * render the row id
     140     * @param row the row index
     141     * @param isSelected
     142     */
     143    protected  void renderRowId(int row, boolean isSelected) {
     144        setBorder(rowNumberBorder);
     145        setText(Integer.toString(row+1));
     146    }
     147
     148    protected void renderEmptyRow() {
     149        setIcon(null);
     150        setBackground(BGCOLOR_EMPTY_ROW);
     151        setText("");
     152    }
     153
     154
    131155    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
    132156            int row, int column) {
     
    137161        switch(column) {
    138162        case 0:
    139             renderRole(member);
     163            renderRowId(row, isSelected);
    140164            break;
    141165        case 1:
    142             renderPrimitive(member);
     166            if (member == null) {
     167                renderEmptyRow();
     168            } else {
     169                renderRole(member);
     170            }
     171            break;
     172        case 2:
     173            if (member == null) {
     174                renderEmptyRow();
     175            } else {
     176                renderPrimitive(member);
     177            }
    143178            break;
    144179        default:
  • trunk/src/org/openstreetmap/josm/gui/conflict/tags/MergedTableCellRenderer.java

    r1627 r1642  
    66import java.awt.Color;
    77
    8 public class UndecidedTableCellRenderer extends TagMergeTableCellRenderer {
     8public class MergedTableCellRenderer extends TagMergeTableCellRenderer {
    99
    1010    public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
  • trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagMerger.java

    r1631 r1642  
    1313import java.awt.event.MouseAdapter;
    1414import java.awt.event.MouseEvent;
    15 import java.net.URL;
    1615import java.util.ArrayList;
    1716
     
    2726import javax.swing.event.ListSelectionListener;
    2827
     28import org.openstreetmap.josm.tools.ImageProvider;
     29/**
     30 * UI component for resolving conflicts in the tag sets of two {@see OsmPrimitive}s.
     31 *
     32 */
    2933public class TagMerger extends JPanel {
    3034
     
    3741    AdjustmentSynchronizer adjustmentSynchronizer;
    3842
     43    /**
     44     * embeds table in a new {@see JScrollPane} and returns th scroll pane
     45     *
     46     * @param table the table
     47     * @return the scroll pane embedding the table
     48     */
    3949    protected JScrollPane embeddInScrollPane(JTable table) {
    4050        JScrollPane pane = new JScrollPane(table);
     
    4656    }
    4757
     58    /**
     59     * builds the table for my tag set (table already embedded in a scroll pane)
     60     *
     61     * @return the table (embedded in a scroll pane)
     62     */
    4863    protected JScrollPane buildMineTagTable() {
    4964        mineTable  = new JTable(
     
    5772    }
    5873
     74    /**
     75     * builds the table for their tag set (table already embedded in a scroll pane)
     76     *
     77     * @return the table (embedded in a scroll pane)
     78     */
    5979    protected JScrollPane buildTheirTable() {
    6080        theirTable  = new JTable(
     
    6888    }
    6989
    70     protected JScrollPane buildUndecidedTable() {
     90    /**
     91     * builds the table for the merged tag set (table already embedded in a scroll pane)
     92     *
     93     * @return the table (embedded in a scroll pane)
     94     */
     95
     96    protected JScrollPane buildMergedTable() {
    7197        mergedTable  = new JTable(
    7298                model,
    7399                new TagMergeColumnModel(
    74                         new UndecidedTableCellRenderer()
     100                        new MergedTableCellRenderer()
    75101                )
    76102        );
     
    79105    }
    80106
     107    /**
     108     * build the user interface
     109     */
    81110    protected void build() {
    82111        GridBagConstraints gc = new GridBagConstraints();
     
    152181        gc.weightx = 0.3;
    153182        gc.weighty = 1.0;
    154         add(buildUndecidedTable(), gc);
     183        add(buildMergedTable(), gc);
    155184
    156185        gc.gridx = 3;
     
    205234    }
    206235
     236    /**
     237     * replies the model used by this tag merger
     238     *
     239     * @return the model
     240     */
    207241    public TagMergeModel getModel() {
    208242        return model;
    209243    }
    210244
    211     protected ImageIcon loadIcon(String name) {
    212         String path = "/images/dialogs/conflict/" + name;
    213         URL url = this.getClass().getResource(path);
    214         if (url == null) {
    215             System.out.println(tr("WARNING: failed to load resource {0}", path));
    216             return null;
    217         }
    218         return new ImageIcon(url);
    219     }
    220 
     245    /**
     246     * Keeps the currently selected tags in my table in the list of merged tags.
     247     *
     248     */
    221249    class KeepMineAction extends AbstractAction implements ListSelectionListener {
    222 
    223 
    224250        public KeepMineAction() {
    225             ImageIcon icon = loadIcon("tagkeepmine.png");
     251            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagkeepmine.png");
    226252            if (icon != null) {
    227253                putValue(Action.SMALL_ICON, icon);
     
    246272    }
    247273
     274    /**
     275     * Keeps the currently selected tags in their table in the list of merged tags.
     276     *
     277     */
    248278    class KeepTheirAction extends AbstractAction implements ListSelectionListener {
    249 
    250279        public KeepTheirAction() {
    251             ImageIcon icon = loadIcon("tagkeeptheir.png");
     280            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagkeeptheir.png");
    252281            if (icon != null) {
    253282                putValue(Action.SMALL_ICON, icon);
     
    272301    }
    273302
     303    /**
     304     * Synchronizes scrollbar adjustments between a set of
     305     * {@see Adjustable}s. Whenever the adjustment of one of
     306     * the registerd Adjustables is updated the adjustment of
     307     * the other registered Adjustables is adjusted too.
     308     *
     309     */
    274310    class AdjustmentSynchronizer implements AdjustmentListener {
    275311        private final ArrayList<Adjustable> synchronizedAdjustables;
     
    297333    }
    298334
     335    /**
     336     * Handler for double clicks on entries in the three tag tables.
     337     *
     338     */
    299339    class DoubleClickAdapter extends MouseAdapter {
    300340
     
    324364    }
    325365
     366    /**
     367     * Sets the currently selected tags in the table of merged tags to state
     368     * {@see MergeDecisionType#UNDECIDED}
     369     *
     370     */
    326371    class UndecideAction extends AbstractAction implements ListSelectionListener  {
    327372
    328373        public UndecideAction() {
    329             ImageIcon icon = loadIcon("tagundecide.png");
     374            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagundecide.png");
    330375            if (icon != null) {
    331376                putValue(Action.SMALL_ICON, icon);
  • trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java

    r1640 r1642  
    5151    private final DefaultListModel model = new DefaultListModel();
    5252    private final JList displaylist = new JList(model);
    53    
     53
    5454    private final SideButton sbSelect = new SideButton(marktr("Select"), "select", "Conflict",
    5555            tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
    56                 public void actionPerformed(ActionEvent e) {
    57                     Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
    58                     for (Object o : displaylist.getSelectedValues())
    59                         sel.add((OsmPrimitive)o);
    60                     Main.ds.setSelected(sel);
    61                 }
    62             });
     56        public void actionPerformed(ActionEvent e) {
     57            Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
     58            for (Object o : displaylist.getSelectedValues()) {
     59                sel.add((OsmPrimitive)o);
     60            }
     61            Main.ds.setSelected(sel);
     62        }
     63    });
    6364    private final SideButton sbResolve = new SideButton(marktr("Resolve"), "conflict", "Conflict",
    6465            tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
     
    7071    public ConflictDialog() {
    7172        super(tr("Conflict"), "conflict", tr("Merging conflicts."),
    72         Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
     73                Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
    7374        displaylist.setCellRenderer(new OsmPrimitivRenderer());
    7475        displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    7576        displaylist.addMouseListener(new MouseAdapter(){
    7677            @Override public void mouseClicked(MouseEvent e) {
    77                 if (e.getClickCount() >= 2)
     78                if (e.getClickCount() >= 2) {
    7879                    resolve();
     80                }
    7981            }
    8082        });
     
    102104            }
    103105        });
    104        
     106
    105107        rebuildList();
    106108    }
     
    110112        method = method.trim().toLowerCase();
    111113        if (method.equals("traditional")) {
    112             resolveTraditional();           
     114            resolveTraditional();
    113115        } else if (method.equals("extended")) {
    114116            resolveExtended();
     
    118120        }
    119121    }
    120    
    121    
     122
     123
    122124    private final void resolveExtended() {
    123         if(model.size() == 1)
     125        if(model.size() == 1) {
    124126            displaylist.setSelectedIndex(0);
    125        
     127        }
     128
    126129        if (displaylist.getSelectedIndex() == -1)
    127130            return;
    128        
     131
    129132        int [] selectedRows = displaylist.getSelectedIndices();
    130         if (selectedRows == null || selectedRows.length == 0) {
    131             return;
    132         }
     133        if (selectedRows == null || selectedRows.length == 0)
     134            return;
    133135        int row = selectedRows[0];
    134136        OsmPrimitive my = (OsmPrimitive)model.get(row);
    135137        OsmPrimitive their = conflicts.get(my);
    136         ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);     
     138        ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);
    137139        dialog.getConflictResolver().populate(my, their);
    138140        dialog.setVisible(true);
    139141        Main.map.mapView.repaint();
    140142    }
    141    
    142    
     143
     144
    143145    private final void resolveTraditional() {
    144         if(model.size() == 1)
     146        if(model.size() == 1) {
    145147            displaylist.setSelectedIndex(0);
    146        
     148        }
     149
    147150        if (displaylist.getSelectedIndex() == -1)
    148151            return;
     
    154157        ConflictResolver resolver = new ConflictResolver(sel);
    155158        int answer = new ExtendedDialog(Main.parent,
    156                           tr("Resolve Conflicts"),
    157                           resolver,
    158                           new String[] { tr("Solve Conflict"), tr("Cancel") },
    159                           new String[] { "dialogs/conflict.png", "cancel.png"}
    160         ).getValue(); 
     159                tr("Resolve Conflicts"),
     160                resolver,
     161                new String[] { tr("Solve Conflict"), tr("Cancel") },
     162                new String[] { "dialogs/conflict.png", "cancel.png"}
     163        ).getValue();
    161164
    162165        if (answer != 1)
     
    171174            model.addElement(osm);
    172175        }
    173        
     176
    174177        if(model.size() != 0) {
    175178            setTitle(tr("Conflicts: {0}", model.size()), true);
     
    177180            setTitle(tr("Conflicts"), false);
    178181        }
    179        
     182
    180183        sbSelect.setEnabled(model.size() > 0);
    181184        sbResolve.setEnabled(model.size() > 0);
     
    185188        this.conflicts.putAll(conflicts);
    186189        rebuildList();
     190    }
     191
     192
     193    /**
     194     * removes a conflict registered for {@see OsmPrimitive} <code>my</code>
     195     *
     196     * @param my the {@see OsmPrimitive} for which a conflict is registered
     197     *   with this dialog
     198     */
     199    public void removeConflictForPrimitive(OsmPrimitive my) {
     200        if (! conflicts.keySet().contains(my))
     201            return;
     202        conflicts.remove(my);
     203        rebuildList();
     204        repaint();
     205    }
     206
     207    /**
     208     * registers a conflict with this dialog. The conflict is represented
     209     * by a pair of {@see OsmPrimitive} with differences in their tag sets,
     210     * their node lists (for {@see Way}s) or their member lists (for {@see Relation}s)
     211     *
     212     * @param my  my version of the {@see OsmPrimitive}
     213     * @param their their version of the {@see OsmPrimitive}
     214     */
     215    public void addConflict(OsmPrimitive my, OsmPrimitive their) {
     216        conflicts.put(my, their);
     217        rebuildList();
     218        repaint();
    187219    }
    188220
     
    222254            }
    223255            public void visit(Relation e) {
    224                 for (RelationMember em : e.members)
     256                for (RelationMember em : e.members) {
    225257                    em.member.visit(this);
     258                }
    226259            }
    227260        };
  • trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java

    r1631 r1642  
    169169
    170170        public void actionPerformed(ActionEvent arg0) {
     171            if (! resolver.isCompletelyResolved()) {
     172                Object[] options = {
     173                        tr("Apply partial resolutions"),
     174                        tr("Continue resolving")};
     175                int n = JOptionPane.showOptionDialog(null,
     176                        tr("<html>You didn''t finish to resolve all conflicts.<br>"
     177                                + "Click <strong>{0}</strong> to apply already resolved conflicts anyway.<br>"
     178                                + "You can resolve the remaining conflicts later.<br>"
     179                                + "Click <strong>{1}</strong> to return to resolving conflicts.</html>"
     180                                , options[0].toString(), options[1].toString()
     181                        ),
     182                        tr("Warning"),
     183                        JOptionPane.YES_NO_OPTION,
     184                        JOptionPane.WARNING_MESSAGE,
     185                        null,
     186                        options,
     187                        options[1]
     188                );
     189                if (n == JOptionPane.NO_OPTION || n == JOptionPane.CLOSED_OPTION)
     190                    return;
     191            }
    171192            Command cmd = resolver.buildResolveCommand();
    172193            Main.main.undoRedo.add(cmd);
Note: See TracChangeset for help on using the changeset viewer.