Class ListEvent<E>
- java.lang.Object
-
- java.util.EventObject
-
- ca.odell.glazedlists.event.ListEvent<E>
-
- All Implemented Interfaces:
java.io.Serializable
public abstract class ListEvent<E> extends java.util.EventObject
A ListEvent models a sequence of changes to anEventList
. AListEventListener
can be registered on anEventList
to observe and handle these ListEvents.A simple change is characterized by its type and the corresponding list index. The type indicates the
INSERT
,UPDATE
orDELETE
operation that took place at the specified index.Here are some examples:
eventList.add(0, value)
produces anINSERT
at index 0 ("I0")eventList.add(value)
on a list with size 5 produces anINSERT
at index 5 ("I5")eventList.remove(3)
on a list with appropriate size produces aDELETE
at index 3 ("D3")eventList.remove(value)
on a list which contains the value at index 2 produces aDELETE
at index 2 ("D2")eventList.clear()
on a list with size 1 produces aDELETE
at index 0 ("D0")eventList.set(1, value)
on a list with appropriate size produces anUPDATE
at index 1 ("U1")
A ListEvent is capable of representing a sequence of such changes. Consider this example:
EventList<String> list = GlazedLists.eventListOf("A", "D", "E"); list.addAll(1, GlazedLists.eventListOf("B", "C"));
This operation inserts element "B" at index 1 ("I1") and element "C" at index 2 ("I2"). These two changes are not represented as two separate ListEvents but as a sequence of changes ("I1", "I2") within one ListEvent. Because of this, the ListEvent is accessed like an iterator with the user iterating over the contained sequence of changes, see below. Here is another example:EventList<String> list = GlazedLists.eventListOf("A", "B", "C", "B"); list.removeAll(GlazedLists.eventListOf("A", "C"));
This will remove element "A" at index 0 and element "C" at original index 2. But the corresponding ListEvent looks like ("D0","D1"). The list index of the second deletion is automatically adjusted, taking the first deletion into account.Note, that the sequence of changes is ordered by ascending list indexes.
The typical pattern to iterate over a ListEvent is:
ListEvent listChanges = ... while (listChanges.next()) { final int type = listChanges.getType()); final int index = listChanges.getIndex(); // handle insert, update or delete at index ... }
If you need to iterate over a ListEvent again, that's of course possible, justreset
the ListEvent and iterate again.In addition to simple changes, ListEvent supports the view on list changes as blocks. This basically means, that simple changes of one particular type that build a continuous range of indexes are grouped together. Consider this example:
EventList<String> list = GlazedLists.eventListOf("A", "A", "B", "B", "C", "C"); list.removeAll(GlazedLists.eventListOf("A", "C"));
This deletes all occurences of elements "A" and "C" from the list. So there is a deletion from index 0 to index 1 (inclusive) and another deletion from index 2 to 3. So, instead of modeling each change one by one like ("D0", "D0", "D2", "D2"), you can view the changes in blocks "D0-1" and "D2-3". This view is exactly what ListEvent offers by iterating the changes in blocks:ListEvent listChanges = ... while (listChanges.nextBlock()) { final int type = listChanges.getType()); final int startIndex = listChanges.getBlockStartIndex(); final int endIndex = listChanges.getBlockEndIndex(); // handle insert, update or delete from startIndex to endIndex ... }
In the above example you would have two blocks of changes of typeDELETE
instead of four simple changes. It is up to you, which iteration style you choose. Handling blocks of changes might yield a better performance.While it is possible to change the style during one iteration, it is not recommended, because you have to be careful to not miss some changes. Refering to the last example above, the following code would skip the change "D1":
ListEvent listChanges = ...// ("D0", "D0", "D2", "D2") vs. ("D0-1", "D2-3") if (listChanges.next()) { final int type = listChanges.getType(); final int index = listChanges.getIndex(); // handle delete at index 0 // ... while (listChanges.nextBlock()) {// move to next block starting at index 2, skipping change at index 1, which is part of the first block ! final int type2 = listChanges.getType(); final int startIndex = listChanges.getBlockStartIndex(); final int endIndex = listChanges.getBlockEndIndex(); // handle deletion from startIndex 2 to endIndex 3 ... } }
This kind of code is unusual, error-prone and should be avoided.There is a special kind of change, a
reordering
ListEvent. It indicates a reordering of the list elements, for example triggered by setting a new comparator on aSortedList
.A reorder event cannot contain other regular changes in the current implementation. Instead it provides a
reorder map
, which maps the new indexes of the list elements to the old indexes. For details of the mapping see the javadoc of methodgetReorderMap()
.ListEventListener
s, that don't explicitly check for a reorder event, will observe a deletion of all list elements with a subsequent re-insertion instead.In the future, ListEvent will provide even more information about the list changes to be more self-contained:
- for deletes, it will provide the deleted element with
getOldValue()
- for inserts, it will provide the inserted element with
getNewValue()
- for updates, it will provide the old and new element with
getOldValue()
andgetNewValue()
Note, that providing the old and new elements has an impact on the granularity of blocks of changes. For example, consider the clear operation on a list:
EventList<String> list = GlazedLists.eventListOf("A", "B", "C"); list.clear();
Without considering the old and new elements, the ListEvent would consist of one block: a deletion from index 0 to 2 ("D0-2"). With the feature of providing the deleted elements, the ListEvent cannot consist of one block anymore, because of the additional requirement, that the old element must have the same value in one block:ListEvent listChanges = ... while (listChanges.nextBlock()) { final int type = listChanges.getType()); final int startIndex = listChanges.getBlockStartIndex(); final int endIndex = listChanges.getBlockEndIndex(); final Object oldValue = listChanges.getOldValue(); final Object newValue = listChanges.getNewValue(); // handle insert, update or delete from startIndex to endIndex ... }
So, a sequence of simple changes can only be grouped as block, when the type, as well as the old and new value are equal.- Author:
- Jesse Wilson
- See Also:
- Serialized Form
-
-
Field Summary
Fields Modifier and Type Field Description static int
DELETE
different types of changesstatic int
INSERT
protected EventList<E>
sourceList
the list that has changedstatic java.lang.Object
UNKNOWN_VALUE
indicates a removed element whose value is unknownstatic int
UPDATE
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Deprecated Methods Modifier and Type Method Description abstract ListEvent<E>
copy()
Create a bitwise copy of thisListEvent
.abstract int
getBlockEndIndex()
Gets the last row of the current block of changes.abstract int
getBlocksRemaining()
Deprecated.this method depends on a particular implementation of how list events are stored internally, and this implementation has since changed.abstract int
getBlockStartIndex()
Gets the first row of the current block of changes.abstract int
getIndex()
Gets the current row index.abstract E
getNewValue()
Deprecated.this is a developer preview API that is not yet fit for human consumption.abstract E
getOldValue()
Deprecated.this is a developer preview API that is not yet fit for human consumption.abstract int[]
getReorderMap()
Gets the reorder map of this list.EventList<E>
getSourceList()
Gets the List where this event originally occured.abstract int
getType()
Gets the type of the current change, which should be one of ListEvent.INSERT, UPDATE, or DELETE.abstract boolean
hasNext()
Without incrementing the implicit iterator, this tests if there is another change to view.abstract boolean
isReordering()
Tests if this change is a complete reordering of the list.abstract boolean
next()
Increments the change sequence to view the next change.abstract boolean
nextBlock()
Increments the change sequence to view the next change block.abstract void
reset()
Resets this event's position to the previously-marked position.abstract java.lang.String
toString()
Gets this event as a String.static <E> E
unknownValue()
Returns a value indicating a removed element whose value is unknown.
-
-
-
Field Detail
-
DELETE
public static final int DELETE
different types of changes- See Also:
- Constant Field Values
-
UPDATE
public static final int UPDATE
- See Also:
- Constant Field Values
-
INSERT
public static final int INSERT
- See Also:
- Constant Field Values
-
UNKNOWN_VALUE
public static final java.lang.Object UNKNOWN_VALUE
indicates a removed element whose value is unknown
-
-
Method Detail
-
unknownValue
public static final <E> E unknownValue()
Returns a value indicating a removed element whose value is unknown.
-
reset
public abstract void reset()
Resets this event's position to the previously-marked position. This should be used forTransformedList
s that require multiple-passes of theListEvent
in order to process it.
-
next
public abstract boolean next()
Increments the change sequence to view the next change. This will return true if such a change exists and false when there is no change to view.
-
hasNext
public abstract boolean hasNext()
Without incrementing the implicit iterator, this tests if there is another change to view. The user will still need to call next() to view such a change.
-
nextBlock
public abstract boolean nextBlock()
Increments the change sequence to view the next change block.
-
isReordering
public abstract boolean isReordering()
Tests if this change is a complete reordering of the list.If it's a reordering, you can determine the changed element positions with the help of the reorder map.
- See Also:
getReorderMap()
-
getReorderMap
public abstract int[] getReorderMap()
Gets the reorder map of this list. Before calling this method, you should check thatisReordering()
returnstrue
.The size of the returned array is equal to the list size. The array value at index i is the previous index (before the reordering) of the list element at index i (after the reordering).
list before the reordering: "A", "B", "C"
list after the reordering: "C", "B", "A"
The reorder map of the corresponding ListEvent would look like: map[0]=2; map[1]=1; map[2]=0
- Returns:
- an array of integers where the previous index of a value is stored at the current index of that value.
- Throws:
java.lang.IllegalStateException
- if this is not a reordering event- See Also:
isReordering()
-
getIndex
public abstract int getIndex()
Gets the current row index. If the block type is delete, this will always return the startIndex of the current list change.
-
getBlockStartIndex
public abstract int getBlockStartIndex()
Gets the first row of the current block of changes. Inclusive.
-
getBlockEndIndex
public abstract int getBlockEndIndex()
Gets the last row of the current block of changes. Inclusive.
-
getType
public abstract int getType()
Gets the type of the current change, which should be one of ListEvent.INSERT, UPDATE, or DELETE.
-
getOldValue
public abstract E getOldValue()
Deprecated.this is a developer preview API that is not yet fit for human consumption. Hopefully the full implementation is complete for Glazed Lists 2.0.Gets the previous value for a deleted or updated element. If that data is not available, this will returnUNKNOWN_VALUE
.
-
getNewValue
public abstract E getNewValue()
Deprecated.this is a developer preview API that is not yet fit for human consumption. Hopefully the full implementation is complete for Glazed Lists 2.0.Gets the current value for an inserted or updated element. If that data is not available, this will returnUNKNOWN_VALUE
.
-
getBlocksRemaining
public abstract int getBlocksRemaining()
Deprecated.this method depends on a particular implementation of how list events are stored internally, and this implementation has since changed.Gets the number of blocks currently remaining in this atomic change.
-
getSourceList
public EventList<E> getSourceList()
Gets the List where this event originally occured.
-
toString
public abstract java.lang.String toString()
Gets this event as a String. This simply iterates through all blocks and concatenates them.- Overrides:
toString
in classjava.util.EventObject
-
-