Represents a selection in a List. Provides bound bean properties for
the list, the selection, the selection index, and the selection empty state.
Selection changes fire an event only if the old and new value are not equal.
If you need to compare the identity you can use and observe the selection
index instead of the selection or value.
The SelectionInList uses three ValueModels to hold the list, the selection
and selection index and provides bound bean properties for these models.
You can access, observe and replace these ValueModels. This is useful
to connect a SelectionInList with other ValueModels; for example you can
use the SelectionInList's selection holder as bean channel for a
PresentationModel. See the Binding tutorial classes for examples on how
to connect a SelectionInList with a PresentationModel.
This class also implements the
ListModel
interface that allows
API users to observe fine grained changes in the structure and contents
of the list. Hence instances of this class can be used directly as model of
a JList. If you want to use a SelectionInList with a JComboBox or JTable,
you can convert the SelectionInList to the associated component model
interfaces using the adapter classes
ComboBoxAdapter
and
AbstractTableAdapter
respectively.
These classes are part of the Binding library too.
Unlike the older SelectionInList, the SelectionInList supports only
List
s as content of its List holder. The SelectionInListModel
supports
ListModel
s as content of its ListModel holder.
The SelectionInList and SelectionInListModel differ in how precise
they can fire events about changes to the content and structure of
the underlying List or ListModel content. The SelectionInList
can only report that the List changes completely; this is done by emitting
a PropertyChangeEvent for the
list property. Also,
a
ListDataEvent
is fired that reports a complete change.
The SelectionInListModel reports the same PropertyChangeEvent.
But fine grained changes in the ListModel will be forwarded
as fine grained changes in the content, added and removed elements.
If the List or ListModel content doesn't change at all, or if it always
changes completely, there's no differences between the SelectionInListModel
and the SelectionInList.
But if the list structure or content changes, the ListModel reports more
fine grained events to registered ListDataListeners, which in turn allows
list views to chooser better user interface gestures: for example, a table
with scroll pane may retain the current selection and scroll offset.
An example for the benefit of fine grained ListDataEvents is the asynchronous
transport of list elements from a server to a client. Let's say you transport
the list elements in portions of 10 elements to improve the application's
responsiveness. The user can then work with the SelectionInListModel
as soon as the ListModel gets populated. If at a later time more elements
are added to the ListModel, the SelectionInListModel can retain the selection
index (and selection) and will just report a ListDataEvent about
the interval added. JList, JTable and JComboBox will then just add
the new elements at the end of the list presentation.
If you want to combine List operations and the ListModel change reports,
you may consider using an implementation that combines these two interfaces,
for example
ArrayListModel
or
LinkedListModel
.
This binding library provides some help for firing PropertyChangeEvents
if the old ListModel and new ListModel are equal but not the same.
Class
ExtendedPropertyChangeSupport
allows to permanently or individually check the identity (using
==
) instead of checking the equity (using
#equals
).
Class
Model
uses this extended
property change support. And class
ValueHolder
uses it too
and can be configured to always test the identity.
This class inherits public convenience methods for firing ListDataEvents,
see the methods
#fireContentsChanged
,
#fireIntervalAdded
, and
#fireIntervalRemoved
.
These are automatically invoked if the list holder holds a ListModel
that fires these events. If on the other hand the underlying List or
ListModel does not fire a required ListDataEvent, you can use these
methods to notify presentations about a change. It is recommended
to avoid sending duplicate ListDataEvents; hence check if the underlying
ListModel fires the necessary events or not. Typically an underlying
ListModel will fire the add and remove events; but often it'll lack
an event if the (seletcted) contents has changed. A convenient way to
indicate that change is
#fireSelectedContentsChanged
. See
the tutorial's AlbumManagerModel for an example how to use this feature.
Constraints: The list holder holds instances
of
List
, the selection holder values of type
Object
and the selection index holder of type
Integer
. The selection
index holder must hold non-null index values; however, when firing
an index value change event, both the old and new value may be null.
If the ListModel changes, the underyling ValueModel must fire
a PropertyChangeEvent.
addValueChangeListener
public final void addValueChangeListener(PropertyChangeListener l)
Registers the given PropertyChangeListener with this model.
The listener will be notified if the value has changed.
The PropertyChangeEvents delivered to the listener have the name
set to "value". In other words, the listeners won't get notified
when a PropertyChangeEvent is fired that has a null object as
the name to indicate an arbitrary set of the event source's
properties have changed.
In the rare case, where you want to notify a PropertyChangeListener
even with PropertyChangeEvents that have no property name set,
you can register the listener with #addPropertyChangeListener,
not #addValueChangeListener.
- addValueChangeListener in interface ValueModel
clearSelection
public void clearSelection()
Clears the selection of this SelectionInList - if any.
fireSelectedContentsChanged
public void fireSelectedContentsChanged()
Notifies all registered ListDataListeners that the contents
of the selected list item - if any - has changed.
Useful to update a presentation after editing the selection.
See the tutorial's AlbumManagerModel for an example how to use
this feature.
If the list holder holds a ListModel, this SelectionInList listens
to ListDataEvents fired by that ListModel, and forwards these events
by invoking the associated
#fireXXX
method, which in turn
notifies all registered ListDataListeners. Therefore if you fire
ListDataEvents in an underlying ListModel, you don't need this method
and should not use it to avoid sending duplicate ListDataEvents.
ListModel
, ListDataListener
, ListDataEvent
getSelection
public Object getSelection()
Looks up and returns the current selection using
the current selection index. Returns null
if
no object is selected or if the list has no elements.
- the current selection,
null
if none is selected
getSelectionHolder
public ValueModel getSelectionHolder()
Returns the selection holder.
getSelectionIndex
public int getSelectionIndex()
Returns the selection index.
getSelectionIndexHolder
public ValueModel getSelectionIndexHolder()
Returns the selection index holder.
- the selection index holder
getValue
public Object getValue()
Returns the current selection, null
if the selection index
does not represent a selection in the list.
- getValue in interface ValueModel
- the selected element - if any
hasSelection
public boolean hasSelection()
Checks and answers if an element is selected.
- true if an element is selected, false otherwise
isSelectionEmpty
public boolean isSelectionEmpty()
Checks and answers whether the selection is empty or not.
Unlike #hasSelection, the underlying property #selectionEmpty
for this method is bound. I.e. you can observe this property
using a PropertyChangeListener to update UI state.
- true if nothing is selected, false if there's a selection
release
public void release()
Removes the internal listeners from the list holder, selection holder,
selection index holder. This SelectionInList
must not be used after calling
#release
.
To avoid memory leaks it is recommended to invoke this method,
if the list holder, selection holder, or selection index holder
live much longer than this SelectionInList.
Instead of releasing the SelectionInList, you typically make
the list holder, selection holder, and selection index holder
obsolete by releasing the PresentationModel or BeanAdapter that has
created them before.
As an alternative you may use ValueModels that in turn use
event listener lists implemented using
WeakReference
.
Basically this release method performs the reverse operation
performed during the SelectionInList construction.
- release in interface ListHolder
removeValueChangeListener
public final void removeValueChangeListener(PropertyChangeListener l)
Removes the given PropertyChangeListener from the model.
- removeValueChangeListener in interface ValueModel
l
- the listener to remove
setSelection
public void setSelection(Object newSelection)
Sets the first list element that equals the given new selection
as new selection. Does nothing if the list is empty.
newSelection
- the object to be set as new selection
setSelectionHolder
public void setSelectionHolder(ValueModel newSelectionHolder)
Sets a new selection holder.
Does nothing if the new is the same as before.
The selection remains unchanged and is still driven
by the selection index holder. It's just that future
index changes will update the new selection holder
and that future selection holder changes affect the
selection index.
newSelectionHolder
- the selection holder to set
setSelectionIndex
public void setSelectionIndex(int newSelectionIndex)
Sets a new selection index. Does nothing if it is the same as before.
newSelectionIndex
- the selection index to be set
setSelectionIndexHolder
public void setSelectionIndexHolder(ValueModel newSelectionIndexHolder)
Sets a new selection index holder.
Does nothing if the new is the same as before.
newSelectionIndexHolder
- the selection index holder to set
setValue
public void setValue(Object newValue)
Sets the first list element that equals the given value as selection.
- setValue in interface ValueModel
newValue
- the new value to set
updateList
protected void updateList(List oldList,
List newList)
Updates the selection index and fires a property change for
the list and a contents change event.
- updateList in interface ListHolder
oldList
- the old List contentnewList
- the new List content