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

Last change on this file since 2512 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

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