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

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

performance - remove useless boxing of boolean constants

  • Property svn:eol-style set to native
File size: 32.6 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 transient 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 transient 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<ComparePairType> 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);
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(/* ICON(dialogs/conflict/)*/ "copystartleft", tr("> top"),
438 tr("Copy my selected nodes to the start of the merged node list"));
439 }
440
441 @Override
442 public void actionPerformed(ActionEvent e) {
443 model.copyMyToTop(myEntriesTable.getSelectedRows());
444 }
445
446 @Override
447 public void valueChanged(ListSelectionEvent e) {
448 setEnabled(!myEntriesTable.getSelectionModel().isSelectionEmpty());
449 }
450 }
451
452 /**
453 * Action for copying selected nodes in the list of my nodes to the list of merged
454 * nodes. Inserts the nodes at the end of the list of merged nodes.
455 */
456 class CopyEndLeftAction extends CopyAction {
457
458 public CopyEndLeftAction() {
459 super(/* ICON(dialogs/conflict/)*/ "copyendleft", tr("> bottom"),
460 tr("Copy my selected elements to the end of the list of merged elements."));
461 }
462
463 @Override
464 public void actionPerformed(ActionEvent e) {
465 model.copyMyToEnd(myEntriesTable.getSelectedRows());
466 }
467
468 @Override
469 public void valueChanged(ListSelectionEvent e) {
470 setEnabled(!myEntriesTable.getSelectionModel().isSelectionEmpty());
471 }
472 }
473
474 /**
475 * Action for copying selected nodes in the list of my nodes to the list of merged
476 * nodes. Inserts the nodes before the first selected row in the list of merged nodes.
477 */
478 class CopyBeforeCurrentLeftAction extends CopyAction {
479
480 public CopyBeforeCurrentLeftAction() {
481 super(/* ICON(dialogs/conflict/)*/ "copybeforecurrentleft", tr("> before"),
482 tr("Copy my selected elements before the first selected element in the list of merged elements."));
483 }
484
485 @Override
486 public void actionPerformed(ActionEvent e) {
487 int [] mergedRows = mergedEntriesTable.getSelectedRows();
488 if (mergedRows == null || mergedRows.length == 0)
489 return;
490 int [] myRows = myEntriesTable.getSelectedRows();
491 int current = mergedRows[0];
492 model.copyMyBeforeCurrent(myRows, current);
493 }
494
495 @Override
496 public void valueChanged(ListSelectionEvent e) {
497 setEnabled(
498 !myEntriesTable.getSelectionModel().isSelectionEmpty()
499 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
500 );
501 }
502 }
503
504 /**
505 * Action for copying selected nodes in the list of my nodes to the list of merged
506 * nodes. Inserts the nodes after the first selected row in the list of merged nodes.
507 */
508 class CopyAfterCurrentLeftAction extends CopyAction {
509
510 public CopyAfterCurrentLeftAction() {
511 super(/* ICON(dialogs/conflict/)*/ "copyaftercurrentleft", tr("> after"),
512 tr("Copy my selected elements after the first selected element in the list of merged elements."));
513 }
514
515 @Override
516 public void actionPerformed(ActionEvent e) {
517 int [] mergedRows = mergedEntriesTable.getSelectedRows();
518 if (mergedRows == null || mergedRows.length == 0)
519 return;
520 int [] myRows = myEntriesTable.getSelectedRows();
521 int current = mergedRows[0];
522 model.copyMyAfterCurrent(myRows, current);
523 }
524
525 @Override
526 public void valueChanged(ListSelectionEvent e) {
527 setEnabled(
528 !myEntriesTable.getSelectionModel().isSelectionEmpty()
529 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
530 );
531 }
532 }
533
534 class CopyStartRightAction extends CopyAction {
535
536 public CopyStartRightAction() {
537 super(/* ICON(dialogs/conflict/)*/ "copystartright", tr("< top"),
538 tr("Copy their selected element to the start of the list of merged elements."));
539 }
540
541 @Override
542 public void actionPerformed(ActionEvent e) {
543 model.copyTheirToTop(theirEntriesTable.getSelectedRows());
544 }
545
546 @Override
547 public void valueChanged(ListSelectionEvent e) {
548 setEnabled(!theirEntriesTable.getSelectionModel().isSelectionEmpty());
549 }
550 }
551
552 class CopyEndRightAction extends CopyAction {
553
554 public CopyEndRightAction() {
555 super(/* ICON(dialogs/conflict/)*/ "copyendright", tr("< bottom"),
556 tr("Copy their selected elements to the end of the list of merged elements."));
557 }
558
559 @Override
560 public void actionPerformed(ActionEvent arg0) {
561 model.copyTheirToEnd(theirEntriesTable.getSelectedRows());
562 }
563
564 @Override
565 public void valueChanged(ListSelectionEvent e) {
566 setEnabled(!theirEntriesTable.getSelectionModel().isSelectionEmpty());
567 }
568 }
569
570 class CopyBeforeCurrentRightAction extends CopyAction {
571
572 public CopyBeforeCurrentRightAction() {
573 super(/* ICON(dialogs/conflict/)*/ "copybeforecurrentright", tr("< before"),
574 tr("Copy their selected elements before the first selected element in the list of merged elements."));
575 }
576
577 @Override
578 public void actionPerformed(ActionEvent e) {
579 int [] mergedRows = mergedEntriesTable.getSelectedRows();
580 if (mergedRows == null || mergedRows.length == 0)
581 return;
582 int [] myRows = theirEntriesTable.getSelectedRows();
583 int current = mergedRows[0];
584 model.copyTheirBeforeCurrent(myRows, current);
585 }
586
587 @Override
588 public void valueChanged(ListSelectionEvent e) {
589 setEnabled(
590 !theirEntriesTable.getSelectionModel().isSelectionEmpty()
591 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
592 );
593 }
594 }
595
596 class CopyAfterCurrentRightAction extends CopyAction {
597
598 public CopyAfterCurrentRightAction() {
599 super(/* ICON(dialogs/conflict/)*/ "copyaftercurrentright", tr("< after"),
600 tr("Copy their selected element after the first selected element in the list of merged elements"));
601 }
602
603 @Override
604 public void actionPerformed(ActionEvent e) {
605 int [] mergedRows = mergedEntriesTable.getSelectedRows();
606 if (mergedRows == null || mergedRows.length == 0)
607 return;
608 int [] myRows = theirEntriesTable.getSelectedRows();
609 int current = mergedRows[0];
610 model.copyTheirAfterCurrent(myRows, current);
611 }
612
613 @Override
614 public void valueChanged(ListSelectionEvent e) {
615 setEnabled(
616 !theirEntriesTable.getSelectionModel().isSelectionEmpty()
617 && !mergedEntriesTable.getSelectionModel().isSelectionEmpty()
618 );
619 }
620 }
621
622 class CopyAllLeft extends AbstractAction implements Observer, PropertyChangeListener {
623
624 public CopyAllLeft() {
625 ImageIcon icon = ImageProvider.get("dialogs/conflict", "useallleft");
626 putValue(Action.SMALL_ICON, icon);
627 putValue(Action.SHORT_DESCRIPTION, tr("Copy all my elements to the target"));
628 }
629
630 @Override
631 public void actionPerformed(ActionEvent arg0) {
632 model.copyAll(ListRole.MY_ENTRIES);
633 model.setFrozen(true);
634 }
635
636 private void updateEnabledState() {
637 setEnabled(model.getMergedEntries().isEmpty() && !model.isFrozen());
638 }
639
640 @Override
641 public void update(Observable o, Object arg) {
642 updateEnabledState();
643 }
644
645 @Override
646 public void propertyChange(PropertyChangeEvent evt) {
647 updateEnabledState();
648 }
649 }
650
651 class CopyAllRight extends AbstractAction implements Observer, PropertyChangeListener {
652
653 public CopyAllRight() {
654 ImageIcon icon = ImageProvider.get("dialogs/conflict", "useallright");
655 putValue(Action.SMALL_ICON, icon);
656 putValue(Action.SHORT_DESCRIPTION, tr("Copy all their elements to the target"));
657 }
658
659 @Override
660 public void actionPerformed(ActionEvent arg0) {
661 model.copyAll(ListRole.THEIR_ENTRIES);
662 model.setFrozen(true);
663 }
664
665 private void updateEnabledState() {
666 setEnabled(model.getMergedEntries().isEmpty() && !model.isFrozen());
667 }
668
669 @Override
670 public void update(Observable o, Object arg) {
671 updateEnabledState();
672 }
673
674 @Override
675 public void propertyChange(PropertyChangeEvent evt) {
676 updateEnabledState();
677 }
678 }
679
680 class MoveUpMergedAction extends AbstractAction implements ListSelectionListener {
681
682 public MoveUpMergedAction() {
683 ImageIcon icon = ImageProvider.get("dialogs/conflict", "moveup");
684 putValue(Action.SMALL_ICON, icon);
685 if (icon == null) {
686 putValue(Action.NAME, tr("Up"));
687 }
688 putValue(Action.SHORT_DESCRIPTION, tr("Move up the selected entries by one position."));
689 setEnabled(false);
690 }
691
692 @Override
693 public void actionPerformed(ActionEvent arg0) {
694 int [] rows = mergedEntriesTable.getSelectedRows();
695 model.moveUpMerged(rows);
696 }
697
698 @Override
699 public void valueChanged(ListSelectionEvent e) {
700 int [] rows = mergedEntriesTable.getSelectedRows();
701 setEnabled(
702 rows != null
703 && rows.length > 0
704 && rows[0] != 0
705 );
706 }
707 }
708
709 /**
710 * Action for moving the currently selected entries in the list of merged entries
711 * one position down
712 *
713 */
714 class MoveDownMergedAction extends AbstractAction implements ListSelectionListener {
715
716 public MoveDownMergedAction() {
717 ImageIcon icon = ImageProvider.get("dialogs/conflict", "movedown");
718 putValue(Action.SMALL_ICON, icon);
719 if (icon == null) {
720 putValue(Action.NAME, tr("Down"));
721 }
722 putValue(Action.SHORT_DESCRIPTION, tr("Move down the selected entries by one position."));
723 setEnabled(false);
724 }
725
726 @Override
727 public void actionPerformed(ActionEvent arg0) {
728 int [] rows = mergedEntriesTable.getSelectedRows();
729 model.moveDownMerged(rows);
730 }
731
732 @Override
733 public void valueChanged(ListSelectionEvent e) {
734 int [] rows = mergedEntriesTable.getSelectedRows();
735 setEnabled(
736 rows != null
737 && rows.length > 0
738 && rows[rows.length -1] != mergedEntriesTable.getRowCount() -1
739 );
740 }
741 }
742
743 /**
744 * Action for removing the selected entries in the list of merged entries
745 * from the list of merged entries.
746 *
747 */
748 class RemoveMergedAction extends AbstractAction implements ListSelectionListener {
749
750 public RemoveMergedAction() {
751 ImageIcon icon = ImageProvider.get("dialogs/conflict", "remove");
752 putValue(Action.SMALL_ICON, icon);
753 if (icon == null) {
754 putValue(Action.NAME, tr("Remove"));
755 }
756 putValue(Action.SHORT_DESCRIPTION, tr("Remove the selected entries from the list of merged elements."));
757 setEnabled(false);
758 }
759
760 @Override
761 public void actionPerformed(ActionEvent arg0) {
762 int [] rows = mergedEntriesTable.getSelectedRows();
763 model.removeMerged(rows);
764 }
765
766 @Override
767 public void valueChanged(ListSelectionEvent e) {
768 int [] rows = mergedEntriesTable.getSelectedRows();
769 setEnabled(
770 rows != null
771 && rows.length > 0
772 );
773 }
774 }
775
776 private static interface FreezeActionProperties {
777 String PROP_SELECTED = FreezeActionProperties.class.getName() + ".selected";
778 }
779
780 /**
781 * Action for freezing the current state of the list merger
782 *
783 */
784 private class FreezeAction extends AbstractAction implements ItemListener, FreezeActionProperties {
785
786 private FreezeAction() {
787 putValue(Action.NAME, tr("Freeze"));
788 putValue(Action.SHORT_DESCRIPTION, tr("Freeze the current list of merged elements."));
789 putValue(PROP_SELECTED, Boolean.FALSE);
790 setEnabled(true);
791 }
792
793 @Override
794 public void actionPerformed(ActionEvent arg0) {
795 // do nothing
796 }
797
798 /**
799 * Java 1.5 doesn't known Action.SELECT_KEY. Wires a toggle button to this action
800 * such that the action gets notified about item state changes and the button gets
801 * notified about selection state changes of the action.
802 *
803 * @param btn a toggle button
804 */
805 public void adapt(final JToggleButton btn) {
806 btn.addItemListener(this);
807 addPropertyChangeListener(
808 new PropertyChangeListener() {
809 @Override
810 public void propertyChange(PropertyChangeEvent evt) {
811 if (evt.getPropertyName().equals(PROP_SELECTED)) {
812 btn.setSelected((Boolean)evt.getNewValue());
813 }
814 }
815 }
816 );
817 }
818
819 @Override
820 public void itemStateChanged(ItemEvent e) {
821 int state = e.getStateChange();
822 if (state == ItemEvent.SELECTED) {
823 putValue(Action.NAME, tr("Unfreeze"));
824 putValue(Action.SHORT_DESCRIPTION, tr("Unfreeze the list of merged elements and start merging."));
825 model.setFrozen(true);
826 } else if (state == ItemEvent.DESELECTED) {
827 putValue(Action.NAME, tr("Freeze"));
828 putValue(Action.SHORT_DESCRIPTION, tr("Freeze the current list of merged elements."));
829 model.setFrozen(false);
830 }
831 boolean isSelected = (Boolean)getValue(PROP_SELECTED);
832 if (isSelected != (e.getStateChange() == ItemEvent.SELECTED)) {
833 putValue(PROP_SELECTED, e.getStateChange() == ItemEvent.SELECTED);
834 }
835
836 }
837 }
838
839 protected void handlePropertyChangeFrozen(boolean oldValue, boolean newValue) {
840 myEntriesTable.getSelectionModel().clearSelection();
841 myEntriesTable.setEnabled(!newValue);
842 theirEntriesTable.getSelectionModel().clearSelection();
843 theirEntriesTable.setEnabled(!newValue);
844 mergedEntriesTable.getSelectionModel().clearSelection();
845 mergedEntriesTable.setEnabled(!newValue);
846 freezeAction.putValue(FreezeActionProperties.PROP_SELECTED, newValue);
847 if (newValue) {
848 lblFrozenState.setText(
849 tr("<html>Click <strong>{0}</strong> to start merging my and their entries.</html>",
850 freezeAction.getValue(Action.NAME))
851 );
852 } else {
853 lblFrozenState.setText(
854 tr("<html>Click <strong>{0}</strong> to finish merging my and their entries.</html>",
855 freezeAction.getValue(Action.NAME))
856 );
857 }
858 }
859
860 @Override
861 public void propertyChange(PropertyChangeEvent evt) {
862 if (evt.getPropertyName().equals(ListMergeModel.FROZEN_PROP)) {
863 handlePropertyChangeFrozen((Boolean)evt.getOldValue(), (Boolean)evt.getNewValue());
864 }
865 }
866
867 public ListMergeModel<T> getModel() {
868 return model;
869 }
870
871 @Override
872 public void update(Observable o, Object arg) {
873 lblMyVersion.setText(
874 trn("My version ({0} entry)", "My version ({0} entries)", model.getMyEntriesSize(), model.getMyEntriesSize())
875 );
876 lblMergedVersion.setText(
877 trn("Merged version ({0} entry)", "Merged version ({0} entries)", model.getMergedEntriesSize(), model.getMergedEntriesSize())
878 );
879 lblTheirVersion.setText(
880 trn("Their version ({0} entry)", "Their version ({0} entries)", model.getTheirEntriesSize(), model.getTheirEntriesSize())
881 );
882 }
883
884 public void unlinkAsListener() {
885 myEntriesTable.unlinkAsListener();
886 mergedEntriesTable.unlinkAsListener();
887 theirEntriesTable.unlinkAsListener();
888 }
889
890 protected final <P extends OsmPrimitive> OsmDataLayer findLayerFor(P primitive) {
891 if (primitive != null) {
892 Iterable<OsmDataLayer> layers = Main.map.mapView.getLayersOfType(OsmDataLayer.class);
893 // Find layer with same dataset
894 for (OsmDataLayer layer : layers) {
895 if (layer.data == primitive.getDataSet()) {
896 return layer;
897 }
898 }
899 // Conflict after merging layers: a dataset could be no more in any layer, try to find another layer with same primitive
900 for (OsmDataLayer layer : layers) {
901 final Collection<? extends OsmPrimitive> collection;
902 if (primitive instanceof Way) {
903 collection = layer.data.getWays();
904 } else if (primitive instanceof Relation) {
905 collection = layer.data.getRelations();
906 } else {
907 collection = layer.data.allPrimitives();
908 }
909 for (OsmPrimitive p : collection) {
910 if (p.getPrimitiveId().equals(primitive.getPrimitiveId())) {
911 return layer;
912 }
913 }
914 }
915 }
916 return null;
917 }
918}
Note: See TracBrowser for help on using the repository browser.