com.jgoodies.binding.list
E
- the type of the list elementspublic class IndirectListModel<E> extends Model implements javax.swing.ListModel
ListDataEvent
is fired that reports
a complete change. In contrast, if you use a ListModel it will report
the same PropertyChangeEvent. But fine grained changes in the ListModel
will be fired by this class to notify observes about changes in the content,
added and removed elements.If the list content doesn't change at all, or if it always changes completely, you can work well with both List content and ListModel content. 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.
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 com.jgoodies.common.collect.ArrayListModel
or com.jgoodies.common.collect.LinkedListModel
.
Important Note: If you change the ListModel instance,
either by calling #setListModel(ListModel)
or by setting
a new value to the underlying list holder, you must ensure that
the list holder throws a PropertyChangeEvent whenever the instance changes.
This event is used to remove a ListDataListener from the old ListModel
instance and is later used to add it to the new ListModel instance.
It is easy to violate this constraint, just because Java's standard
PropertyChangeSupport helper class that is used by many beans, checks
a changed property value via #equals
, not ==
.
For example, if you change the IndirectListModel's list model from an empty
list L1
to another empty list instance L2
,
the PropertyChangeSupport won't generate a PropertyChangeEvent,
and so, the IndirectListModel won't know about the change, which
may lead to unexpected behavior.
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 provides 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.
Constraints: The list holder holds instances of List
or ListModel
. If the ListModel changes, the underlying ValueModel
must fire a PropertyChangeEvent.
List
,
ListModel
,
SelectionInList
,
ValueModel
,
ComboBoxAdapter
,
AbstractTableAdapter
,
ExtendedPropertyChangeSupport
,
Model
,
ValueHolder
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
PROPERTYNAME_LIST
The name of the bound write-only list property.
|
static java.lang.String |
PROPERTYNAME_LIST_HOLDER
The name of the bound read-write listHolder property.
|
Constructor and Description |
---|
IndirectListModel()
Constructs an IndirectListModel with an empty initial
ArrayListModel . |
IndirectListModel(E[] listItems)
Constructs an IndirectListModel on the given item array.
|
IndirectListModel(java.util.List<E> list)
Constructs an IndirectListModel on the given list.
|
IndirectListModel(javax.swing.ListModel listModel)
Constructs an IndirectListModel on the given list model
using a default list holder.
|
IndirectListModel(ValueModel listHolder)
Constructs an IndirectListModel on the given list holder.
|
Modifier and Type | Method and Description |
---|---|
void |
addListDataListener(javax.swing.event.ListDataListener l)
Adds a listener to the list that's notified each time a change
to the data model occurs.
|
protected javax.swing.event.ListDataListener |
createListDataChangeHandler()
Creates and returns the ListDataListener used to observe
changes in the underlying ListModel.
|
void |
fireContentsChanged(int index0,
int index1)
Notifies all registered ListDataListeners that the contents
of one or more list elements has changed.
|
void |
fireIntervalAdded(int index0,
int index1)
Notifies all registered ListDataListeners that one or more elements
have been added to this IndirectListModel's List/ListModel.
|
void |
fireIntervalRemoved(int index0,
int index1)
Notifies all registered ListDataListeners that one or more elements
have been removed from this IndirectListModel's List/ListModel.
|
protected void |
fireListChanged(int oldLastIndex,
int newLastIndex)
Notifies all registered ListDataListeners that this ListModel
has changed from an old list to a new list content.
|
E |
getElementAt(int index)
Returns the value at the specified index,
null
if the list model is null . |
java.util.List<E> |
getList()
Returns the list holder's List or an empty List, if it
holds
null . |
javax.swing.event.ListDataListener[] |
getListDataListeners()
Returns an array of all the list data listeners
registered on this
IndirectListModel . |
ValueModel |
getListHolder()
Returns the model that holds the List/ListModel.
|
javax.swing.ListModel |
getListModel()
Returns the list holder's ListModel or an empty ListModel, if it
holds
null . |
int |
getSize()
Returns the length of the list,
0 if the list model
is null . |
protected int |
getSize(java.lang.Object aListListModelOrNull)
Returns the length of the given list,
0 if the list model
is null . |
boolean |
isEmpty()
Checks and answers if the list is empty or
null . |
void |
release()
Removes the internal listeners from the list holder.
|
void |
removeListDataListener(javax.swing.event.ListDataListener l)
Removes a listener from the list that's notified each time a
change to the data model occurs.
|
void |
setList(java.util.List<E> newList)
Sets the given list as value of the list holder.
|
void |
setListHolder(ValueModel newListHolder)
Sets a new list holder.
|
void |
setListModel(javax.swing.ListModel newListModel)
Sets the given list model as value of the list holder.
|
protected void |
updateList(java.lang.Object oldList,
int oldSize,
java.lang.Object newList)
Removes the list data change handler from the old list in case
it is a
ListModel and adds it to new one in case
it is a ListModel . |
createPropertyChangeSupport, firePropertyChange
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
addPropertyChangeListener, removePropertyChangeListener
public static final java.lang.String PROPERTYNAME_LIST
public static final java.lang.String PROPERTYNAME_LIST_HOLDER
public IndirectListModel()
ArrayListModel
.public IndirectListModel(E[] listItems)
Changes to the list "write through" to the array, and changes to the array contents will be reflected in the list.
listItems
- the array of initial itemsjava.lang.NullPointerException
- if listItems
is null
public IndirectListModel(java.util.List<E> list)
Note: Favor ListModel
over
List
when working with an IndirectListModel.
Why? The IndirectListModel can work with both types. What's the
difference? ListModel provides all list access features
required by the IndirectListModel's. In addition it reports more
fine grained change events, instances of ListDataEvents
.
In contrast developer often create Lists and operate on them
and the ListModel may be inconvenient for these operations.
A convenient solution for this situation is to use the
ArrayListModel
and LinkedListModel
classes.
These implement both List and ListModel, offer the standard List
operations and report the fine grained ListDataEvents.
list
- the initial listpublic IndirectListModel(javax.swing.ListModel listModel)
listModel
- the initial list modelpublic IndirectListModel(ValueModel listHolder)
Constraints:
1) The listHolder must hold instances of List or ListModel and
2) must report a value change whenever the value's identity changes.
Note that many bean properties don't fire a PropertyChangeEvent
if the old and new value are equal - and so would break this constraint.
If you provide a ValueHolder, enable its identityCheck feature
during construction. If you provide an adapted bean property from
a bean that extends the JGoodies Model
class,
you can enable the identity check feature in the methods
#firePropertyChange
by setting the trailing boolean
parameter to true
.
listHolder
- holds the list or list modeljava.lang.NullPointerException
- if listHolder
is null
public final java.util.List<E> getList()
null
. Throws an exception if the list holder holds
any other type, including ListModels.null
java.lang.ClassCastException
- if the list holder is neither
null
nor a ListsetList(List)
,
getListModel()
,
setListModel(ListModel)
public final void setList(java.util.List<E> newList)
Note: Favor ListModel
over
List
when working with an IndirectListModel.
Why? The IndirectListModel can work with both types. What's the
difference? ListModel provides all list access features
required by the IndirectListModel's. In addition it reports more
fine grained change events, instances of ListDataEvents
.
In contrast developer often create Lists and operate on them
and the ListModel may be inconvenient for these operations.
A convenient solution for this situation is to use the
ArrayListModel
and LinkedListModel
classes.
These implement both List and ListModel, offer the standard List
operations and report the fine grained ListDataEvents.
newList
- the list to be set as new list contentgetList()
,
getListModel()
,
setListModel(ListModel)
public final javax.swing.ListModel getListModel()
null
. Throws an exception if the list holder holds
any other type, including Lists.null
java.lang.ClassCastException
- if the list holder is neither
null
nor a ListModelsetListModel(ListModel)
,
setList(List)
public final void setListModel(javax.swing.ListModel newListModel)
newListModel
- the list model to be set as new list contentgetListModel()
,
setList(List)
public final ValueModel getListHolder()
public final void setListHolder(ValueModel newListHolder)
#updateListDataRegistration
in the same way as done in the
list change handler.TODO: Check and verify whether the list data registration update can be performed in one step after the listHolder has been changed - instead of remove the list data change handler, then changing the listHolder, and finally adding the list data change handler.
newListHolder
- the list holder to be setjava.lang.NullPointerException
- if the new list holder is null
java.lang.IllegalArgumentException
- if the listHolder is a ValueHolder
that doesn't check the identity when changing its valuepublic final boolean isEmpty()
null
.null
, false otherwisepublic final int getSize()
0
if the list model
is null
.getSize
in interface javax.swing.ListModel
0
if the list model is
null
public final E getElementAt(int index)
null
if the list model is null
.getElementAt
in interface javax.swing.ListModel
index
- the requested indexindex
, null
if the list model is null
java.lang.NullPointerException
- if the list holder's content is nullpublic final void addListDataListener(javax.swing.event.ListDataListener l)
addListDataListener
in interface javax.swing.ListModel
l
- the ListDataListener
to be addedpublic final void removeListDataListener(javax.swing.event.ListDataListener l)
removeListDataListener
in interface javax.swing.ListModel
l
- the ListDataListener
to be removedpublic final javax.swing.event.ListDataListener[] getListDataListeners()
IndirectListModel
.ListDataListener
s,
or an empty array if no list data listeners
are currently registeredaddListDataListener(ListDataListener)
,
removeListDataListener(ListDataListener)
public final void fireContentsChanged(int index0, int index1)
If the list holder holds a ListModel, this IndirectListModel 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.
index0
- one end of the new intervalindex1
- the other end of the new intervalListModel
,
ListDataListener
,
ListDataEvent
public final void fireIntervalAdded(int index0, int index1)
If the list holder holds a ListModel, this IndirectListModel 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.
index0
- one end of the new intervalindex1
- the other end of the new intervalListModel
,
ListDataListener
,
ListDataEvent
public final void fireIntervalRemoved(int index0, int index1)
index0
and index1
are the end points
of the interval that's been removed. Note that index0
need not be less than or equal to index1
.
If the list holder holds a ListModel, this IndirectListModel 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.
index0
- one end of the removed interval,
including index0
index1
- the other end of the removed interval,
including index1
ListModel
,
ListDataListener
,
ListDataEvent
public void release()
#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 IndirectListModel. Instead of releasing the IndirectListModel, you typically make the list 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 IndirectListModel construction.
PresentationModel.release()
,
BeanAdapter.release()
,
WeakReference
protected javax.swing.event.ListDataListener createListDataChangeHandler()
#updateListModel
.protected void updateList(java.lang.Object oldList, int oldSize, java.lang.Object newList)
ListModel
and adds it to new one in case
it is a ListModel
.
It then fires a property change for the list and a contents change event
for the list content.oldList
- the old list contentoldSize
- the size of the old List contentnewList
- the new list contentJTable.tableChanged(javax.swing.event.TableModelEvent)
protected final void fireListChanged(int oldLastIndex, int newLastIndex)
This method is invoked by #updateList during the transition from an old List(Model) to a new List(Model).
Note: The order of the events fired ensures that after each event the size described by the ListDataEvents equals the ListModel size.
oldLastIndex
- the last index of the old listnewLastIndex
- the last index of the new listprotected final int getSize(java.lang.Object aListListModelOrNull)
0
if the list model
is null
.aListListModelOrNull
- a List, ListModel or null0
if the list model is
null
Copyright © 2002-2010 JGoodies Karsten Lentzsch. All Rights Reserved.