source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/pair/ListMergeModel.java@ 2936

Last change on this file since 2936 was 2936, checked in by jttt, 14 years ago

Fixed #4408 confict manager: do not have to solve tag- and element-conficts when deleting

File size: 26.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.pair;
3
4import static org.openstreetmap.josm.gui.conflict.pair.ComparePairType.MY_WITH_MERGED;
5import static org.openstreetmap.josm.gui.conflict.pair.ComparePairType.MY_WITH_THEIR;
6import static org.openstreetmap.josm.gui.conflict.pair.ComparePairType.THEIR_WITH_MERGED;
7import static org.openstreetmap.josm.gui.conflict.pair.ListRole.MERGED_ENTRIES;
8import static org.openstreetmap.josm.gui.conflict.pair.ListRole.MY_ENTRIES;
9import static org.openstreetmap.josm.gui.conflict.pair.ListRole.THEIR_ENTRIES;
10import static org.openstreetmap.josm.tools.I18n.tr;
11
12import java.beans.PropertyChangeEvent;
13import java.beans.PropertyChangeListener;
14import java.util.ArrayList;
15import java.util.HashMap;
16import java.util.List;
17import java.util.Observable;
18
19import javax.swing.AbstractListModel;
20import javax.swing.ComboBoxModel;
21import javax.swing.DefaultListSelectionModel;
22import javax.swing.table.DefaultTableModel;
23import javax.swing.table.TableModel;
24
25/**
26 * ListMergeModel is a model for interactively comparing and merging two list of entries
27 * of type T. It maintains three lists of entries of type T:
28 * <ol>
29 * <li>the list of <em>my</em> entries</li>
30 * <li>the list of <em>their</em> entries</li>
31 * <li>the list of <em>merged</em> entries</li>
32 * </ol>
33 *
34 * A ListMergeModel is a factory for three {@see TableModel}s and three {@see ListSelectionModel}s:
35 * <ol>
36 * <li>the table model and the list selection for for a {@see JTable} which shows my entries.
37 * See {@see #getMyTableModel()}</li> and {@see ListMergeModel#getMySelectionModel()}</li>
38 * <li>dito for their entries and merged entries</li>
39 * </ol>
40 *
41 * A ListMergeModel can be ''frozen''. If it's frozen, it doesn't accept additional merge
42 * decisions. {@see PropertyChangeListener}s can register for property value changes of
43 * {@see #PROP_FROZEN}.
44 *
45 * ListMergeModel is an abstract class. Three methods have to be implemented by subclasses:
46 * <ul>
47 * <li>{@see ListMergeModel#cloneEntryForMergedList(Object)} - clones an entry of type T</li>
48 * <li>{@see ListMergeModel#isEqualEntry(Object, Object)} - checks whether two entries are equals </li>
49 * <li>{@see ListMergeModel#setValueAt(DefaultTableModel, Object, int, int)} - handles values edited in
50 * a JTable, dispatched from {@see TableModel#setValueAt(Object, int, int)} </li>
51 * </ul>
52 * A ListMergeModel is used in combination with a {@see ListMerger}.
53 *
54 * @param <T> the type of the list entries
55 * @see ListMerger
56 */
57public abstract class ListMergeModel<T> extends Observable {
58 //private static final Logger logger = Logger.getLogger(ListMergeModel.class.getName());
59
60 public static final String FROZEN_PROP = ListMergeModel.class.getName() + ".frozen";
61
62 protected HashMap<ListRole, ArrayList<T>> entries;
63
64 protected DefaultTableModel myEntriesTableModel;
65 protected DefaultTableModel theirEntriesTableModel;
66 protected DefaultTableModel mergedEntriesTableModel;
67
68 protected EntriesSelectionModel myEntriesSelectionModel;
69 protected EntriesSelectionModel theirEntriesSelectionModel;
70 protected EntriesSelectionModel mergedEntriesSelectionModel;
71
72 private final ArrayList<PropertyChangeListener> listeners;
73 private boolean isFrozen = false;
74 private final ComparePairListModel comparePairListModel;
75
76 /**
77 * Creates a clone of an entry of type T suitable to be included in the
78 * list of merged entries
79 *
80 * @param entry the entry
81 * @return the cloned entry
82 */
83 protected abstract T cloneEntryForMergedList(T entry);
84
85 /**
86 * checks whether two entries are equal. This is not necessarily the same as
87 * e1.equals(e2).
88 *
89 * @param e1 the first entry
90 * @param e2 the second entry
91 * @return true, if the entries are equal, false otherwise.
92 */
93 public abstract boolean isEqualEntry(T e1, T e2);
94
95 /**
96 * Handles method dispatches from {@see TableModel#setValueAt(Object, int, int)}.
97 *
98 * @param model the table model
99 * @param value the value to be set
100 * @param row the row index
101 * @param col the column index
102 *
103 * @see TableModel#setValueAt(Object, int, int)
104 */
105 protected abstract void setValueAt(DefaultTableModel model, Object value, int row, int col);
106
107 protected void buildMyEntriesTableModel() {
108 myEntriesTableModel = new EntriesTableModel(MY_ENTRIES);
109 }
110
111 protected void buildTheirEntriesTableModel() {
112 theirEntriesTableModel = new EntriesTableModel(THEIR_ENTRIES);
113 }
114
115 protected void buildMergedEntriesTableModel() {
116 mergedEntriesTableModel = new EntriesTableModel(MERGED_ENTRIES);
117 }
118
119 protected List<T> getMergedEntries() {
120 return entries.get(MERGED_ENTRIES);
121 }
122
123 protected List<T> getMyEntries() {
124 return entries.get(MY_ENTRIES);
125 }
126
127 protected List<T> getTheirEntries() {
128 return entries.get(THEIR_ENTRIES);
129 }
130
131 public int getMyEntriesSize() {
132 return getMyEntries().size();
133 }
134
135 public int getMergedEntriesSize() {
136 return getMergedEntries().size();
137 }
138
139 public int getTheirEntriesSize() {
140 return getTheirEntries().size();
141 }
142
143 public ListMergeModel() {
144 entries = new HashMap<ListRole, ArrayList<T>>();
145 for (ListRole role : ListRole.values()) {
146 entries.put(role, new ArrayList<T>());
147 }
148
149 buildMyEntriesTableModel();
150 buildTheirEntriesTableModel();
151 buildMergedEntriesTableModel();
152
153 myEntriesSelectionModel = new EntriesSelectionModel(entries.get(MY_ENTRIES));
154 theirEntriesSelectionModel = new EntriesSelectionModel(entries.get(THEIR_ENTRIES));
155 mergedEntriesSelectionModel = new EntriesSelectionModel(entries.get(MERGED_ENTRIES));
156
157 listeners = new ArrayList<PropertyChangeListener>();
158 comparePairListModel = new ComparePairListModel();
159
160 setFrozen(true);
161 }
162
163 public void addPropertyChangeListener(PropertyChangeListener listener) {
164 synchronized(listeners) {
165 if (listener != null && ! listeners.contains(listener)) {
166 listeners.add(listener);
167 }
168 }
169 }
170
171 public void removePropertyChangeListener(PropertyChangeListener listener) {
172 synchronized(listeners) {
173 if (listener != null && listeners.contains(listener)) {
174 listeners.remove(listener);
175 }
176 }
177 }
178
179 protected void fireFrozenChanged(boolean oldValue, boolean newValue) {
180 synchronized(listeners) {
181 PropertyChangeEvent evt = new PropertyChangeEvent(this, FROZEN_PROP, oldValue, newValue);
182 for (PropertyChangeListener listener: listeners) {
183 listener.propertyChange(evt);
184 }
185 }
186 }
187
188 public void setFrozen(boolean isFrozen) {
189 boolean oldValue = this.isFrozen;
190 this.isFrozen = isFrozen;
191 fireFrozenChanged(oldValue, this.isFrozen);
192 }
193
194 public boolean isFrozen() {
195 return isFrozen;
196 }
197
198 public TableModel getMyTableModel() {
199 return myEntriesTableModel;
200 }
201
202 public TableModel getTheirTableModel() {
203 return theirEntriesTableModel;
204 }
205
206 public TableModel getMergedTableModel() {
207 return mergedEntriesTableModel;
208 }
209
210 public EntriesSelectionModel getMySelectionModel() {
211 return myEntriesSelectionModel;
212 }
213
214 public EntriesSelectionModel getTheirSelectionModel() {
215 return theirEntriesSelectionModel;
216 }
217
218 public EntriesSelectionModel getMergedSelectionModel() {
219 return mergedEntriesSelectionModel;
220 }
221
222 protected void fireModelDataChanged() {
223 myEntriesTableModel.fireTableDataChanged();
224 theirEntriesTableModel.fireTableDataChanged();
225 mergedEntriesTableModel.fireTableDataChanged();
226 setChanged();
227 notifyObservers();
228 }
229
230 protected void copyToTop(ListRole role, int []rows) {
231 copy(role, rows, 0);
232 mergedEntriesSelectionModel.setSelectionInterval(0, rows.length -1);
233 }
234
235 /**
236 * Copies the nodes given by indices in rows from the list of my nodes to the
237 * list of merged nodes. Inserts the nodes at the top of the list of merged
238 * nodes.
239 *
240 * @param rows the indices
241 */
242 public void copyMyToTop(int [] rows) {
243 copyToTop(MY_ENTRIES, rows);
244 }
245
246 /**
247 * Copies the nodes given by indices in rows from the list of their nodes to the
248 * list of merged nodes. Inserts the nodes at the top of the list of merged
249 * nodes.
250 *
251 * @param rows the indices
252 */
253 public void copyTheirToTop(int [] rows) {
254 copyToTop(THEIR_ENTRIES, rows);
255 }
256
257 /**
258 * Copies the nodes given by indices in rows from the list of nodes in source to the
259 * list of merged nodes. Inserts the nodes at the end of the list of merged
260 * nodes.
261 *
262 * @param source the list of nodes to copy from
263 * @param rows the indices
264 */
265
266 public void copyToEnd(ListRole source, int [] rows) {
267 copy(source, rows, getMergedEntriesSize());
268 mergedEntriesSelectionModel.setSelectionInterval(getMergedEntriesSize()-rows.length, getMergedEntriesSize() -1);
269
270 }
271
272 /**
273 * Copies the nodes given by indices in rows from the list of my nodes to the
274 * list of merged nodes. Inserts the nodes at the end of the list of merged
275 * nodes.
276 *
277 * @param rows the indices
278 */
279 public void copyMyToEnd(int [] rows) {
280 copyToEnd(MY_ENTRIES, rows);
281 }
282
283 /**
284 * Copies the nodes given by indices in rows from the list of their nodes to the
285 * list of merged nodes. Inserts the nodes at the end of the list of merged
286 * nodes.
287 *
288 * @param rows the indices
289 */
290 public void copyTheirToEnd(int [] rows) {
291 copyToEnd(THEIR_ENTRIES, rows);
292 }
293
294 public void clearMerged() {
295 getMergedEntries().clear();
296 fireModelDataChanged();
297 }
298
299 private void copy(ListRole sourceRole, int[] rows, int position) {
300 List<T> newItems = new ArrayList<T>(rows.length);
301 List<T> source = entries.get(sourceRole);
302 for (int row: rows) {
303 T clone = cloneEntryForMergedList(source.get(row));
304 if (clone != null) {
305 newItems.add(clone);
306 }
307 }
308 getMergedEntries().addAll(position, newItems);
309 fireModelDataChanged();
310 }
311
312 /**
313 * Copies the nodes given by indices in rows from the list of nodes <code>source</code> to the
314 * list of merged nodes. Inserts the nodes before row given by current.
315 *
316 * @param source the list of nodes to copy from
317 * @param rows the indices
318 * @param current the row index before which the nodes are inserted
319 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
320 *
321 */
322 protected void copyBeforeCurrent(ListRole source, int [] rows, int current) {
323 copy(source, rows, current);
324 mergedEntriesSelectionModel.setSelectionInterval(current, current + rows.length-1);
325 }
326
327 /**
328 * Copies the nodes given by indices in rows from the list of my nodes to the
329 * list of merged nodes. Inserts the nodes before row given by current.
330 *
331 * @param rows the indices
332 * @param current the row index before which the nodes are inserted
333 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
334 *
335 */
336 public void copyMyBeforeCurrent(int [] rows, int current) {
337 copyBeforeCurrent(MY_ENTRIES,rows,current);
338 }
339
340 /**
341 * Copies the nodes given by indices in rows from the list of their nodes to the
342 * list of merged nodes. Inserts the nodes before row given by current.
343 *
344 * @param rows the indices
345 * @param current the row index before which the nodes are inserted
346 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
347 *
348 */
349 public void copyTheirBeforeCurrent(int [] rows, int current) {
350 copyBeforeCurrent(THEIR_ENTRIES,rows,current);
351 }
352
353 /**
354 * Copies the nodes given by indices in rows from the list of nodes <code>source</code> to the
355 * list of merged nodes. Inserts the nodes after the row given by current.
356 *
357 * @param source the list of nodes to copy from
358 * @param rows the indices
359 * @param current the row index after which the nodes are inserted
360 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
361 *
362 */
363 protected void copyAfterCurrent(ListRole source, int [] rows, int current) {
364 copy(source, rows, current + 1);
365 mergedEntriesSelectionModel.setSelectionInterval(current+1, current + rows.length-1);
366 notifyObservers();
367 }
368
369 /**
370 * Copies the nodes given by indices in rows from the list of my nodes to the
371 * list of merged nodes. Inserts the nodes after the row given by current.
372 *
373 * @param rows the indices
374 * @param current the row index after which the nodes are inserted
375 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
376 *
377 */
378 public void copyMyAfterCurrent(int [] rows, int current) {
379 copyAfterCurrent(MY_ENTRIES, rows, current);
380 }
381
382 /**
383 * Copies the nodes given by indices in rows from the list of my nodes to the
384 * list of merged nodes. Inserts the nodes after the row given by current.
385 *
386 * @param rows the indices
387 * @param current the row index after which the nodes are inserted
388 * @exception IllegalArgumentException thrown, if current < 0 or >= #nodes in list of merged nodes
389 *
390 */
391 public void copyTheirAfterCurrent(int [] rows, int current) {
392 copyAfterCurrent(THEIR_ENTRIES, rows, current);
393 }
394
395 /**
396 * Moves the nodes given by indices in rows up by one position in the list
397 * of merged nodes.
398 *
399 * @param rows the indices
400 *
401 */
402 public void moveUpMerged(int [] rows) {
403 if (rows == null || rows.length == 0)
404 return;
405 if (rows[0] == 0)
406 // can't move up
407 return;
408 List<T> mergedEntries = getMergedEntries();
409 for (int row: rows) {
410 T n = mergedEntries.get(row);
411 mergedEntries.remove(row);
412 mergedEntries.add(row -1, n);
413 }
414 fireModelDataChanged();
415 notifyObservers();
416 mergedEntriesSelectionModel.clearSelection();
417 for (int row: rows) {
418 mergedEntriesSelectionModel.addSelectionInterval(row-1, row-1);
419 }
420 }
421
422 /**
423 * Moves the nodes given by indices in rows down by one position in the list
424 * of merged nodes.
425 *
426 * @param rows the indices
427 */
428 public void moveDownMerged(int [] rows) {
429 if (rows == null || rows.length == 0)
430 return;
431 List<T> mergedEntries = getMergedEntries();
432 if (rows[rows.length -1] == mergedEntries.size() -1)
433 // can't move down
434 return;
435 for (int i = rows.length-1; i>=0;i--) {
436 int row = rows[i];
437 T n = mergedEntries.get(row);
438 mergedEntries.remove(row);
439 mergedEntries.add(row +1, n);
440 }
441 fireModelDataChanged();
442 notifyObservers();
443 mergedEntriesSelectionModel.clearSelection();
444 for (int row: rows) {
445 mergedEntriesSelectionModel.addSelectionInterval(row+1, row+1);
446 }
447 }
448
449 /**
450 * Removes the nodes given by indices in rows from the list
451 * of merged nodes.
452 *
453 * @param rows the indices
454 */
455 public void removeMerged(int [] rows) {
456 if (rows == null || rows.length == 0)
457 return;
458
459 List<T> mergedEntries = getMergedEntries();
460
461 for (int i = rows.length-1; i>=0;i--) {
462 mergedEntries.remove(rows[i]);
463 }
464 fireModelDataChanged();
465 notifyObservers();
466 mergedEntriesSelectionModel.clearSelection();
467 }
468
469 /**
470 * Replies true if the list of my entries and the list of their
471 * entries are equal
472 *
473 * @return true, if the lists are equal; false otherwise
474 */
475 protected boolean myAndTheirEntriesEqual() {
476
477 if (getMyEntries().size() != getTheirEntries().size())
478 return false;
479 for (int i=0; i < getMyEntries().size(); i++) {
480 if (! isEqualEntry(getMyEntries().get(i), getTheirEntries().get(i)))
481 return false;
482 }
483 return true;
484 }
485
486 /**
487 * This an adapter between a {@see JTable} and one of the three entry lists
488 * in the role {@see ListRole} managed by the {@see ListMergeModel}.
489 *
490 * From the point of view of the {@see JTable} it is a {@see TableModel}.
491 *
492 * @param <T>
493 * @see ListMergeModel#getMyTableModel()
494 * @see ListMergeModel#getTheirTableModel()
495 * @see ListMergeModel#getMergedTableModel()
496 */
497 public class EntriesTableModel extends DefaultTableModel {
498 private final ListRole role;
499
500 /**
501 *
502 * @param role the role
503 */
504 public EntriesTableModel(ListRole role) {
505 this.role = role;
506 }
507
508 @Override
509 public int getRowCount() {
510 int count = Math.max(getMyEntries().size(), getMergedEntries().size());
511 count = Math.max(count, getTheirEntries().size());
512 return count;
513 }
514
515 @Override
516 public Object getValueAt(int row, int column) {
517 if (row < entries.get(role).size())
518 return entries.get(role).get(row);
519 return null;
520 }
521
522 @Override
523 public boolean isCellEditable(int row, int column) {
524 return false;
525 }
526
527 @Override
528 public void setValueAt(Object value, int row, int col) {
529 ListMergeModel.this.setValueAt(this, value,row,col);
530 }
531
532 public ListMergeModel<T> getListMergeModel() {
533 return ListMergeModel.this;
534 }
535
536 /**
537 * replies true if the {@see ListRole} of this {@see EntriesTableModel}
538 * participates in the current {@see ComparePairType}
539 *
540 * @return true, if the if the {@see ListRole} of this {@see EntriesTableModel}
541 * participates in the current {@see ComparePairType}
542 *
543 * @see ComparePairListModel#getSelectedComparePair()
544 */
545 public boolean isParticipatingInCurrentComparePair() {
546 return getComparePairListModel()
547 .getSelectedComparePair()
548 .isParticipatingIn(role);
549 }
550
551 /**
552 * replies true if the entry at <code>row</code> is equal to the entry at the
553 * same position in the opposite list of the current {@see ComparePairType}.
554 *
555 * @param row the row number
556 * @return true if the entry at <code>row</code> is equal to the entry at the
557 * same position in the opposite list of the current {@see ComparePairType}
558 * @exception IllegalStateException thrown, if this model is not participating in the
559 * current {@see ComparePairType}
560 * @see ComparePairType#getOppositeRole(ListRole)
561 * @see #getRole()
562 * @see #getOppositeEntries()
563 */
564 public boolean isSamePositionInOppositeList(int row) {
565 if (!isParticipatingInCurrentComparePair())
566 throw new IllegalStateException(tr("List in role {0} is currently not participating in a compare pair.", role.toString()));
567 if (row >= getEntries().size()) return false;
568 if (row >= getOppositeEntries().size()) return false;
569
570 T e1 = getEntries().get(row);
571 T e2 = getOppositeEntries().get(row);
572 return isEqualEntry(e1, e2);
573 }
574
575 /**
576 * replies true if the entry at the current position is present in the opposite list
577 * of the current {@see ComparePairType}.
578 *
579 * @param row the current row
580 * @return true if the entry at the current position is present in the opposite list
581 * of the current {@see ComparePairType}.
582 * @exception IllegalStateException thrown, if this model is not participating in the
583 * current {@see ComparePairType}
584 * @see ComparePairType#getOppositeRole(ListRole)
585 * @see #getRole()
586 * @see #getOppositeEntries()
587 */
588 public boolean isIncludedInOppositeList(int row) {
589 if (!isParticipatingInCurrentComparePair())
590 throw new IllegalStateException(tr("List in role {0} is currently not participating in a compare pair.", role.toString()));
591
592 if (row >= getEntries().size()) return false;
593 T e1 = getEntries().get(row);
594 for (T e2: getOppositeEntries()) {
595 if (isEqualEntry(e1, e2)) return true;
596 }
597 return false;
598 }
599
600 protected ArrayList<T> getEntries() {
601 return entries.get(role);
602 }
603
604 /**
605 * replies the opposite list of entries with respect to the current {@see ComparePairType}
606 *
607 * @return the opposite list of entries
608 */
609 protected ArrayList<T> getOppositeEntries() {
610 ListRole opposite = getComparePairListModel().getSelectedComparePair().getOppositeRole(role);
611 return entries.get(opposite);
612 }
613
614 public ListRole getRole() {
615 return role;
616 }
617 }
618
619 /**
620 * This is the selection model to be used in a {@see JTable} which displays
621 * an entry list managed by {@see ListMergeModel}.
622 *
623 * The model ensures that only rows displaying an entry in the entry list
624 * can be selected. "Empty" rows can't be selected.
625 *
626 * @see ListMergeModel#getMySelectionModel()
627 * @see ListMergeModel#getMergedSelectionModel()
628 * @see ListMergeModel#getTheirSelectionModel()
629 *
630 */
631 protected class EntriesSelectionModel extends DefaultListSelectionModel {
632 private final ArrayList<T> entries;
633
634 public EntriesSelectionModel(ArrayList<T> nodes) {
635 this.entries = nodes;
636 }
637
638 @Override
639 public void addSelectionInterval(int index0, int index1) {
640 if (entries.isEmpty()) return;
641 if (index0 > entries.size() - 1) return;
642 index0 = Math.min(entries.size()-1, index0);
643 index1 = Math.min(entries.size()-1, index1);
644 super.addSelectionInterval(index0, index1);
645 }
646
647 @Override
648 public void insertIndexInterval(int index, int length, boolean before) {
649 if (entries.isEmpty()) return;
650 if (before) {
651 int newindex = Math.min(entries.size()-1, index);
652 if (newindex < index - length) return;
653 length = length - (index - newindex);
654 super.insertIndexInterval(newindex, length, before);
655 } else {
656 if (index > entries.size() -1) return;
657 length = Math.min(entries.size()-1 - index, length);
658 super.insertIndexInterval(index, length, before);
659 }
660 }
661
662 @Override
663 public void moveLeadSelectionIndex(int leadIndex) {
664 if (entries.isEmpty()) return;
665 leadIndex = Math.max(0, leadIndex);
666 leadIndex = Math.min(entries.size() - 1, leadIndex);
667 super.moveLeadSelectionIndex(leadIndex);
668 }
669
670 @Override
671 public void removeIndexInterval(int index0, int index1) {
672 if (entries.isEmpty()) return;
673 index0 = Math.max(0, index0);
674 index0 = Math.min(entries.size() - 1, index0);
675
676 index1 = Math.max(0, index1);
677 index1 = Math.min(entries.size() - 1, index1);
678 super.removeIndexInterval(index0, index1);
679 }
680
681 @Override
682 public void removeSelectionInterval(int index0, int index1) {
683 if (entries.isEmpty()) return;
684 index0 = Math.max(0, index0);
685 index0 = Math.min(entries.size() - 1, index0);
686
687 index1 = Math.max(0, index1);
688 index1 = Math.min(entries.size() - 1, index1);
689 super.removeSelectionInterval(index0, index1);
690 }
691
692 @Override
693 public void setAnchorSelectionIndex(int anchorIndex) {
694 if (entries.isEmpty()) return;
695 anchorIndex = Math.min(entries.size() - 1, anchorIndex);
696 super.setAnchorSelectionIndex(anchorIndex);
697 }
698
699 @Override
700 public void setLeadSelectionIndex(int leadIndex) {
701 if (entries.isEmpty()) return;
702 leadIndex = Math.min(entries.size() - 1, leadIndex);
703 super.setLeadSelectionIndex(leadIndex);
704 }
705
706 @Override
707 public void setSelectionInterval(int index0, int index1) {
708 if (entries.isEmpty()) return;
709 index0 = Math.max(0, index0);
710 index0 = Math.min(entries.size() - 1, index0);
711
712 index1 = Math.max(0, index1);
713 index1 = Math.min(entries.size() - 1, index1);
714
715 super.setSelectionInterval(index0, index1);
716 }
717 }
718
719 public ComparePairListModel getComparePairListModel() {
720 return this.comparePairListModel;
721 }
722
723 public class ComparePairListModel extends AbstractListModel implements ComboBoxModel {
724
725 private int selectedIdx;
726 private final ArrayList<ComparePairType> compareModes;
727
728 public ComparePairListModel() {
729 this.compareModes = new ArrayList<ComparePairType>();
730 compareModes.add(MY_WITH_THEIR);
731 compareModes.add(MY_WITH_MERGED);
732 compareModes.add(THEIR_WITH_MERGED);
733 selectedIdx = 0;
734 }
735
736 public Object getElementAt(int index) {
737 if (index < compareModes.size())
738 return compareModes.get(index);
739 throw new IllegalArgumentException(tr("Unexpected value of parameter ''index''. Got {0}.", index));
740 }
741
742 public int getSize() {
743 return compareModes.size();
744 }
745
746 public Object getSelectedItem() {
747 return compareModes.get(selectedIdx);
748 }
749
750 public void setSelectedItem(Object anItem) {
751 int i = compareModes.indexOf(anItem);
752 if (i < 0)
753 throw new IllegalStateException(tr("Item {0} not found in list.", anItem));
754 selectedIdx = i;
755 fireModelDataChanged();
756 }
757
758 public ComparePairType getSelectedComparePair() {
759 return compareModes.get(selectedIdx);
760 }
761 }
762}
Note: See TracBrowser for help on using the repository browser.