001 /* DefaultListSelectionModel.java --
002 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing;
040
041 import java.io.Serializable;
042 import java.util.BitSet;
043 import java.util.EventListener;
044
045 import javax.swing.event.EventListenerList;
046 import javax.swing.event.ListSelectionEvent;
047 import javax.swing.event.ListSelectionListener;
048
049 /**
050 * The default implementation of {@link ListSelectionModel},
051 * which is used by {@link javax.swing.JList} and
052 * similar classes to manage the selection status of a number of data
053 * elements.
054 *
055 * <p>The class is organized <em>abstractly</em> as a set of intervals of
056 * integers. Each interval indicates an inclusive range of indices in a
057 * list -- held by some other object and unknown to this class -- which is
058 * considered "selected". There are various accessors for querying and
059 * modifying the set of intervals, with simplified forms accepting a single
060 * index, representing an interval with only one element. </p>
061 */
062 public class DefaultListSelectionModel implements Cloneable,
063 ListSelectionModel,
064 Serializable
065 {
066 private static final long serialVersionUID = -5718799865110415860L;
067
068 /** The list of ListSelectionListeners subscribed to this selection model. */
069 protected EventListenerList listenerList = new EventListenerList();
070
071
072 /**
073 * The current list selection mode. Must be one of the numeric constants
074 * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
075 * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
076 * ListSelectionModel}. The default value is
077 * <code>MULTIPLE_INTERVAL_SELECTION</code>.
078 */
079 int selectionMode = MULTIPLE_INTERVAL_SELECTION;
080
081 /**
082 * The index of the "lead" of the most recent selection. The lead is the
083 * second argument in any call to {@link #setSelectionInterval}, {@link
084 * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
085 * the lead refers to the most recent position a user dragged their mouse
086 * over.
087 */
088 int leadSelectionIndex = -1;
089
090 /**
091 * The index of the "anchor" of the most recent selection. The anchor is
092 * the first argument in any call to {@link #setSelectionInterval},
093 * {@link #addSelectionInterval} or {@link
094 * #removeSelectionInterval}. Generally the anchor refers to the first
095 * recent position a user clicks when they begin to drag their mouse over
096 * a list.
097 *
098 * @see #getAnchorSelectionIndex
099 * @see #setAnchorSelectionIndex
100 */
101 int anchorSelectionIndex = -1;
102
103 /**
104 * controls the range of indices provided in any {@link
105 * ListSelectionEvent} fired by the selectionModel. Let
106 * <code>[A,L]</code> be the range of indices between {@link
107 * #anchorSelectionIndex} and {@link #leadSelectionIndex} inclusive, and
108 * let <code>[i0,i1]</code> be the range of indices changed in a given
109 * call which generates a {@link ListSelectionEvent}. Then when this
110 * property is <code>true</code>, the {@link ListSelectionEvent} contains
111 * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it
112 * will contain only <code>[i0,i1]</code>. The default is
113 * <code>true</code>.
114 *
115 * @see #isLeadAnchorNotificationEnabled
116 * @see #setLeadAnchorNotificationEnabled
117 */
118 protected boolean leadAnchorNotificationEnabled = true;
119
120 /**
121 * Whether the selection is currently "adjusting". Any {@link
122 * ListSelectionEvent} events constructed in response to changes in this
123 * list selection model will have their {@link
124 * ListSelectionEvent#isAdjusting} field set to this value.
125 *
126 * @see #getValueIsAdjusting
127 * @see #setValueIsAdjusting
128 */
129 boolean valueIsAdjusting = false;
130
131
132 /**
133 * The current set of "intervals", represented simply by a {@link
134 * java.util.BitSet}. A set bit indicates a selected index, whereas a
135 * cleared bit indicates a non-selected index.
136 */
137 BitSet sel = new BitSet();
138
139 /**
140 * A variable to store the previous value of sel.
141 * Used to make sure we only fireValueChanged when the BitSet
142 * actually does change.
143 */
144 Object oldSel;
145
146 /**
147 * Whether this call of setLeadSelectionInterval was called locally
148 * from addSelectionInterval
149 */
150 boolean setLeadCalledFromAdd = false;
151
152 /**
153 * Returns the selection mode, which is one of {@link #SINGLE_SELECTION},
154 * {@link #SINGLE_INTERVAL_SELECTION} and
155 * {@link #MULTIPLE_INTERVAL_SELECTION}. The default value is
156 * {@link #MULTIPLE_INTERVAL_SELECTION}.
157 *
158 * @return The selection mode.
159 *
160 * @see #setSelectionMode(int)
161 */
162 public int getSelectionMode()
163 {
164 return selectionMode;
165 }
166
167 /**
168 * Sets the value of the {@link #selectionMode} property.
169 *
170 * @param mode The new value of the property
171 */
172 public void setSelectionMode(int mode)
173 {
174 if (mode < ListSelectionModel.SINGLE_SELECTION
175 || mode > ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
176 throw new IllegalArgumentException("Unrecognised mode: " + mode);
177 selectionMode = mode;
178 }
179
180 /**
181 * Gets the value of the {@link #anchorSelectionIndex} property.
182 *
183 * @return The current property value
184 *
185 * @see #setAnchorSelectionIndex
186 */
187 public int getAnchorSelectionIndex()
188 {
189 return anchorSelectionIndex;
190 }
191
192 /**
193 * Sets the value of the {@link #anchorSelectionIndex} property.
194 *
195 * @param index The new property value
196 *
197 * @see #getAnchorSelectionIndex
198 */
199 public void setAnchorSelectionIndex(int index)
200 {
201 if (anchorSelectionIndex != index)
202 {
203 int old = anchorSelectionIndex;
204 anchorSelectionIndex = index;
205 if (leadAnchorNotificationEnabled)
206 fireValueChanged(index, old);
207 }
208 }
209
210 /**
211 * Gets the value of the {@link #leadSelectionIndex} property.
212 *
213 * @return The current property value
214 *
215 * @see #setLeadSelectionIndex
216 */
217 public int getLeadSelectionIndex()
218 {
219 return leadSelectionIndex;
220 }
221
222 /**
223 * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
224 * side effect, alters the selection status of two ranges of indices. Let
225 * <code>OL</code> be the old lead selection index, <code>NL</code> be
226 * the new lead selection index, and <code>A</code> be the anchor
227 * selection index. Then if <code>A</code> is a valid selection index,
228 * one of two things happens depending on the seleciton status of
229 * <code>A</code>:</p>
230 *
231 * <ul>
232 *
233 * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
234 * to <em>deselected</em>, then set <code>[A,NL]</code> to
235 * <em>selected</em>.</li>
236 *
237 * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
238 * to <em>selected</em>, then set <code>[A,NL]</code> to
239 * <em>deselected</em>.</li>
240 *
241 * </ul>
242 *
243 * <p>This method generates at most a single {@link ListSelectionEvent}
244 * despite changing multiple ranges. The range of values provided to the
245 * {@link ListSelectionEvent} includes only the minimum range of values
246 * which changed selection status between the beginning and end of the
247 * method.</p>
248 *
249 * @param leadIndex The new property value
250 *
251 * @see #getAnchorSelectionIndex
252 */
253 public void setLeadSelectionIndex(int leadIndex)
254 {
255 // Only set the lead selection index to < 0 if anchorSelectionIndex < 0.
256 if (leadIndex < 0)
257 {
258 if (anchorSelectionIndex < 0)
259 leadSelectionIndex = -1;
260 else
261 return;
262 }
263
264 // Only touch the lead selection index if the anchor is >= 0.
265 if (anchorSelectionIndex < 0)
266 return;
267
268 if (selectionMode == SINGLE_SELECTION)
269 setSelectionInterval (leadIndex, leadIndex);
270
271 int oldLeadIndex = leadSelectionIndex;
272 if (oldLeadIndex == -1)
273 oldLeadIndex = leadIndex;
274 if (setLeadCalledFromAdd == false)
275 oldSel = sel.clone();
276 leadSelectionIndex = leadIndex;
277
278 if (anchorSelectionIndex == -1)
279 return;
280
281 int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
282 int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
283 int S1 = Math.min(anchorSelectionIndex, leadIndex);
284 int S2 = Math.max(anchorSelectionIndex, leadIndex);
285
286 int lo = Math.min(R1, S1);
287 int hi = Math.max(R2, S2);
288
289 if (isSelectedIndex(anchorSelectionIndex))
290 {
291 sel.clear(R1, R2+1);
292 sel.set(S1, S2+1);
293 }
294 else
295 {
296 sel.set(R1, R2+1);
297 sel.clear(S1, S2+1);
298 }
299
300 int beg = sel.nextSetBit(0), end = -1;
301 for(int i=beg; i >= 0; i=sel.nextSetBit(i+1))
302 end = i;
303
304 BitSet old = (BitSet) oldSel;
305
306 // The new and previous lead location requires repainting.
307 old.set(oldLeadIndex, !sel.get(oldLeadIndex));
308 old.set(leadSelectionIndex, !sel.get(leadSelectionIndex));
309
310 fireDifference(sel, old);
311 }
312
313 /**
314 * Moves the lead selection index to <code>leadIndex</code> without
315 * changing the selection values.
316 *
317 * If leadAnchorNotificationEnabled is true, send a notification covering the
318 * old and new lead cells.
319 *
320 * @param leadIndex the new lead selection index
321 * @since 1.5
322 */
323 public void moveLeadSelectionIndex (int leadIndex)
324 {
325 if (leadSelectionIndex == leadIndex)
326 return;
327
328 leadSelectionIndex = leadIndex;
329 if (isLeadAnchorNotificationEnabled())
330 fireValueChanged(Math.min(leadSelectionIndex, leadIndex),
331 Math.max(leadSelectionIndex, leadIndex));
332 }
333
334 /**
335 * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
336 *
337 * @return The current property value
338 *
339 * @see #setLeadAnchorNotificationEnabled
340 */
341 public boolean isLeadAnchorNotificationEnabled()
342 {
343 return leadAnchorNotificationEnabled;
344 }
345
346 /**
347 * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
348 *
349 * @param l The new property value
350 *
351 * @see #isLeadAnchorNotificationEnabled
352 */
353 public void setLeadAnchorNotificationEnabled(boolean l)
354 {
355 leadAnchorNotificationEnabled = l;
356 }
357
358 /**
359 * Gets the value of the {@link #valueIsAdjusting} property.
360 *
361 * @return The current property value
362 *
363 * @see #setValueIsAdjusting
364 */
365 public boolean getValueIsAdjusting()
366 {
367 return valueIsAdjusting;
368 }
369
370 /**
371 * Sets the value of the {@link #valueIsAdjusting} property.
372 *
373 * @param v The new property value
374 *
375 * @see #getValueIsAdjusting
376 */
377 public void setValueIsAdjusting(boolean v)
378 {
379 valueIsAdjusting = v;
380 }
381
382 /**
383 * Determines whether the selection is empty.
384 *
385 * @return <code>true</code> if the selection is empty, otherwise
386 * <code>false</code>
387 */
388 public boolean isSelectionEmpty()
389 {
390 return sel.isEmpty();
391 }
392
393 /**
394 * Gets the smallest index which is currently a member of a selection
395 * interval.
396 *
397 * @return The least integer <code>i</code> such that <code>i >=
398 * 0</code> and <code>i</code> is a member of a selected interval, or
399 * <code>-1</code> if there are no selected intervals
400 *
401 * @see #getMaxSelectionIndex
402 */
403 public int getMinSelectionIndex()
404 {
405 if (isSelectionEmpty())
406 return -1;
407
408 return sel.nextSetBit(0);
409 }
410
411 /**
412 * Gets the largest index which is currently a member of a selection
413 * interval.
414 *
415 * @return The greatest integer <code>i</code> such that <code>i >=
416 * 0</code> and <code>i</code> is a member of a selected interval, or
417 * <code>-1</code> if there are no selected intervals
418 *
419 * @see #getMinSelectionIndex
420 */
421 public int getMaxSelectionIndex()
422 {
423 if (isSelectionEmpty())
424 return -1;
425
426 int mx = -1;
427 for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1))
428 {
429 mx = i;
430 }
431 return mx;
432 }
433
434 /**
435 * Determines whether a particular index is a member of a selection
436 * interval.
437 *
438 * @param a The index to search for
439 *
440 * @return <code>true</code> if the index is a member of a selection interval,
441 * otherwise <code>false</code>
442 */
443 public boolean isSelectedIndex(int a)
444 {
445 // TODO: Probably throw an exception here?
446 if (a >= sel.length() || a < 0)
447 return false;
448 return sel.get(a);
449 }
450
451 /**
452 * If the {@link #selectionMode} property is equal to
453 * <code>SINGLE_SELECTION</code> equivalent to calling
454 * <code>setSelectionInterval(index1, index2)</code>;
455 * If the {@link #selectionMode} property is equal to
456 * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
457 * added is not adjacent to an already selected interval,
458 * equivalent to <code>setSelectionInterval(index1, index2)</code>.
459 * Otherwise adds the range <code>[index0, index1]</code>
460 * to the selection interval set.
461 *
462 * @param index0 The beginning of the range of indices to select
463 * @param index1 The end of the range of indices to select
464 *
465 * @see #setSelectionInterval
466 * @see #removeSelectionInterval
467 */
468 public void addSelectionInterval(int index0, int index1)
469 {
470 if (index0 == -1 || index1 == -1)
471 return;
472
473 if (selectionMode == SINGLE_SELECTION)
474 setSelectionInterval(index0, index1);
475 else
476 {
477 int lo = Math.min(index0, index1);
478 int hi = Math.max(index0, index1);
479 oldSel = sel.clone();
480
481
482 // COMPAT: Like Sun (but not like IBM), we allow calls to
483 // addSelectionInterval when selectionMode is
484 // SINGLE_SELECTION_INTERVAL iff the interval being added
485 // is adjacent to an already selected interval
486 if (selectionMode == SINGLE_INTERVAL_SELECTION)
487 if (!(isSelectedIndex(index0) ||
488 isSelectedIndex(index1) ||
489 isSelectedIndex(Math.max(lo-1,0)) ||
490 isSelectedIndex(Math.min(hi+1,sel.size()))))
491 sel.clear();
492
493 // We have to update the anchorSelectionIndex and leadSelectionIndex
494 // variables
495
496 // The next if statements breaks down to "if this selection is adjacent
497 // to the previous selection and going in the same direction"
498 if ((isSelectedIndex(leadSelectionIndex))
499 && ((index0 - 1 == leadSelectionIndex
500 && (index1 >= index0)
501 && (leadSelectionIndex >= anchorSelectionIndex))
502 || (index0 + 1 == leadSelectionIndex && (index1 <= index0)
503 && (leadSelectionIndex <= anchorSelectionIndex)))
504 && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
505 {
506 // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
507 // not to update oldSel
508 setLeadCalledFromAdd = true;
509 setLeadSelectionIndex(index1);
510 setLeadCalledFromAdd = false;
511 }
512 else
513 {
514 leadSelectionIndex = index1;
515 anchorSelectionIndex = index0;
516 sel.set(lo, hi+1);
517 fireDifference(sel, (BitSet) oldSel);
518 }
519 }
520 }
521
522
523 /**
524 * Deselects all indices in the inclusive range
525 * <code>[index0,index1]</code>.
526 *
527 * @param index0 The beginning of the range of indices to deselect
528 * @param index1 The end of the range of indices to deselect
529 *
530 * @see #addSelectionInterval
531 * @see #setSelectionInterval
532 */
533 public void removeSelectionInterval(int index0,
534 int index1)
535 {
536 if (index0 == -1 || index1 == -1)
537 return;
538
539 oldSel = sel.clone();
540 int lo = Math.min(index0, index1);
541 int hi = Math.max(index0, index1);
542
543 // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
544 // (index0,index1) would leave two disjoint selection intervals, remove all
545 // selected indices from lo to the last selected index
546 if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo &&
547 selectionMode == SINGLE_INTERVAL_SELECTION)
548 hi = sel.size() - 1;
549
550 sel.clear(lo, hi+1);
551 //update anchorSelectionIndex and leadSelectionIndex variables
552 //TODO: will probably need MouseDragged to test properly and know if this works
553 setAnchorSelectionIndex(index0);
554 leadSelectionIndex = index1;
555
556 fireDifference(sel, (BitSet) oldSel);
557 }
558
559 /**
560 * Removes all intervals in the selection set.
561 */
562 public void clearSelection()
563 {
564 // Find the selected interval.
565 int from = sel.nextSetBit(0);
566 if (from < 0)
567 return; // Empty selection - nothing to do.
568 int to = from;
569
570 int i;
571
572 for (i = from; i>=0; i=sel.nextSetBit(i+1))
573 to = i;
574
575 sel.clear();
576 fireValueChanged(from, to, valueIsAdjusting);
577 }
578
579 /**
580 * Fire the change event, covering the difference between the two sets.
581 *
582 * @param current the current set
583 * @param x the previous set, the object will be reused.
584 */
585 private void fireDifference(BitSet current, BitSet x)
586 {
587 x.xor(current);
588 int from = x.nextSetBit(0);
589 if (from < 0)
590 return; // No difference.
591 int to = from;
592 int i;
593
594 for (i = from; i >= 0; i = x.nextSetBit(i+1))
595 to = i;
596
597 fireValueChanged(from, to, valueIsAdjusting);
598 }
599
600 /**
601 * Clears the current selection and marks a given interval as "selected". If
602 * the current selection mode is <code>SINGLE_SELECTION</code> only the
603 * index <code>index2</code> is selected.
604 *
605 * @param anchor the anchor selection index.
606 * @param lead the lead selection index.
607 */
608 public void setSelectionInterval(int anchor, int lead)
609 {
610 if (anchor == -1 || lead == -1)
611 return;
612 if (selectionMode == SINGLE_SELECTION)
613 {
614 int lo = lead;
615 int hi = lead;
616 int selected = sel.nextSetBit(0);
617 if (selected == lead)
618 return; // the selection is not changing
619 if (selected >= 0)
620 {
621 lo = Math.min(lo, selected);
622 hi = Math.max(hi, selected);
623 }
624 if (anchorSelectionIndex >= 0)
625 {
626 lo = Math.min(lo, anchorSelectionIndex);
627 hi = Math.max(hi, anchorSelectionIndex);
628 }
629 sel.clear();
630 sel.set(lead);
631 leadSelectionIndex = lead;
632 anchorSelectionIndex = lead;
633 fireValueChanged(lo, hi);
634 }
635 else if (selectionMode == SINGLE_INTERVAL_SELECTION)
636 {
637 // determine the current interval
638 int first = sel.nextSetBit(0);
639 int last = first;
640 if (first >= 0)
641 last += (sel.cardinality() - 1);
642
643 // update the selection
644 int lo = Math.min(anchor, lead);
645 int hi = Math.max(anchor, lead);
646 if (lo == first && hi == last)
647 return; // selected interval is not being changed
648 sel.clear();
649 sel.set(lo, hi + 1);
650
651 // include the old selection in the event range
652 if (first >= 0)
653 lo = Math.min(lo, first);
654 if (last >= 0)
655 hi = Math.max(hi, last);
656 if (anchorSelectionIndex >= 0)
657 {
658 lo = Math.min(lo, anchorSelectionIndex);
659 hi = Math.max(hi, anchorSelectionIndex);
660 }
661 anchorSelectionIndex = anchor;
662 leadSelectionIndex = lead;
663 fireValueChanged(lo, hi);
664 }
665 else
666 {
667 BitSet oldSel = (BitSet) sel.clone();
668 sel.clear();
669 if (selectionMode == SINGLE_SELECTION)
670 anchor = lead;
671
672 int lo = Math.min(anchor, lead);
673 int hi = Math.max(anchor, lead);
674 sel.set(lo, hi+1);
675 // update the anchorSelectionIndex and leadSelectionIndex variables
676 setAnchorSelectionIndex(anchor);
677 leadSelectionIndex = lead;
678
679 fireDifference(sel, oldSel);
680 }
681 }
682
683 /**
684 * Inserts a number of indices either before or after a particular
685 * position in the set of indices. Renumbers all indices after the
686 * inserted range. The new indices in the inserted range are not
687 * selected. This method is typically called to synchronize the selection
688 * model with an inserted range of elements in a {@link ListModel}.
689 *
690 * @param index The position to insert indices at
691 * @param length The number of indices to insert
692 * @param before Indicates whether to insert the indices before the index
693 * or after it
694 */
695 public void insertIndexInterval(int index,
696 int length,
697 boolean before)
698 {
699 if (!before)
700 {
701 index++;
702 length--;
703 }
704 BitSet tmp = sel.get(index, sel.size());
705 sel.clear(index, sel.size());
706 int n = tmp.size();
707 for (int i = 0; i < n; ++i)
708 sel.set(index + length + i, tmp.get(i));
709 }
710
711 /**
712 * Removes a range from the set of indices. Renumbers all indices after
713 * the removed range. This method is typically called to synchronize the
714 * selection model with a deleted range of elements in a {@link
715 * ListModel}.
716 *
717 * @param index0 The first index to remove (inclusive)
718 * @param index1 The last index to remove (inclusive)
719 */
720 public void removeIndexInterval(int index0,
721 int index1)
722 {
723 int lo = Math.min(index0, index1);
724 int hi = Math.max(index0, index1);
725
726 BitSet tmp = sel.get(hi, sel.size());
727 sel.clear(lo, sel.size());
728 int n = tmp.size();
729 for (int i = 0; i < n; ++i)
730 sel.set(lo + i, tmp.get(i));
731 }
732
733 /**
734 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
735 * ListSelectionListener} registered with this selection model to
736 * indicate that a series of adjustment has just ended.
737 *
738 * The values of {@link #getMinSelectionIndex} and
739 * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
740 * that gets fired.
741 *
742 * @param isAdjusting <code>true</code> if this is the final change
743 * in a series of adjustments, <code>false/code> otherwise
744 */
745 protected void fireValueChanged(boolean isAdjusting)
746 {
747 fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
748 isAdjusting);
749 }
750
751 /**
752 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
753 * ListSelectionListener} registered with this selection model.
754 *
755 * @param firstIndex The low index of the changed range
756 * @param lastIndex The high index of the changed range
757 */
758 protected void fireValueChanged(int firstIndex, int lastIndex)
759 {
760 fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
761 }
762
763 /**
764 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
765 * ListSelectionListener} registered with this selection model.
766 *
767 * @param firstIndex The low index of the changed range
768 * @param lastIndex The high index of the changed range
769 * @param isAdjusting Whether this change is part of a seqence of adjustments
770 * made to the selection, such as during interactive scrolling
771 */
772 protected void fireValueChanged(int firstIndex, int lastIndex,
773 boolean isAdjusting)
774 {
775 ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
776 lastIndex, isAdjusting);
777 ListSelectionListener[] listeners = getListSelectionListeners();
778 for (int i = 0; i < listeners.length; ++i)
779 listeners[i].valueChanged(evt);
780 }
781
782 /**
783 * Adds a listener.
784 *
785 * @param listener The listener to add
786 *
787 * @see #removeListSelectionListener
788 * @see #getListSelectionListeners
789 */
790 public void addListSelectionListener(ListSelectionListener listener)
791 {
792 listenerList.add(ListSelectionListener.class, listener);
793 }
794
795 /**
796 * Removes a registered listener.
797 *
798 * @param listener The listener to remove
799 *
800 * @see #addListSelectionListener
801 * @see #getListSelectionListeners
802 */
803 public void removeListSelectionListener(ListSelectionListener listener)
804 {
805 listenerList.remove(ListSelectionListener.class, listener);
806 }
807
808 /**
809 * Returns an array of all registerers listeners.
810 *
811 * @param listenerType The type of listener to retrieve
812 *
813 * @return The array
814 *
815 * @see #getListSelectionListeners
816 * @since 1.3
817 */
818 public <T extends EventListener> T[] getListeners(Class<T> listenerType)
819 {
820 return listenerList.getListeners(listenerType);
821 }
822
823 /**
824 * Returns an array of all registerd list selection listeners.
825 *
826 * @return the array
827 *
828 * @see #addListSelectionListener
829 * @see #removeListSelectionListener
830 * @see #getListeners
831 * @since 1.4
832 */
833 public ListSelectionListener[] getListSelectionListeners()
834 {
835 return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
836 }
837
838 /**
839 * Returns a clone of this object.
840 * <code>listenerList</code> don't gets duplicated.
841 *
842 * @return the cloned object
843 *
844 * @throws CloneNotSupportedException if an error occurs
845 */
846 public Object clone()
847 throws CloneNotSupportedException
848 {
849 DefaultListSelectionModel model =
850 (DefaultListSelectionModel) super.clone();
851 model.sel = (BitSet) sel.clone();
852 model.listenerList = new EventListenerList();
853 return model;
854 }
855 }