ca.odell.glazedlists.event
Class ListEvent<E>

java.lang.Object
  extended by java.util.EventObject
      extended by 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 an EventList. A ListEventListener can be registered on an EventList 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 or DELETE operation that took place at the specified index.

Here are some examples:

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, just reset 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 type DELETE 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 a SortedList.

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 method getReorderMap().

ListEventListeners, 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:

The methods are currently marked as deprecated and should not be used yet, because the implementation is a work in progress.

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
static int DELETE
          different types of changes
static int INSERT
           
protected  EventList<E> sourceList
          the list that has changed
static java.lang.Object UNKNOWN_VALUE
          indicates a removed element whose value is unknown
static int UPDATE
           
 
Fields inherited from class java.util.EventObject
source
 
Method Summary
abstract  ListEvent<E> copy()
          Create a bitwise copy of this ListEvent.
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. Hopefully the full implementation is complete for Glazed Lists 2.0.
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.
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.
 
Methods inherited from class java.util.EventObject
getSource
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

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


sourceList

protected EventList<E> sourceList
the list that has changed

Method Detail

unknownValue

public static final <E> E unknownValue()
Returns a value indicating a removed element whose value is unknown.


copy

public abstract ListEvent<E> copy()
Create a bitwise copy of this ListEvent.


reset

public abstract void reset()
Resets this event's position to the previously-marked position. This should be used for TransformedLists that require multiple-passes of the ListEvent 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 that isReordering() returns true.

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 return UNKNOWN_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 return UNKNOWN_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 class java.util.EventObject


Glazed Lists, Copyright © 2003 publicobject.com, O'Dell Engineering.
Documentation build by pbuilder at 2013-07-04 20:55