Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / javax / swing / DefaultListSelectionModel.java
blobccae2804c3d98376474c8051f11986e3b4087c02
1 /* DefaultListSelectionModel.java --
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing;
41 import java.io.Serializable;
42 import java.util.BitSet;
43 import java.util.EventListener;
45 import javax.swing.event.EventListenerList;
46 import javax.swing.event.ListSelectionEvent;
47 import javax.swing.event.ListSelectionListener;
49 /**
50 * <p>This class provides a default implementation of {@link
51 * ListSelectioModel}, which is used by {@link javax.swing.JList} and
52 * similar classes to manage the selection status of a number of data
53 * elements. </p>
55 * <p>The class is organized <em>abstractly</em> as a set of intervals of
56 * integers. Each interval indicates an inclusive range of indices in a
57 * list -- held by some other object and unknown to this class -- which is
58 * considered "selected". There are various accessors for querying and
59 * modifying the set of intervals, with simplified forms accepting a single
60 * index, representing an interval with only one element. </p>
62 public class DefaultListSelectionModel implements Cloneable,
63 ListSelectionModel,
64 Serializable
66 private static final long serialVersionUID = -5718799865110415860L;
68 /** The list of ListSelectionListeners subscribed to this selection model. */
69 protected EventListenerList listenerList = new EventListenerList();
72 /**
73 * The current list selection mode. Must be one of the numeric constants
74 * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>
75 * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link
76 * ListSelectionModel}. The default value is
77 * <code>MULTIPLE_INTERVAL_SELECTION</code>.
79 int selectionMode = MULTIPLE_INTERVAL_SELECTION;
82 /**
83 * The index of the "lead" of the most recent selection. The lead is the
84 * second argument in any call to {@link #setSelectionInterval}, {@link
85 * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
86 * the lead refers to the most recent position a user dragged their mouse
87 * over.
89 int leadSelectionIndex = -1;
92 /**
93 * The index of the "anchor" of the most recent selection. The anchor is
94 * the first argument in any call to {@link #setSelectionInterval},
95 * {@link #addSelectionInterval} or {@link
96 * #removeSelectionInterval}. Generally the anchor refers to the first
97 * recent position a user clicks when they begin to drag their mouse over
98 * a list.
100 * @see #getAnchorSelectionIndex
101 * @see #setAnchorSelectionIndex
103 int anchorSelectionIndex = -1;
107 * controls the range of indices provided in any {@link
108 * ListSelectionEvent} fired by the selectionModel. Let
109 * <code>[A,L]</code> be the range of indices between {@link
110 * anchorSelectionIndex} and {@link leadSelectionIndex} inclusive, and
111 * let <code>[i0,i1]</code> be the range of indices changed in a given
112 * call which generates a {@link ListSelectionEvent}. Then when this
113 * property is <code>true</code>, the {@link ListSelectionEvent} contains
114 * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it
115 * will contain only <code>[i0,i1]</code>. The default is
116 * <code>true</code>.
118 * @see #isLeadAnchorNotificationEnabled
119 * @see #setLeadAnchorNotificationEnabled
121 protected boolean leadAnchorNotificationEnabled = true;
125 * Whether the selection is currently "adjusting". Any {@link
126 * ListSelectionEvent} events constructed in response to changes in this
127 * list selection model will have their {@link
128 * ListSelectionEvent#isAdjusting} field set to this value.
130 * @see #getValueIsAdjusting
131 * @see #setValueIsAdjusting
133 boolean valueIsAdjusting = false;
136 /**
137 * The current set of "intervals", represented simply by a {@link
138 * java.util.BitSet}. A set bit indicates a selected index, whereas a
139 * cleared bit indicates a non-selected index.
141 BitSet sel = new BitSet();
145 * Gets the value of the {@link #selectionMode} property.
147 * @return The current value of the property
149 public int getSelectionMode()
151 return selectionMode;
155 * Sets the value of the {@link #selectionMode} property.
157 * @param a The new value of the property
159 public void setSelectionMode(int a)
161 selectionMode = a;
165 * Gets the value of the {@link #anchorSelectionIndex} property.
167 * @return The current property value
169 * @see #setAnchorSelectionIndex
171 public int getAnchorSelectionIndex()
173 return anchorSelectionIndex;
177 * Sets the value of the {@link #anchorSelectionIndex} property.
179 * @param anchorIndex The new property value
181 * @see #getAnchorSelectionIndex
183 public void setAnchorSelectionIndex(int anchorIndex)
185 anchorSelectionIndex = anchorIndex;
189 * Gets the value of the {@link #leadSelectionIndex} property.
191 * @return The current property value
193 * @see #setLeadSelectionIndex
195 public int getLeadSelectionIndex()
197 return leadSelectionIndex;
201 * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
202 * side effect, alters the selection status of two ranges of indices. Let
203 * <code>OL</code> be the old lead selection index, <code>NL</code> be
204 * the new lead selection index, and <code>A</code> be the anchor
205 * selection index. Then if <code>A</code> is a valid selection index,
206 * one of two things happens depending on the seleciton status of
207 * <code>A</code>:</p>
209 * <ul>
211 * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
212 * to <em>deselected</em>, then set <code>[A,NL]</code> to
213 * <em>selected</em>.</li>
215 * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
216 * to <em>selected</em>, then set <code>[A,NL]</code> to
217 * <em>deselected</em>.</li>
219 * </ul>
221 * <p>This method generates at most a single {@link ListSelectionEvent}
222 * despite changing multiple ranges. The range of values provided to the
223 * {@link ListSelectionEvent} includes only the minimum range of values
224 * which changed selection status between the beginning and end of the
225 * method.</p>
227 * @param anchorIndex The new property value
229 * @see #getAnchorSelectionIndex
231 public void setLeadSelectionIndex(int leadIndex)
233 int oldLeadIndex = leadSelectionIndex;
234 leadSelectionIndex = leadIndex;
236 if (anchorSelectionIndex == -1)
237 return;
239 int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
240 int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
241 int S1 = Math.min(anchorSelectionIndex, leadIndex);
242 int S2 = Math.max(anchorSelectionIndex, leadIndex);
244 int lo = Math.min(R1, S1);
245 int hi = Math.max(R2, S2);
247 BitSet oldRange = sel.get(lo, hi+1);
249 if (isSelectedIndex(anchorSelectionIndex))
251 sel.clear(R1, R2+1);
252 sel.set(S1, S2+1);
254 else
256 sel.set(R1, R2+1);
257 sel.clear(S1, S2+1);
260 BitSet newRange = sel.get(lo, hi+1);
261 newRange.xor(oldRange);
263 int beg = sel.nextSetBit(0), end = -1;
264 for(int i=beg; i >= 0; i=sel.nextSetBit(i+1))
266 end = i;
268 fireValueChanged(beg, end, valueIsAdjusting);
272 * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
274 * @return The current property value
276 * @see #setLeadAnchorNotificationEnabled
278 public boolean isLeadAnchorNotificationEnabled()
280 return leadAnchorNotificationEnabled;
284 * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
286 * @param flag The new property value
288 * @see #getLeadAnchorNotificationEnabled
290 public void setLeadAnchorNotificationEnabled(boolean l)
292 leadAnchorNotificationEnabled = l;
297 * Gets the value of the {@link #valueIsAdjusting} property.
299 * @return The current property value
301 * @see #setValueIsAdjusting
303 public boolean getValueIsAdjusting()
305 return valueIsAdjusting;
309 * Sets the value of the {@link #valueIsAdjusting} property.
311 * @param v The new property value
313 * @see #getValueIsAdjusting
315 public void setValueIsAdjusting(boolean v)
317 valueIsAdjusting = v;
321 * Determines whether the selection is empty.
323 * @return <code>true</code> if the selection is empty, otherwise
324 * <code>false</code>
326 public boolean isSelectionEmpty()
328 return sel.isEmpty();
333 * Gets the smallest index which is currently a member of a selection
334 * interval.
336 * @return The least integer <code>i</code> such that <code>i >=
337 * 0</code> and <code>i</code> is a member of a selected interval, or
338 * <code>-1</code> if there are no selected intervals
340 * @see #getMaxSelectionIndex
342 public int getMinSelectionIndex()
344 if (isSelectionEmpty())
345 return -1;
347 return sel.nextSetBit(0);
351 * Gets the largest index which is currently a member of a selection
352 * interval.
354 * @return The greatest integer <code>i</code> such that <code>i >=
355 * 0</code> and <code>i</code> is a member of a selected interval, or
356 * <code>-1</code> if there are no selected intervals
358 * @see #getMinSelectionIndex
360 public int getMaxSelectionIndex()
362 if (isSelectionEmpty())
363 return -1;
365 int mx = -1;
366 for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1))
368 mx = i;
370 return mx;
374 * Determines whether a particular index is a member of a selection
375 * interval.
377 * @param a The index to search for
379 * @return <code>true</code> if the index is a member of a selection interval,
380 * otherwise <code>false</code>
382 public boolean isSelectedIndex(int a)
384 return sel.get(a);
388 * If the {@link #selectionMode} property is equal to
389 * <code>SINGLE_SELECTION</code> or
390 * <code>SINGLE_INTERVAL_SELECTION</code>, equivalent to calling
391 * <code>setSelectionInterval(index1, index2)</code>; otherwise adds the
392 * range <code>[index0, index1]</code> to the selection interval set.
394 * @param index0 The beginning of the range of indices to select
395 * @param index1 The end of the range of indices to select
397 * @see #setSelectionInterval
398 * @see #removeSelectionInterval
400 public void addSelectionInterval(int index0, int index1)
402 if (selectionMode == SINGLE_SELECTION
403 || selectionMode == SINGLE_INTERVAL_SELECTION)
404 sel.clear();
406 if (selectionMode == SINGLE_SELECTION)
407 index0 = index1;
409 int lo = Math.min(index0, index1);
410 int hi = Math.max(index0, index1);
412 sel.set(lo, hi+1);
413 fireValueChanged(lo, hi, valueIsAdjusting);
418 * Deselects all indices in the inclusive range
419 * <code>[index0,index1]</code>.
421 * @param index0 The beginning of the range of indices to deselect
422 * @param index1 The end of the range of indices to deselect
424 * @see #addSelectionInterval
425 * @see #setSelectionInterval
427 public void removeSelectionInterval(int index0,
428 int index1)
430 int lo = Math.min(index0, index1);
431 int hi = Math.max(index0, index1);
432 sel.clear(lo, hi+1);
433 fireValueChanged(lo, hi, valueIsAdjusting);
437 * Removes all intervals in the selection set.
439 public void clearSelection()
441 int sz = sel.size();
442 sel.clear();
443 fireValueChanged(0, sz, valueIsAdjusting);
447 * Clears the current selection and marks a given interval as
448 * "selected". If the current selection mode is
449 * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is
450 * selected.
452 * @param index0 The low end of the new selection
453 * @param index1 The high end of the new selection
455 public void setSelectionInterval(int index0, int index1)
457 sel.clear();
458 if (selectionMode == SINGLE_SELECTION)
459 index0 = index1;
461 int lo = Math.min(index0, index1);
462 int hi = Math.max(index0, index1);
463 sel.set(lo, hi+1);
464 fireValueChanged(lo, hi, valueIsAdjusting);
468 * Inserts a number of indices either before or after a particular
469 * position in the set of indices. Renumbers all indices after the
470 * inserted range. The new indices in the inserted range are not
471 * selected. This method is typically called to synchronize the selection
472 * model with an inserted range of elements in a {@link ListModel}.
474 * @param index The position to insert indices at
475 * @param length The number of indices to insert
476 * @param before Indicates whether to insert the indices before the index
477 * or after it
479 public void insertIndexInterval(int index,
480 int length,
481 boolean before)
483 if (!before)
485 index++;
486 length--;
488 BitSet tmp = sel.get(index, sel.size());
489 sel.clear(index, sel.size());
490 int n = tmp.size();
491 for (int i = 0; i < n; ++i)
492 sel.set(index + length + i, tmp.get(i));
496 * Removes a range from the set of indices. Renumbers all indices after
497 * the removed range. This method is typically called to synchronize the
498 * selection model with a deleted range of elements in a {@link
499 * ListModel}.
501 * @param index0 The first index to remove (inclusive)
502 * @param index1 The last index to remove (inclusive)
504 public void removeIndexInterval(int index0,
505 int index1)
507 int lo = Math.min(index0, index1);
508 int hi = Math.max(index0, index1);
510 BitSet tmp = sel.get(hi, sel.size());
511 sel.clear(lo, sel.size());
512 int n = tmp.size();
513 for (int i = 0; i < n; ++i)
514 sel.set(lo + i, tmp.get(i));
518 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
519 * ListSelectionListener} registered with this selection model.
521 * @param firstIndex The low index of the changed range
522 * @param lastIndex The high index of the changed range
524 protected void fireValueChanged(int firstIndex, int lastIndex)
526 fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
530 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
531 * ListSelectionListener} registered with this selection model.
533 * @param firstIndex The low index of the changed range
534 * @param lastIndex The high index of the changed range
535 * @param isAdjusting Whether this change is part of a seqence of adjustments
536 * made to the selection, such as during interactive scrolling
538 protected void fireValueChanged(int firstIndex, int lastIndex,
539 boolean isAdjusting)
541 ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
542 lastIndex, isAdjusting);
543 ListSelectionListener[] listeners = getListSelectionListeners();
544 for (int i = 0; i < listeners.length; ++i)
545 listeners[i].valueChanged(evt);
549 * Adds a listener.
551 * @param listener The listener to add
553 * @see removeListSelectionListener
554 * @see getListSelectionListeners
556 public void addListSelectionListener(ListSelectionListener listener)
558 listenerList.add(ListSelectionListener.class, listener);
562 * Removes a registered listener.
564 * @param listener The listener to remove
566 * @see addListSelectionListener
567 * @see getListSelectionListeners
569 public void removeListSelectionListener(ListSelectionListener listener)
571 listenerList.remove(ListSelectionListener.class, listener);
575 * Returns an array of all registerers listeners.
577 * @param listenerType The type of listener to retrieve
579 * @return The array
581 * @see getListSelectionListener
582 * @since 1.3
584 public EventListener[] getListeners(Class listenerType)
586 return listenerList.getListeners(listenerType);
590 * Returns an array of all registerd list selection listeners.
592 * @return the array
594 * @see addListSelectionListener
595 * @see removeListSelectionListener
596 * @see getListeners
597 * @since 1.4
599 public ListSelectionListener[] getListSelectionListeners()
601 return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
605 * Returns a clone of this object.
606 * <code>listenerList</code> don't gets duplicated.
608 * @return the cloned object
610 * @throws CloneNotSupportedException if an error occurs
612 public Object clone()
613 throws CloneNotSupportedException
615 DefaultListSelectionModel model =
616 (DefaultListSelectionModel) super.clone();
617 model.sel = (BitSet) sel.clone();
618 return model;