JavaSwingStructure: Observable lists


Observable lists

Observable collections

Usually, the collections in questions are either lists or sets. Otherwise it is not clear which of two equal items is meant. With sets, there can be no multiple equal items; with list, indices can be used instead of the items themselves to distinguish between them.

Structural changes

Adding

Removal

Replacement

Property changes

Lists

A list (in this context) is ordered collection of items, indexable by non-negative (or positive) integers.

By this definition, both java.util.SortedSet and java.util.List are lists. The latter allows to introduce any order from the outside, the former implicitly sorts by the given comparison order.

The absolute minimum of inspection methods to provide are get(index) and size() . This is exactly what ListModel provides. It is also possible to only provide an iterator, like SortedSet; but that is inefficient in this context, where fast random access is needed. (It is possible to write tree-based sorted sets that allow indexing).

Observable lists

Lists may change with dynamically with time. How that is done and why isn't the point here, but how listeners are notified of changes in the list.

Structural changes

Adding

Removal

Replacement

of item(s) at certain indices by others, while the item count remains the same.

Fake: remove + add

Weak replacement

The new item(s) should take the role of the item(s) that were in the same place before; in contrast, (strong) replacement is just an atomic remove+add operation (the old items have nothing to do with the new ones).

Reordering

The placement of items at certain indices has been permuted, but no items have been added or removed. Together with sending along the old order, this type of event enables choices (selections, expansions of tree nodes) to "survive" the change. If this event type is simulated by replacement or adding/removable, information is lost.

For example, JList stores the indices of the selected items (it is impossible to store the items themselves, since the ListModel may contain multiple equal items, and it is not clear which one would be selected). When the items are reordered (for example sorted), there is no way to signify to the JList to keep the logically same indices selected.

Moving or Exchanging (special case of reordering)

Fake: replacement for bounds; or remove + add

Complete changes

Fake: remove + add

Property changes

In theory, the observer could also register with the individual items to observe property changes instead of the list also handling these. Reasons against it are:

So the list also sents out events when "relevant" property changes have ocurred. Unfortunately, some event types don't distinguish between replacements and mere property changes (with lossless notification, this could always be done by comparing the old and new items).

This is especially awkward with ComboBoxModel's selection part (which is, if at all, a degenerate zero-or-one-element list). If a property of the selection changed, the ComboBoxModel must fire the same event as if there were a new selection. JComboBox has some special logic when receiving these events, probably to avoid firing extraneous Item- and ActionEvents if only a property of the selection item changed.

List-like models in Swing

Model

Adding

Replacement

Removal

Moving

Complete changes

Property changesProperty changes

ListModel

range

range

(without old items)

range

(without old items)

no

yes

(without old items)

= replacement

TableModel

range

range

(without old items)

range

(without old items)

no

yes

(without old items)

= replacement

TableColumnModel

single

no

single

(without old item)

single

no

width and preferred width

(by columnMarginChanged)

items are observable

TreeModel (children lists)

any

no

any

(with old items)

no

yes

(without old items)

any

Document (list of characters)

range

no

range

no

no

range

Document (element children lists)

range

range

range

no

except root?

with character events

No model supports exchanging or reordering (ListDataEvent and TableModelEvent can be extended to do it, with ignorant listeners treating the event as normal replacement/property change).

ListModel

complete changes only vaguely documented about the actual contents of the event.

TableModel (considered as the list of its rows)

nothing special.

TableColumnModel

No replacement is bad because by faking it, the selection state is inconsistent for a short time. To observe the items (which wouldn't be a problem since you know they are TableColumns), you must still have a copy of the model because you aren't given the TableColumn to disattach the property change listener from when it is removed (only the old index; DefaultTableColumnModel even gave a wrong index until 1.4.)

With the standard interface, you can only add columns at the end. If you want to have them elsewhere, you have to move them afterwards.

TreeModel

The fact that the old items are sent with removal events still is not enough. First, still a structure changed event for the parent could arrive, and that carries no information about the lost children. Second, changes up in the tree hierarchy only (if at all) sent the children along and not all descendants; and as they are removed, you cannot use the TreeModel methods anymore to get information about them. In fact, TreeModel is the model where it makes the least sense to sent them along, and to have changes at any indices instead of ranges.

Document (considered as the list of its characters)

Change update is only for attribute changes.

Document (element children list's)

The documentation is rather vague about how elements can be added and removed at once, or how it works at all. It appears they must be consecutive.


(C) 2001-2009 Christian Kaufhold (swing@chka.de)