Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / swing / DefaultListSelectionModel.java
blobce1dfdd79c59aff3360e22549f43193306851cc3
1 /* DefaultListSelectionModel.java --
2 Copyright (C) 2002, 2004, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 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 * The default implementation of {@link ListSelectionModel},
51 * which is used by {@link javax.swing.JList} and
52 * similar classes to manage the selection status of a number of data
53 * elements.
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;
81 /**
82 * The index of the "lead" of the most recent selection. The lead is the
83 * second argument in any call to {@link #setSelectionInterval}, {@link
84 * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally
85 * the lead refers to the most recent position a user dragged their mouse
86 * over.
88 int leadSelectionIndex = -1;
90 /**
91 * The index of the "anchor" of the most recent selection. The anchor is
92 * the first argument in any call to {@link #setSelectionInterval},
93 * {@link #addSelectionInterval} or {@link
94 * #removeSelectionInterval}. Generally the anchor refers to the first
95 * recent position a user clicks when they begin to drag their mouse over
96 * a list.
98 * @see #getAnchorSelectionIndex
99 * @see #setAnchorSelectionIndex
101 int anchorSelectionIndex = -1;
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>.
115 * @see #isLeadAnchorNotificationEnabled
116 * @see #setLeadAnchorNotificationEnabled
118 protected boolean leadAnchorNotificationEnabled = true;
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.
126 * @see #getValueIsAdjusting
127 * @see #setValueIsAdjusting
129 boolean valueIsAdjusting = false;
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.
137 BitSet sel = new BitSet();
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.
144 Object oldSel;
147 * Whether this call of setLeadSelectionInterval was called locally
148 * from addSelectionInterval
150 boolean setLeadCalledFromAdd = false;
153 * Gets the value of the {@link #selectionMode} property.
155 * @return The current value of the property
157 public int getSelectionMode()
159 return selectionMode;
163 * Sets the value of the {@link #selectionMode} property.
165 * @param a The new value of the property
167 public void setSelectionMode(int a)
169 selectionMode = a;
173 * Gets the value of the {@link #anchorSelectionIndex} property.
175 * @return The current property value
177 * @see #setAnchorSelectionIndex
179 public int getAnchorSelectionIndex()
181 return anchorSelectionIndex;
185 * Sets the value of the {@link #anchorSelectionIndex} property.
187 * @param anchorIndex The new property value
189 * @see #getAnchorSelectionIndex
191 public void setAnchorSelectionIndex(int anchorIndex)
193 anchorSelectionIndex = anchorIndex;
197 * Gets the value of the {@link #leadSelectionIndex} property.
199 * @return The current property value
201 * @see #setLeadSelectionIndex
203 public int getLeadSelectionIndex()
205 return leadSelectionIndex;
209 * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a
210 * side effect, alters the selection status of two ranges of indices. Let
211 * <code>OL</code> be the old lead selection index, <code>NL</code> be
212 * the new lead selection index, and <code>A</code> be the anchor
213 * selection index. Then if <code>A</code> is a valid selection index,
214 * one of two things happens depending on the seleciton status of
215 * <code>A</code>:</p>
217 * <ul>
219 * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code>
220 * to <em>deselected</em>, then set <code>[A,NL]</code> to
221 * <em>selected</em>.</li>
223 * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code>
224 * to <em>selected</em>, then set <code>[A,NL]</code> to
225 * <em>deselected</em>.</li>
227 * </ul>
229 * <p>This method generates at most a single {@link ListSelectionEvent}
230 * despite changing multiple ranges. The range of values provided to the
231 * {@link ListSelectionEvent} includes only the minimum range of values
232 * which changed selection status between the beginning and end of the
233 * method.</p>
235 * @param leadIndex The new property value
237 * @see #getAnchorSelectionIndex
239 public void setLeadSelectionIndex(int leadIndex)
241 // Only set the lead selection index to < 0 if anchorSelectionIndex < 0.
242 if (leadIndex < 0)
244 if (anchorSelectionIndex < 0)
245 leadSelectionIndex = -1;
246 else
247 return;
250 // Only touch the lead selection index if the anchor is >= 0.
251 if (anchorSelectionIndex < 0)
252 return;
254 if (selectionMode == SINGLE_SELECTION)
255 setSelectionInterval (leadIndex, leadIndex);
257 int oldLeadIndex = leadSelectionIndex;
258 if (oldLeadIndex == -1)
259 oldLeadIndex = leadIndex;
260 if (setLeadCalledFromAdd == false)
261 oldSel = sel.clone();
262 leadSelectionIndex = leadIndex;
264 if (anchorSelectionIndex == -1)
265 return;
267 int R1 = Math.min(anchorSelectionIndex, oldLeadIndex);
268 int R2 = Math.max(anchorSelectionIndex, oldLeadIndex);
269 int S1 = Math.min(anchorSelectionIndex, leadIndex);
270 int S2 = Math.max(anchorSelectionIndex, leadIndex);
272 int lo = Math.min(R1, S1);
273 int hi = Math.max(R2, S2);
275 if (isSelectedIndex(anchorSelectionIndex))
277 sel.clear(R1, R2+1);
278 sel.set(S1, S2+1);
280 else
282 sel.set(R1, R2+1);
283 sel.clear(S1, S2+1);
286 int beg = sel.nextSetBit(0), end = -1;
287 for(int i=beg; i >= 0; i=sel.nextSetBit(i+1))
288 end = i;
289 if (sel.equals(oldSel) == false)
290 fireValueChanged(beg, end, valueIsAdjusting);
294 * Moves the lead selection index to <code>leadIndex</code> without
295 * changing the selection values.
297 * If leadAnchorNotificationEnabled is true, send a notification covering the
298 * old and new lead cells.
300 * @param leadIndex the new lead selection index
301 * @since 1.5
303 public void moveLeadSelectionIndex (int leadIndex)
305 if (leadSelectionIndex == leadIndex)
306 return;
308 leadSelectionIndex = leadIndex;
309 if (isLeadAnchorNotificationEnabled())
310 fireValueChanged(Math.min(leadSelectionIndex, leadIndex),
311 Math.max(leadSelectionIndex, leadIndex));
315 * Gets the value of the {@link #leadAnchorNotificationEnabled} property.
317 * @return The current property value
319 * @see #setLeadAnchorNotificationEnabled
321 public boolean isLeadAnchorNotificationEnabled()
323 return leadAnchorNotificationEnabled;
327 * Sets the value of the {@link #leadAnchorNotificationEnabled} property.
329 * @param l The new property value
331 * @see #isLeadAnchorNotificationEnabled
333 public void setLeadAnchorNotificationEnabled(boolean l)
335 leadAnchorNotificationEnabled = l;
339 * Gets the value of the {@link #valueIsAdjusting} property.
341 * @return The current property value
343 * @see #setValueIsAdjusting
345 public boolean getValueIsAdjusting()
347 return valueIsAdjusting;
351 * Sets the value of the {@link #valueIsAdjusting} property.
353 * @param v The new property value
355 * @see #getValueIsAdjusting
357 public void setValueIsAdjusting(boolean v)
359 valueIsAdjusting = v;
363 * Determines whether the selection is empty.
365 * @return <code>true</code> if the selection is empty, otherwise
366 * <code>false</code>
368 public boolean isSelectionEmpty()
370 return sel.isEmpty();
374 * Gets the smallest index which is currently a member of a selection
375 * interval.
377 * @return The least integer <code>i</code> such that <code>i >=
378 * 0</code> and <code>i</code> is a member of a selected interval, or
379 * <code>-1</code> if there are no selected intervals
381 * @see #getMaxSelectionIndex
383 public int getMinSelectionIndex()
385 if (isSelectionEmpty())
386 return -1;
388 return sel.nextSetBit(0);
392 * Gets the largest index which is currently a member of a selection
393 * interval.
395 * @return The greatest integer <code>i</code> such that <code>i >=
396 * 0</code> and <code>i</code> is a member of a selected interval, or
397 * <code>-1</code> if there are no selected intervals
399 * @see #getMinSelectionIndex
401 public int getMaxSelectionIndex()
403 if (isSelectionEmpty())
404 return -1;
406 int mx = -1;
407 for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1))
409 mx = i;
411 return mx;
415 * Determines whether a particular index is a member of a selection
416 * interval.
418 * @param a The index to search for
420 * @return <code>true</code> if the index is a member of a selection interval,
421 * otherwise <code>false</code>
423 public boolean isSelectedIndex(int a)
425 // TODO: Probably throw an exception here?
426 if (a >= sel.length() || a < 0)
427 return false;
428 return sel.get(a);
432 * If the {@link #selectionMode} property is equal to
433 * <code>SINGLE_SELECTION</code> equivalent to calling
434 * <code>setSelectionInterval(index1, index2)</code>;
435 * If the {@link #selectionMode} property is equal to
436 * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being
437 * added is not adjacent to an already selected interval,
438 * equivalent to <code>setSelectionInterval(index1, index2)</code>.
439 * Otherwise adds the range <code>[index0, index1]</code>
440 * to the selection interval set.
442 * @param index0 The beginning of the range of indices to select
443 * @param index1 The end of the range of indices to select
445 * @see #setSelectionInterval
446 * @see #removeSelectionInterval
448 public void addSelectionInterval(int index0, int index1)
450 int lo = Math.min(index0, index1);
451 int hi = Math.max(index0, index1);
452 oldSel = sel.clone();
454 if (selectionMode == SINGLE_SELECTION)
455 setSelectionInterval(index0, index1);
457 // COMPAT: Like Sun (but not like IBM), we allow calls to
458 // addSelectionInterval when selectionMode is
459 // SINGLE_SELECTION_INTERVAL iff the interval being added
460 // is adjacent to an already selected interval
461 if (selectionMode == SINGLE_INTERVAL_SELECTION)
462 if (!(isSelectedIndex(index0) ||
463 isSelectedIndex(index1) ||
464 isSelectedIndex(Math.max(lo-1,0)) ||
465 isSelectedIndex(Math.min(hi+1,sel.size()))))
466 sel.clear();
468 // We have to update the anchorSelectionIndex and leadSelectionIndex
469 // variables
471 // The next if statements breaks down to "if this selection is adjacent
472 // to the previous selection and going in the same direction"
473 if ((isSelectedIndex(leadSelectionIndex))
474 && ((index0 - 1 == leadSelectionIndex
475 && (index1 >= index0)
476 && (leadSelectionIndex >= anchorSelectionIndex))
477 || (index0 + 1 == leadSelectionIndex && (index1 <= index0)
478 && (leadSelectionIndex <= anchorSelectionIndex)))
479 && (anchorSelectionIndex != -1 || leadSelectionIndex != -1))
481 // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex
482 // not to update oldSel
483 setLeadCalledFromAdd = true;
484 setLeadSelectionIndex(index1);
485 setLeadCalledFromAdd = false;
487 else
489 leadSelectionIndex = index1;
490 anchorSelectionIndex = index0;
491 sel.set(lo, hi+1);
492 if (sel.equals(oldSel) == false)
493 fireValueChanged(lo, hi, valueIsAdjusting);
499 * Deselects all indices in the inclusive range
500 * <code>[index0,index1]</code>.
502 * @param index0 The beginning of the range of indices to deselect
503 * @param index1 The end of the range of indices to deselect
505 * @see #addSelectionInterval
506 * @see #setSelectionInterval
508 public void removeSelectionInterval(int index0,
509 int index1)
511 oldSel = sel.clone();
512 int lo = Math.min(index0, index1);
513 int hi = Math.max(index0, index1);
515 // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval
516 // (index0,index1) would leave two disjoint selection intervals, remove all
517 // selected indices from lo to the last selected index
518 if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo &&
519 selectionMode == SINGLE_INTERVAL_SELECTION)
520 hi = sel.size() - 1;
522 sel.clear(lo, hi+1);
523 //update anchorSelectionIndex and leadSelectionIndex variables
524 //TODO: will probably need MouseDragged to test properly and know if this works
525 setAnchorSelectionIndex(index0);
526 leadSelectionIndex = index1;
527 if (sel.equals(oldSel) == false)
528 fireValueChanged(lo, hi, valueIsAdjusting);
532 * Removes all intervals in the selection set.
534 public void clearSelection()
536 oldSel = sel.clone();
537 int sz = sel.size();
538 sel.clear();
539 if (sel.equals(oldSel) == false)
540 fireValueChanged(0, sz, valueIsAdjusting);
544 * Clears the current selection and marks a given interval as
545 * "selected". If the current selection mode is
546 * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is
547 * selected.
549 * @param index0 The low end of the new selection
550 * @param index1 The high end of the new selection
552 public void setSelectionInterval(int index0, int index1)
554 oldSel = sel.clone();
555 sel.clear();
556 if (selectionMode == SINGLE_SELECTION)
557 index0 = index1;
559 int lo = Math.min(index0, index1);
560 int hi = Math.max(index0, index1);
561 sel.set(lo, hi+1);
562 // update the anchorSelectionIndex and leadSelectionIndex variables
563 setAnchorSelectionIndex(index0);
564 leadSelectionIndex=index1;
565 if (sel.equals(oldSel) == false)
566 fireValueChanged(lo, hi, valueIsAdjusting);
570 * Inserts a number of indices either before or after a particular
571 * position in the set of indices. Renumbers all indices after the
572 * inserted range. The new indices in the inserted range are not
573 * selected. This method is typically called to synchronize the selection
574 * model with an inserted range of elements in a {@link ListModel}.
576 * @param index The position to insert indices at
577 * @param length The number of indices to insert
578 * @param before Indicates whether to insert the indices before the index
579 * or after it
581 public void insertIndexInterval(int index,
582 int length,
583 boolean before)
585 if (!before)
587 index++;
588 length--;
590 BitSet tmp = sel.get(index, sel.size());
591 sel.clear(index, sel.size());
592 int n = tmp.size();
593 for (int i = 0; i < n; ++i)
594 sel.set(index + length + i, tmp.get(i));
598 * Removes a range from the set of indices. Renumbers all indices after
599 * the removed range. This method is typically called to synchronize the
600 * selection model with a deleted range of elements in a {@link
601 * ListModel}.
603 * @param index0 The first index to remove (inclusive)
604 * @param index1 The last index to remove (inclusive)
606 public void removeIndexInterval(int index0,
607 int index1)
609 int lo = Math.min(index0, index1);
610 int hi = Math.max(index0, index1);
612 BitSet tmp = sel.get(hi, sel.size());
613 sel.clear(lo, sel.size());
614 int n = tmp.size();
615 for (int i = 0; i < n; ++i)
616 sel.set(lo + i, tmp.get(i));
620 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
621 * ListSelectionListener} registered with this selection model to
622 * indicate that a series of adjustment has just ended.
624 * The values of {@link #getMinSelectionIndex} and
625 * {@link #getMaxSelectionIndex} are used in the {@link ListSelectionEvent}
626 * that gets fired.
628 * @param isAdjusting <code>true</code> if this is the final change
629 * in a series of adjustments, <code>false/code> otherwise
631 protected void fireValueChanged(boolean isAdjusting)
633 fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(),
634 isAdjusting);
638 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
639 * ListSelectionListener} registered with this selection model.
641 * @param firstIndex The low index of the changed range
642 * @param lastIndex The high index of the changed range
644 protected void fireValueChanged(int firstIndex, int lastIndex)
646 fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
650 * Fires a {@link ListSelectionEvent} to all the listeners of type {@link
651 * ListSelectionListener} registered with this selection model.
653 * @param firstIndex The low index of the changed range
654 * @param lastIndex The high index of the changed range
655 * @param isAdjusting Whether this change is part of a seqence of adjustments
656 * made to the selection, such as during interactive scrolling
658 protected void fireValueChanged(int firstIndex, int lastIndex,
659 boolean isAdjusting)
661 ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex,
662 lastIndex, isAdjusting);
663 ListSelectionListener[] listeners = getListSelectionListeners();
664 for (int i = 0; i < listeners.length; ++i)
665 listeners[i].valueChanged(evt);
669 * Adds a listener.
671 * @param listener The listener to add
673 * @see #removeListSelectionListener
674 * @see #getListSelectionListeners
676 public void addListSelectionListener(ListSelectionListener listener)
678 listenerList.add(ListSelectionListener.class, listener);
682 * Removes a registered listener.
684 * @param listener The listener to remove
686 * @see #addListSelectionListener
687 * @see #getListSelectionListeners
689 public void removeListSelectionListener(ListSelectionListener listener)
691 listenerList.remove(ListSelectionListener.class, listener);
695 * Returns an array of all registerers listeners.
697 * @param listenerType The type of listener to retrieve
699 * @return The array
701 * @see #getListSelectionListeners
702 * @since 1.3
704 public EventListener[] getListeners(Class listenerType)
706 return listenerList.getListeners(listenerType);
710 * Returns an array of all registerd list selection listeners.
712 * @return the array
714 * @see #addListSelectionListener
715 * @see #removeListSelectionListener
716 * @see #getListeners
717 * @since 1.4
719 public ListSelectionListener[] getListSelectionListeners()
721 return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
725 * Returns a clone of this object.
726 * <code>listenerList</code> don't gets duplicated.
728 * @return the cloned object
730 * @throws CloneNotSupportedException if an error occurs
732 public Object clone()
733 throws CloneNotSupportedException
735 DefaultListSelectionModel model =
736 (DefaultListSelectionModel) super.clone();
737 model.sel = (BitSet) sel.clone();
738 return model;