source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/pair/ListMerger.java@ 6890

Last change on this file since 6890 was 6890, checked in by Don-vip, 10 years ago

fix some Sonar issues (Constructor Calls Overridable Method)

  • Property svn:eol-style set to native
File size: 32.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.pair;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.FlowLayout;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
10import java.awt.Insets;
11import java.awt.event.ActionEvent;
12import java.awt.event.ItemEvent;
13import java.awt.event.ItemListener;
14import java.beans.PropertyChangeEvent;
15import java.beans.PropertyChangeListener;
16import java.util.Collection;
17import java.util.Observable;
18import java.util.Observer;
19
20import javax.swing.AbstractAction;
21import javax.swing.Action;
22import javax.swing.ImageIcon;
23import javax.swing.JButton;
24import javax.swing.JCheckBox;
25import javax.swing.JLabel;
26import javax.swing.JPanel;
27import javax.swing.JScrollPane;
28import javax.swing.JTable;
29import javax.swing.JToggleButton;
30import javax.swing.event.ListSelectionEvent;
31import javax.swing.event.ListSelectionListener;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.data.osm.OsmPrimitive;
35import org.openstreetmap.josm.data.osm.PrimitiveId;
36import org.openstreetmap.josm.data.osm.Relation;
37import org.openstreetmap.josm.data.osm.Way;
38import org.openstreetmap.josm.gui.layer.OsmDataLayer;
39import org.openstreetmap.josm.gui.util.AdjustmentSynchronizer;
40import org.openstreetmap.josm.gui.widgets.JosmComboBox;
41import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTable;
42import org.openstreetmap.josm.tools.ImageProvider;
43
44/**
45 * A UI component for resolving conflicts in two lists of entries of type T.
46 *
47 * @param <T> the type of the entries
48 * @see ListMergeModel
49 */
50public abstract class ListMerger<T extends PrimitiveId> extends JPanel implements PropertyChangeListener, Observer {
51 protected OsmPrimitivesTable myEntriesTable;
52 protected OsmPrimitivesTable mergedEntriesTable;
53 protected OsmPrimitivesTable theirEntriesTable;
54
55 protected ListMergeModel<T> model;
56
57 private CopyStartLeftAction copyStartLeftAction;
58 private CopyBeforeCurrentLeftAction copyBeforeCurrentLeftAction;
59 private CopyAfterCurrentLeftAction copyAfterCurrentLeftAction;
60 private CopyEndLeftAction copyEndLeftAction;
61 private CopyAllLeft copyAllLeft;
62
63 private CopyStartRightAction copyStartRightAction;
64 private CopyBeforeCurrentRightAction copyBeforeCurrentRightAction;
65 private CopyAfterCurrentRightAction copyAfterCurrentRightAction;
66 private CopyEndRightAction copyEndRightAction;
67 private CopyAllRight copyAllRight;
68
69 private MoveUpMergedAction moveUpMergedAction;
70 private MoveDownMergedAction moveDownMergedAction;
71 private RemoveMergedAction removeMergedAction;
72 private FreezeAction freezeAction;
73
74 private AdjustmentSynchronizer adjustmentSynchronizer;
75
76 private JLabel lblMyVersion;
77 private JLabel lblMergedVersion;
78 private JLabel lblTheirVersion;
79
80 private JLabel lblFrozenState;
81
82 protected abstract JScrollPane buildMyElementsTable();
83 protected abstract JScrollPane buildMergedElementsTable();
84 protected abstract JScrollPane buildTheirElementsTable();
85
86 protected JScrollPane embeddInScrollPane(JTable table) {
87 JScrollPane pane = new JScrollPane(table);
88 if (adjustmentSynchronizer == null) {
89 adjustmentSynchronizer = new AdjustmentSynchronizer();
90 }
91 return pane;
92 }
93
94 protected void wireActionsToSelectionModels() {
95 myEntriesTable.getSelectionModel().addListSelectionListener(copyStartLeftAction);
96
97 myEntriesTable.getSelectionModel().addListSelectionListener(copyBeforeCurrentLeftAction);
98 mergedEntriesTable.getSelectionModel().addListSelectionListener(copyBeforeCurrentLeftAction);
99
100 myEntriesTable.getSelectionModel().addListSelectionListener(copyAfterCurrentLeftAction);
101 mergedEntriesTable.getSelectionModel().addListSelectionListener(copyAfterCurrentLeftAction);
102
103 myEntriesTable.getSelectionModel().addListSelectionListener(copyEndLeftAction);
104
105 theirEntriesTable.getSelectionModel().addListSelectionListener(copyStartRightAction);
106
107 theirEntriesTable.getSelectionModel().addListSelectionListener(copyBeforeCurrentRightAction);
108 mergedEntriesTable.getSelectionModel().addListSelectionListener(copyBeforeCurrentRightAction);
109
110 theirEntriesTable.getSelectionModel().addListSelectionListener(copyAfterCurrentRightAction);
111 mergedEntriesTable.getSelectionModel().addListSelectionListener(copyAfterCurrentRightAction);
112
113 theirEntriesTable.getSelectionModel().addListSelectionListener(copyEndRightAction);
114
115 mergedEntriesTable.getSelectionModel().addListSelectionListener(moveUpMergedAction);
116 mergedEntriesTable.getSelectionModel().addListSelectionListener(moveDownMergedAction);
117 mergedEntriesTable.getSelectionModel().addListSelectionListener(removeMergedAction);
118
119 model.addObserver(copyAllLeft);
120 model.addObserver(copyAllRight);
121 model.addPropertyChangeListener(copyAllLeft);
122 model.addPropertyChangeListener(copyAllRight);
123 }
124
125 protected JPanel buildLeftButtonPanel() {
126 JPanel pnl = new JPanel();
127 pnl.setLayout(new GridBagLayout());
128 GridBagConstraints gc = new GridBagConstraints();
129
130 gc.gridx = 0;
131 gc.gridy = 0;
132 copyStartLeftAction = new CopyStartLeftAction();
133 JButton btn = new JButton(copyStartLeftAction);
134 btn.setName("button.copystartleft");
135 pnl.add(btn, gc);
136
137 gc.gridx = 0;
138 gc.gridy = 1;
139 copyBeforeCurrentLeftAction = new CopyBeforeCurrentLeftAction();
140 btn = new JButton(copyBeforeCurrentLeftAction);
141 btn.setName("button.copybeforecurrentleft");
142 pnl.add(btn, gc);
143
144 gc.gridx = 0;
145 gc.gridy = 2;
146 copyAfterCurrentLeftAction = new CopyAfterCurrentLeftAction();
147 btn = new JButton(copyAfterCurrentLeftAction);
148 btn.setName("button.copyaftercurrentleft");
149 pnl.add(btn, gc);
150
151 gc.gridx = 0;
152 gc.gridy = 3;
153 copyEndLeftAction = new CopyEndLeftAction();
154 btn = new JButton(copyEndLeftAction);
155 btn.setName("button.copyendleft");
156 pnl.add(btn, gc);
157
158 gc.gridx = 0;
159 gc.gridy = 4;
160 copyAllLeft = new CopyAllLeft();
161 btn = new JButton(copyAllLeft);
162 btn.setName("button.copyallleft");
163 pnl.add(btn, gc);
164
165 return pnl;
166 }
167
168 protected JPanel buildRightButtonPanel() {
169 JPanel pnl = new JPanel();
170 pnl.setLayout(new GridBagLayout());
171 GridBagConstraints gc = new GridBagConstraints();
172
173 gc.gridx = 0;
174 gc.gridy = 0;
175 copyStartRightAction = new CopyStartRightAction();
176 pnl.add(new JButton(copyStartRightAction), gc);
177
178 gc.gridx = 0;
179 gc.gridy = 1;
180 copyBeforeCurrentRightAction = new CopyBeforeCurrentRightAction();
181 pnl.add(new JButton(copyBeforeCurrentRightAction), gc);
182
183 gc.gridx = 0;
184 gc.gridy = 2;
185 copyAfterCurrentRightAction = new CopyAfterCurrentRightAction();
186 pnl.add(new JButton(copyAfterCurrentRightAction), gc);
187
188 gc.gridx = 0;
189 gc.gridy = 3;
190 copyEndRightAction = new CopyEndRightAction();
191 pnl.add(new JButton(copyEndRightAction), gc);
192
193 gc.gridx = 0;
194 gc.gridy = 4;
195 copyAllRight = new CopyAllRight();
196 pnl.add(new JButton(copyAllRight), gc);
197
198 return pnl;
199 }
200
201 protected JPanel buildMergedListControlButtons() {
202 JPanel pnl = new JPanel();
203 pnl.setLayout(new GridBagLayout());
204 GridBagConstraints gc = new GridBagConstraints();
205
206 gc.gridx = 0;
207 gc.gridy = 0;
208 gc.gridwidth = 1;
209 gc.gridheight = 1;
210 gc.fill = GridBagConstraints.HORIZONTAL;
211 gc.anchor = GridBagConstraints.CENTER;
212 gc.weightx = 0.3;
213 gc.weighty = 0.0;
214 moveUpMergedAction = new MoveUpMergedAction();
215 pnl.add(new JButton(moveUpMergedAction), gc);
216
217 gc.gridx = 1;
218 gc.gridy = 0;
219 moveDownMergedAction = new MoveDownMergedAction();
220 pnl.add(new JButton(moveDownMergedAction), gc);
221
222 gc.gridx = 2;
223 gc.gridy = 0;
224 removeMergedAction = new RemoveMergedAction();
225 pnl.add(new JButton(removeMergedAction), gc);
226
227 return pnl;
228 }
229
230 protected JPanel buildAdjustmentLockControlPanel(JCheckBox cb) {
231 JPanel panel = new JPanel();
232 panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
233 panel.add(new JLabel(tr("lock scrolling")));
234 panel.add(cb);
235 return panel;
236 }
237
238 protected JPanel buildComparePairSelectionPanel() {
239 JPanel p = new JPanel();
240 p.setLayout(new FlowLayout(FlowLayout.LEFT));
241 p.add(new JLabel(tr("Compare ")));
242 JosmComboBox cbComparePair = new JosmComboBox(model.getComparePairListModel());
243 cbComparePair.setRenderer(new ComparePairListCellRenderer());
244 p.add(cbComparePair);
245 return p;
246 }
247
248 protected JPanel buildFrozeStateControlPanel() {
249 JPanel p = new JPanel();
250 p.setLayout(new FlowLayout(FlowLayout.LEFT));
251 lblFrozenState = new JLabel();
252 p.add(lblFrozenState);
253 freezeAction = new FreezeAction();
254 JToggleButton btn = new JToggleButton(freezeAction);
255 freezeAction.adapt(btn);
256 btn.setName("button.freeze");
257 p.add(btn);
258
259 return p;
260 }
261
262 protected final void build() {
263 setLayout(new GridBagLayout());
264 GridBagConstraints gc = new GridBagConstraints();
265
266 // ------------------
267 gc.gridx = 0;
268 gc.gridy = 0;
269 gc.gridwidth = 1;
270 gc.gridheight = 1;
271 gc.fill = GridBagConstraints.NONE;
272 gc.anchor = GridBagConstraints.CENTER;
273 gc.weightx = 0.0;
274 gc.weighty = 0.0;
275 gc.insets = new Insets(10,0,0,0);
276 lblMyVersion = new JLabel(tr("My version"));
277 lblMyVersion.setToolTipText(tr("List of elements in my dataset, i.e. the local dataset"));
278 add(lblMyVersion, gc);
279
280 gc.gridx = 2;
281 gc.gridy = 0;
282 lblMergedVersion = new JLabel(tr("Merged version"));
283 lblMergedVersion.setToolTipText(tr("List of merged elements. They will replace the list of my elements when the merge decisions are applied."));
284 add(lblMergedVersion, gc);
285
286 gc.gridx = 4;
287 gc.gridy = 0;
288 lblTheirVersion = new JLabel(tr("Their version"));
289 lblTheirVersion.setToolTipText(tr("List of elements in their dataset, i.e. the server dataset"));
290 add(lblTheirVersion, gc);
291
292 // ------------------------------
293 gc.gridx = 0;
294 gc.gridy = 1;
295 gc.gridwidth = 1;
296 gc.gridheight = 1;
297 gc.fill = GridBagConstraints.HORIZONTAL;
298 gc.anchor = GridBagConstraints.FIRST_LINE_START;
299 gc.weightx = 0.33;
300 gc.weighty = 0.0;
301 gc.insets = new Insets(0,0,0,0);
302 JCheckBox cbLockMyScrolling = new JCheckBox();
303 cbLockMyScrolling.setName("checkbox.lockmyscrolling");
304 add(buildAdjustmentLockControlPanel(cbLockMyScrolling), gc);
305
306 gc.gridx = 2;
307 gc.gridy = 1;
308 JCheckBox cbLockMergedScrolling = new JCheckBox();
309 cbLockMergedScrolling.setName("checkbox.lockmergedscrolling");
310 add(buildAdjustmentLockControlPanel(cbLockMergedScrolling), gc);
311
312 gc.gridx = 4;
313 gc.gridy = 1;
314 JCheckBox cbLockTheirScrolling = new JCheckBox();
315 cbLockTheirScrolling.setName("checkbox.locktheirscrolling");
316 add(buildAdjustmentLockControlPanel(cbLockTheirScrolling), gc);
317
318 // --------------------------------
319 gc.gridx = 0;
320 gc.gridy = 2;
321 gc.gridwidth = 1;
322 gc.gridheight = 1;
323 gc.fill = GridBagConstraints.BOTH;
324 gc.anchor = GridBagConstraints.FIRST_LINE_START;
325 gc.weightx = 0.33;
326 gc.weighty = 1.0;
327 gc.insets = new Insets(0,0,0,0);
328 JScrollPane pane = buildMyElementsTable();
329 adjustmentSynchronizer.adapt(cbLockMyScrolling, pane.getVerticalScrollBar());
330 add(pane, gc);
331
332 gc.gridx = 1;
333 gc.gridy = 2;
334 gc.fill = GridBagConstraints.NONE;
335 gc.anchor = GridBagConstraints.CENTER;
336 gc.weightx = 0.0;
337 gc.weighty = 0.0;
338 add(buildLeftButtonPanel(), gc);
339
340 gc.gridx = 2;
341 gc.gridy = 2;
342 gc.fill = GridBagConstraints.BOTH;
343 gc.anchor = GridBagConstraints.FIRST_LINE_START;
344 gc.weightx = 0.33;
345 gc.weighty = 0.0;
346 pane = buildMergedElementsTable();
347 adjustmentSynchronizer.adapt(cbLockMergedScrolling, pane.getVerticalScrollBar());
348 add(pane, gc);
349
350 gc.gridx = 3;
351 gc.gridy = 2;
352 gc.fill = GridBagConstraints.NONE;
353 gc.anchor = GridBagConstraints.CENTER;
354 gc.weightx = 0.0;
355 gc.weighty = 0.0;
356 add(buildRightButtonPanel(), gc);
357
358 gc.gridx = 4;
359 gc.gridy = 2;
360 gc.fill = GridBagConstraints.BOTH;
361 gc.anchor = GridBagConstraints.FIRST_LINE_START;
362 gc.weightx = 0.33;
363 gc.weighty = 0.0;
364 pane = buildTheirElementsTable();
365 adjustmentSynchronizer.adapt(cbLockTheirScrolling, pane.getVerticalScrollBar());
366 add(pane, gc);
367
368 // ----------------------------------
369 gc.gridx = 2;
370 gc.gridy = 3;
371 gc.gridwidth = 1;
372 gc.gridheight = 1;
373 gc.fill = GridBagConstraints.BOTH;
374 gc.anchor = GridBagConstraints.CENTER;
375 gc.weightx = 0.0;
376 gc.weighty = 0.0;
377 add(buildMergedListControlButtons(), gc);
378
379 // -----------------------------------
380 gc.gridx = 0;
381 gc.gridy = 4;
382 gc.gridwidth = 2;
383 gc.gridheight = 1;
384 gc.fill = GridBagConstraints.HORIZONTAL;
385 gc.anchor = GridBagConstraints.LINE_START;
386 gc.weightx = 0.0;
387 gc.weighty = 0.0;
388 add(buildComparePairSelectionPanel(), gc);
389
390 gc.gridx = 2;
391 gc.gridy = 4;
392 gc.gridwidth = 3;
393 gc.gridheight = 1;
394 gc.fill = GridBagConstraints.HORIZONTAL;
395 gc.anchor = GridBagConstraints.LINE_START;
396 gc.weightx = 0.0;
397 gc.weighty = 0.0;
398 add(buildFrozeStateControlPanel(), gc);
399
400 wireActionsToSelectionModels();
401 }
402
403 /**
404 * Constructs a new {@code ListMerger}.
405 * @param model
406 */
407 public ListMerger(ListMergeModel<T> model) {
408 this.model = model;
409 model.addObserver(this);
410 build();
411 model.addPropertyChangeListener(this);
412 }
413
414 /**
415 * Base class of all other Copy* inner classes.
416 */
417 abstract class CopyAction extends AbstractAction implements ListSelectionListener {
418
419 protected CopyAction(String icon_name, String action_name, String short_description) {
420 ImageIcon icon = ImageProvider.get("dialogs/conflict", icon_name+".png");
421 putValue(Action.SMALL_ICON, icon);
422 if (icon == null) {
423 putValue(Action.NAME, action_name);
424 }
425 putValue(Action.SHORT_DESCRIPTION, short_description);
426 setEnabled(false);
427 }
428 }
429
430 /**
431 * Action for copying selected nodes in the list of my nodes to the list of merged
432 * nodes. Inserts the nodes at the beginning of the list of merged nodes.
433 */
434 class CopyStartLeftAction extends CopyAction {
435
436 public CopyStartLeftAction() {
437 super("copystartleft", tr("> top"), tr("Copy my selected nodes to the start of the merged node list"));
438 }
439
440 @Override
441 public void actionPerformed(ActionEvent e) {
442 model.copyMyToTop(myEntriesTable.getSelectedRows());
443 }
444
445 @Override
446 public void valueChanged(ListSelectionEvent e) {
447 setEnabled(!myEntriesTable.getSelectionModel().isSelectionEmpty());
448 }
449 }
450
451 /**
452 * Action for copying selected nodes in the list of my nodes to the list of merged
453 * nodes. Inserts the nodes at the end of the list of merged nodes.
454 */
455 class CopyEndLeftAction extends CopyAction {
456
457 public CopyEndLeftAction() {
458 super("copyendleft", tr("> bottom"), tr("Copy my selected elements to the end of the list of merged elements."));
459 }
460
461 @Override
462 public void actionPerformed(ActionEvent e) {
463 model.copyMyToEnd(myEntriesTable.getSelectedRows());
464 }
465
466 @Override
467 public void valueChanged(ListSelectionEvent e) {
468 setEnabled(!myEntriesTable.getSelectionModel().isSelectionEmpty());
469 }
470 }
471
472 /**
473 * Action for copying selected nodes in the list of my nodes to the list of merged
474 * nodes. Inserts the nodes before the first selected row in the list of merged nodes.
475 */
476 class CopyBeforeCurrentLeftAction extends CopyAction {
477
478 public CopyBeforeCurrentLeftAction() {
479 super("copybeforecurrentleft", tr("> before"),
480 tr("Copy my selected elements before the first selected element in the list of merged elements."));
481 }
482
483 @Override
484 public void actionPerformed(ActionEvent e) {
485 int [] mergedRows = mergedEntriesTable.getSelectedRows();
486 if (mergedRows == null || mergedRows.length == 0)
487 return;
488 int [] myRows = myEntriesTable.getSelectedRows();
489 int current = mergedRows[0];
490 model.copyMyBeforeCurrent(myRows, current);
491 }
492
493 @Override
494 public void valueChanged(ListSelectionEvent e) {
495 setEnabled(
496 !myEntriesTable.getSelectionModel().isSelectionEmpty()
497 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
498 );
499 }
500 }
501
502 /**
503 * Action for copying selected nodes in the list of my nodes to the list of merged
504 * nodes. Inserts the nodes after the first selected row in the list of merged nodes.
505 */
506 class CopyAfterCurrentLeftAction extends CopyAction {
507
508 public CopyAfterCurrentLeftAction() {
509 super("copyaftercurrentleft", tr("> after"),
510 tr("Copy my selected elements after the first selected element in the list of merged elements."));
511 }
512
513 @Override
514 public void actionPerformed(ActionEvent e) {
515 int [] mergedRows = mergedEntriesTable.getSelectedRows();
516 if (mergedRows == null || mergedRows.length == 0)
517 return;
518 int [] myRows = myEntriesTable.getSelectedRows();
519 int current = mergedRows[0];
520 model.copyMyAfterCurrent(myRows, current);
521 }
522
523 @Override
524 public void valueChanged(ListSelectionEvent e) {
525 setEnabled(
526 !myEntriesTable.getSelectionModel().isSelectionEmpty()
527 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
528 );
529 }
530 }
531
532 class CopyStartRightAction extends CopyAction {
533
534 public CopyStartRightAction() {
535 super("copystartright", tr("< top"), tr("Copy their selected element to the start of the list of merged elements."));
536 }
537
538 @Override
539 public void actionPerformed(ActionEvent e) {
540 model.copyTheirToTop(theirEntriesTable.getSelectedRows());
541 }
542
543 @Override
544 public void valueChanged(ListSelectionEvent e) {
545 setEnabled(!theirEntriesTable.getSelectionModel().isSelectionEmpty());
546 }
547 }
548
549 class CopyEndRightAction extends CopyAction {
550
551 public CopyEndRightAction() {
552 super("copyendright", tr("< bottom"), tr("Copy their selected elements to the end of the list of merged elements."));
553 }
554
555 @Override
556 public void actionPerformed(ActionEvent arg0) {
557 model.copyTheirToEnd(theirEntriesTable.getSelectedRows());
558 }
559
560 @Override
561 public void valueChanged(ListSelectionEvent e) {
562 setEnabled(!theirEntriesTable.getSelectionModel().isSelectionEmpty());
563 }
564 }
565
566 class CopyBeforeCurrentRightAction extends CopyAction {
567
568 public CopyBeforeCurrentRightAction() {
569 super("copybeforecurrentright", tr("< before"),
570 tr("Copy their selected elements before the first selected element in the list of merged elements."));
571 }
572
573 @Override
574 public void actionPerformed(ActionEvent e) {
575 int [] mergedRows = mergedEntriesTable.getSelectedRows();
576 if (mergedRows == null || mergedRows.length == 0)
577 return;
578 int [] myRows = theirEntriesTable.getSelectedRows();
579 int current = mergedRows[0];
580 model.copyTheirBeforeCurrent(myRows, current);
581 }
582
583 @Override
584 public void valueChanged(ListSelectionEvent e) {
585 setEnabled(
586 !theirEntriesTable.getSelectionModel().isSelectionEmpty()
587 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
588 );
589 }
590 }
591
592 class CopyAfterCurrentRightAction extends CopyAction {
593
594 public CopyAfterCurrentRightAction() {
595 super("copyaftercurrentright", tr("< after"),
596 tr("Copy their selected element after the first selected element in the list of merged elements"));
597 }
598
599 @Override
600 public void actionPerformed(ActionEvent e) {
601 int [] mergedRows = mergedEntriesTable.getSelectedRows();
602 if (mergedRows == null || mergedRows.length == 0)
603 return;
604 int [] myRows = theirEntriesTable.getSelectedRows();
605 int current = mergedRows[0];
606 model.copyTheirAfterCurrent(myRows, current);
607 }
608
609 @Override
610 public void valueChanged(ListSelectionEvent e) {
611 setEnabled(
612 !theirEntriesTable.getSelectionModel().isSelectionEmpty()
613 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
614 );
615 }
616 }
617
618 class CopyAllLeft extends AbstractAction implements Observer, PropertyChangeListener {
619
620 public CopyAllLeft() {
621 ImageIcon icon = ImageProvider.get("dialogs/conflict", "useallleft.png");
622 putValue(Action.SMALL_ICON, icon);
623 putValue(Action.SHORT_DESCRIPTION, tr("Copy all my elements to the target"));
624 }
625
626 @Override
627 public void actionPerformed(ActionEvent arg0) {
628 model.copyAll(ListRole.MY_ENTRIES);
629 model.setFrozen(true);
630 }
631
632 private void updateEnabledState() {
633 setEnabled(model.getMergedEntries().isEmpty() && !model.isFrozen());
634 }
635
636 @Override
637 public void update(Observable o, Object arg) {
638 updateEnabledState();
639 }
640
641 @Override
642 public void propertyChange(PropertyChangeEvent evt) {
643 updateEnabledState();
644 }
645 }
646
647 class CopyAllRight extends AbstractAction implements Observer, PropertyChangeListener {
648
649 public CopyAllRight() {
650 ImageIcon icon = ImageProvider.get("dialogs/conflict", "useallright.png");
651 putValue(Action.SMALL_ICON, icon);
652 putValue(Action.SHORT_DESCRIPTION, tr("Copy all their elements to the target"));
653 }
654
655 @Override
656 public void actionPerformed(ActionEvent arg0) {
657 model.copyAll(ListRole.THEIR_ENTRIES);
658 model.setFrozen(true);
659 }
660
661 private void updateEnabledState() {
662 setEnabled(model.getMergedEntries().isEmpty() && !model.isFrozen());
663 }
664
665 @Override
666 public void update(Observable o, Object arg) {
667 updateEnabledState();
668 }
669
670 @Override
671 public void propertyChange(PropertyChangeEvent evt) {
672 updateEnabledState();
673 }
674 }
675
676 class MoveUpMergedAction extends AbstractAction implements ListSelectionListener {
677
678 public MoveUpMergedAction() {
679 ImageIcon icon = ImageProvider.get("dialogs/conflict", "moveup.png");
680 putValue(Action.SMALL_ICON, icon);
681 if (icon == null) {
682 putValue(Action.NAME, tr("Up"));
683 }
684 putValue(Action.SHORT_DESCRIPTION, tr("Move up the selected entries by one position."));
685 setEnabled(false);
686 }
687
688 @Override
689 public void actionPerformed(ActionEvent arg0) {
690 int [] rows = mergedEntriesTable.getSelectedRows();
691 model.moveUpMerged(rows);
692 }
693
694 @Override
695 public void valueChanged(ListSelectionEvent e) {
696 int [] rows = mergedEntriesTable.getSelectedRows();
697 setEnabled(
698 rows != null
699 && rows.length > 0
700 && rows[0] != 0
701 );
702 }
703 }
704
705 /**
706 * Action for moving the currently selected entries in the list of merged entries
707 * one position down
708 *
709 */
710 class MoveDownMergedAction extends AbstractAction implements ListSelectionListener {
711
712 public MoveDownMergedAction() {
713 ImageIcon icon = ImageProvider.get("dialogs/conflict", "movedown.png");
714 putValue(Action.SMALL_ICON, icon);
715 if (icon == null) {
716 putValue(Action.NAME, tr("Down"));
717 }
718 putValue(Action.SHORT_DESCRIPTION, tr("Move down the selected entries by one position."));
719 setEnabled(false);
720 }
721
722 @Override
723 public void actionPerformed(ActionEvent arg0) {
724 int [] rows = mergedEntriesTable.getSelectedRows();
725 model.moveDownMerged(rows);
726 }
727
728 @Override
729 public void valueChanged(ListSelectionEvent e) {
730 int [] rows = mergedEntriesTable.getSelectedRows();
731 setEnabled(
732 rows != null
733 && rows.length > 0
734 && rows[rows.length -1] != mergedEntriesTable.getRowCount() -1
735 );
736 }
737 }
738
739 /**
740 * Action for removing the selected entries in the list of merged entries
741 * from the list of merged entries.
742 *
743 */
744 class RemoveMergedAction extends AbstractAction implements ListSelectionListener {
745
746 public RemoveMergedAction() {
747 ImageIcon icon = ImageProvider.get("dialogs/conflict", "remove.png");
748 putValue(Action.SMALL_ICON, icon);
749 if (icon == null) {
750 putValue(Action.NAME, tr("Remove"));
751 }
752 putValue(Action.SHORT_DESCRIPTION, tr("Remove the selected entries from the list of merged elements."));
753 setEnabled(false);
754 }
755
756 @Override
757 public void actionPerformed(ActionEvent arg0) {
758 int [] rows = mergedEntriesTable.getSelectedRows();
759 model.removeMerged(rows);
760 }
761
762 @Override
763 public void valueChanged(ListSelectionEvent e) {
764 int [] rows = mergedEntriesTable.getSelectedRows();
765 setEnabled(
766 rows != null
767 && rows.length > 0
768 );
769 }
770 }
771
772 public static interface FreezeActionProperties {
773 String PROP_SELECTED = FreezeActionProperties.class.getName() + ".selected";
774 }
775
776 /**
777 * Action for freezing the current state of the list merger
778 *
779 */
780 class FreezeAction extends AbstractAction implements ItemListener, FreezeActionProperties {
781
782 public FreezeAction() {
783 putValue(Action.NAME, tr("Freeze"));
784 putValue(Action.SHORT_DESCRIPTION, tr("Freeze the current list of merged elements."));
785 putValue(PROP_SELECTED, false);
786 setEnabled(true);
787 }
788
789 @Override
790 public void actionPerformed(ActionEvent arg0) {
791 // do nothing
792 }
793
794 /**
795 * Java 1.5 doesn't known Action.SELECT_KEY. Wires a toggle button to this action
796 * such that the action gets notified about item state changes and the button gets
797 * notified about selection state changes of the action.
798 *
799 * @param btn a toggle button
800 */
801 public void adapt(final JToggleButton btn) {
802 btn.addItemListener(this);
803 addPropertyChangeListener(
804 new PropertyChangeListener() {
805 @Override
806 public void propertyChange(PropertyChangeEvent evt) {
807 if (evt.getPropertyName().equals(PROP_SELECTED)) {
808 btn.setSelected((Boolean)evt.getNewValue());
809 }
810 }
811 }
812 );
813 }
814
815 @Override
816 public void itemStateChanged(ItemEvent e) {
817 int state = e.getStateChange();
818 if (state == ItemEvent.SELECTED) {
819 putValue(Action.NAME, tr("Unfreeze"));
820 putValue(Action.SHORT_DESCRIPTION, tr("Unfreeze the list of merged elements and start merging."));
821 model.setFrozen(true);
822 } else if (state == ItemEvent.DESELECTED) {
823 putValue(Action.NAME, tr("Freeze"));
824 putValue(Action.SHORT_DESCRIPTION, tr("Freeze the current list of merged elements."));
825 model.setFrozen(false);
826 }
827 boolean isSelected = (Boolean)getValue(PROP_SELECTED);
828 if (isSelected != (e.getStateChange() == ItemEvent.SELECTED)) {
829 putValue(PROP_SELECTED, e.getStateChange() == ItemEvent.SELECTED);
830 }
831
832 }
833 }
834
835 protected void handlePropertyChangeFrozen(boolean oldValue, boolean newValue) {
836 myEntriesTable.getSelectionModel().clearSelection();
837 myEntriesTable.setEnabled(!newValue);
838 theirEntriesTable.getSelectionModel().clearSelection();
839 theirEntriesTable.setEnabled(!newValue);
840 mergedEntriesTable.getSelectionModel().clearSelection();
841 mergedEntriesTable.setEnabled(!newValue);
842 freezeAction.putValue(FreezeActionProperties.PROP_SELECTED, newValue);
843 if (newValue) {
844 lblFrozenState.setText(
845 tr("<html>Click <strong>{0}</strong> to start merging my and their entries.</html>",
846 freezeAction.getValue(Action.NAME))
847 );
848 } else {
849 lblFrozenState.setText(
850 tr("<html>Click <strong>{0}</strong> to finish merging my and their entries.</html>",
851 freezeAction.getValue(Action.NAME))
852 );
853 }
854 }
855
856 @Override
857 public void propertyChange(PropertyChangeEvent evt) {
858 if (evt.getPropertyName().equals(ListMergeModel.FROZEN_PROP)) {
859 handlePropertyChangeFrozen((Boolean)evt.getOldValue(), (Boolean)evt.getNewValue());
860 }
861 }
862
863 public ListMergeModel<T> getModel() {
864 return model;
865 }
866
867 @Override
868 public void update(Observable o, Object arg) {
869 lblMyVersion.setText(
870 trn("My version ({0} entry)", "My version ({0} entries)", model.getMyEntriesSize(), model.getMyEntriesSize())
871 );
872 lblMergedVersion.setText(
873 trn("Merged version ({0} entry)", "Merged version ({0} entries)", model.getMergedEntriesSize(), model.getMergedEntriesSize())
874 );
875 lblTheirVersion.setText(
876 trn("Their version ({0} entry)", "Their version ({0} entries)", model.getTheirEntriesSize(), model.getTheirEntriesSize())
877 );
878 }
879
880 public void unlinkAsListener() {
881 myEntriesTable.unlinkAsListener();
882 mergedEntriesTable.unlinkAsListener();
883 theirEntriesTable.unlinkAsListener();
884 }
885
886 protected final <P extends OsmPrimitive> OsmDataLayer findLayerFor(P primitive) {
887 if (primitive != null) {
888 Iterable<OsmDataLayer> layers = Main.map.mapView.getLayersOfType(OsmDataLayer.class);
889 // Find layer with same dataset
890 for (OsmDataLayer layer : layers) {
891 if (layer.data == primitive.getDataSet()) {
892 return layer;
893 }
894 }
895 // Conflict after merging layers: a dataset could be no more in any layer, try to find another layer with same primitive
896 for (OsmDataLayer layer : layers) {
897 final Collection<? extends OsmPrimitive> collection;
898 if (primitive instanceof Way) {
899 collection = layer.data.getWays();
900 } else if (primitive instanceof Relation) {
901 collection = layer.data.getRelations();
902 } else {
903 collection = layer.data.allPrimitives();
904 }
905 for (OsmPrimitive p : collection) {
906 if (p.getPrimitiveId().equals(primitive.getPrimitiveId())) {
907 return layer;
908 }
909 }
910 }
911 }
912 return null;
913 }
914}
Note: See TracBrowser for help on using the repository browser.