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

Last change on this file since 7668 was 7668, checked in by stoecker, 10 years ago

cleanup icons, mark undetected icons, set proper mimetype, delete unused icons, update geticons script

  • 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 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<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.png");
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.png");
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.png");
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.png");
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.png");
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 public 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 class FreezeAction extends AbstractAction implements ItemListener, FreezeActionProperties {
785
786 public FreezeAction() {
787 putValue(Action.NAME, tr("Freeze"));
788 putValue(Action.SHORT_DESCRIPTION, tr("Freeze the current list of merged elements."));
789 putValue(PROP_SELECTED, 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.