summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
diff options
context:
space:
mode:
Diffstat (limited to 'projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java')
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java4219
1 files changed, 1881 insertions, 2338 deletions
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
index bda1dd5..0bdefdf 100644
--- a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/WODisplayGroup.java
@@ -49,2407 +49,1950 @@ import net.wotonomy.foundation.internal.Duplicator;
import net.wotonomy.foundation.internal.WotonomyException;
/**
-* WODisplayGroup manages a set of objects,
-* allowing them to be sorted, batched, and filtered.
-* WODisplay also acts as a bridge to the wotonomy's
-* control package, including WODisplayGroup and
-* EOEditingContext.
-*
-* @author michael@mpowers.net
-* @author $Author: cgruber $
-* @version $Revision: 905 $
-*/
-public class WODisplayGroup extends Observable
- implements EOObserving, EOEditingContext.Editor,
- java.io.Serializable
-{
- /**
- * Notification sent when the display group is about to fetch.
- */
- public static final String DisplayGroupWillFetchNotification
- = "DisplayGroupWillFetchNotification";
-
- private static boolean
- globalDefaultForValidatesChangesImmediately = true;
- private static String
- globalDefaultStringMatchFormat = "caseInsensitiveLike";
- private static String
- globalDefaultStringMatchOperator = "%@*";
-
- protected NSMutableArray allObjects;
- protected NSArray allObjectsProxy;
- protected NSMutableArray displayedObjects;
- protected NSArray displayedObjectsProxy;
- protected NSMutableArray selectedObjects;
- protected NSArray selectedObjectsProxy;
- protected NSMutableArray selectedIndexes;
-
- private String defaultStringMatchOperator;
- private String defaultStringMatchFormat;
-
- private boolean validatesChangesImmediately;
- private Object delegate;
- private EODataSource dataSource;
- private EOQualifier qualifier;
- private NSMutableArray sortOrderings;
- private NSArray sortOrderingsProxy;
-
- private NSArray localKeys;
- private NSDictionary insertedObjectDefaultValues;
- private boolean fetchesOnLoad;
- private boolean selectsFirstObjectAfterFetch;
- private boolean usesOptimisticRefresh;
- private boolean inQueryMode;
-
- // change detection: package access for helper classes
- boolean selectionChanged;
- int updatedObjectIndex;
-
- // batching
- private int batchIndex;
- private int batchSize;
-
- // this property is not in the spec
- private boolean compareByReference = false;
-
- private EOObserving lastGroupObserver;
-
- /**
- * Creates a new display group.
- */
- public WODisplayGroup()
- {
- validatesChangesImmediately =
- globalDefaultForValidatesChangesImmediately();
- defaultStringMatchOperator =
- globalDefaultStringMatchFormat();
- defaultStringMatchFormat =
- globalDefaultStringMatchOperator();
-
- allObjects = new ObservableArray( this );
- allObjectsProxy = NSArray.arrayBackedByList( allObjects );
- displayedObjects = new NSMutableArray();
- displayedObjectsProxy = NSArray.arrayBackedByList( displayedObjects );
- selectedObjects = new NSMutableArray();
- selectedObjectsProxy = NSArray.arrayBackedByList( selectedObjects );
- sortOrderings = new NSMutableArray();
- sortOrderingsProxy = NSArray.arrayBackedByList( sortOrderings );
- selectedIndexes = new NSMutableArray();
-
- delegate = null;
- dataSource = null;
- qualifier = null;
-
- localKeys = new NSArray(); // not implemented
- insertedObjectDefaultValues = new NSDictionary();
- fetchesOnLoad = false; // not implemented
- selectsFirstObjectAfterFetch = false;
- usesOptimisticRefresh = false;
- inQueryMode = false; // not implemented
-
- selectionChanged = false;
- updatedObjectIndex = -1;
-
- batchIndex = 0;
- batchSize = 0;
- }
-
-
-
- // specify optional data source
-
- /**
- * Sets the data source that will be used by
- * this display group.
- */
- public void setDataSource ( EODataSource aDataSource )
- {
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // un-register for notifications from existing parent store
- NSNotificationCenter.defaultCenter().removeObserver(
- this, null, dataSource.editingContext() );
- dataSource.editingContext().removeEditor( this );
- if ( dataSource.editingContext().messageHandler() == this )
- {
- dataSource.editingContext().setMessageHandler( null );
- }
-
- }
-
- dataSource = aDataSource;
-
- if ( ( dataSource != null )
- && ( dataSource.editingContext() != null ) )
- {
- // register for notifications from parent store
- NSNotificationCenter.defaultCenter().addObserver(
- this, new NSSelector( "objectsInvalidatedInEditingContext",
- new Class[] { NSNotification.class } ),
- null, dataSource.editingContext() );
-
- // add ourselves as editor
- dataSource.editingContext().addEditor( this );
-
- // add ourselves as message handler if no such handler exists
- if ( dataSource.editingContext().messageHandler() == null )
- {
- dataSource.editingContext().setMessageHandler( this );
- }
- }
- }
-
- /**
- * Returns the current data source backing this display group,
- * or null if no dataSource is currently used.
- */
- public EODataSource dataSource()
- {
- return dataSource;
- }
-
- /**
- * Returns the key by which this display group is bound a master
- * display group, or null if this is not a detail display group.
- */
- public String detailKey()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).key();
- }
- return null;
- }
-
- /**
- * Sets the key by which this display group is bound a master
- * display group. Does nothing if this is not a detail display group.
- */
- public void setDetailKey( String aKey )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setKey( aKey );
- }
- }
-
- /**
- * Returns whether the data source is a detail data source,
- * suggesting that this is a detail display group.
- */
- public boolean hasDetailDataSource()
- {
- return ( dataSource instanceof PropertyDataSource );
- }
-
- /**
- * Returns the selected object in the master display group,
- * or null if this is not a detail display group.
- */
- public Object masterObject()
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- return ((PropertyDataSource)dataSource).source();
- }
- return null;
- }
-
- /**
- * Sets the master object in the detail data source.
- * Does nothing if there is no detail data source.
- */
- public void setMasterObject( Object anObject )
- {
- if ( dataSource instanceof PropertyDataSource )
- {
- ((PropertyDataSource)dataSource).setSource( anObject );
- }
- }
-
- // specify optional delegate
-
- /**
- * Sets the display group delegate that
- * will be used by this display group.
- */
- public void setDelegate ( Object aDelegate )
- {
- delegate = aDelegate;
- }
-
- /**
- * Returns the current delegate for this display group,
- * or null if no delegate is currently set.
- */
- public Object delegate()
- {
- return delegate;
- }
-
-
-
- // display group configuration
-
- /**
- * Returns the current string matching format.
- * If not set, defaults to "%@*".
- */
- public String defaultStringMatchFormat()
- {
- return defaultStringMatchFormat;
- }
-
- /**
- * Returns the current string matching operator.
- * If not set, defaults to "caseInsensitiveLike".
- */
- public String defaultStringMatchOperator()
- {
- return defaultStringMatchOperator;
- }
-
- /**
- * Sets the display group and associations to edit a
- * "query by example" query object. This method is
- * used for target/action connections.
- */
- public void enterQueryMode ( Object aSender )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns whether this display group should immediate
- * fetch when loaded.
- */
- public boolean fetchesOnLoad()
- {
- return fetchesOnLoad;
- }
-
- /**
- * Returns whether this display group is in "query by
- * example" mode.
- */
- public boolean inQueryMode()
- {
- return inQueryMode;
- }
-
- /**
- * Returns a Map of default values that are applied
- * to new objects that are inserted into the list.
- */
- public NSDictionary insertedObjectDefaultValues()
- {
- return insertedObjectDefaultValues;
- }
-
- /**
- * Returns the keys that were declared when read from
- * an external resource file.
- */
- public NSArray localKeys()
- {
- return localKeys;
- }
-
- /**
- * Sets whether this display group will select the
- * first object in the list after a fetch.
- */
- public boolean selectsFirstObjectAfterFetch()
- {
- return selectsFirstObjectAfterFetch;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by this display group.
- */
- public void setDefaultStringMatchFormat ( String aFormat )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by this display group.
- */
- public void setDefaultStringMatchOperator ( String anOperator )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets whether this display group will fetch objects
- * from its data source on load.
- */
- public void setFetchesOnLoad ( boolean willFetch )
- {
- fetchesOnLoad = willFetch;
- }
-
- /**
- * Sets whether this display group is in "query by example"
- * mode. If true, all associations will bind to a special
- * "example" object.
- */
- public void setInQueryMode ( boolean isInQueryMode )
- {
- inQueryMode = isInQueryMode;
- }
-
- /**
- * Sets the mapping that contains the values that will
- * be applied to new objects inserted into the display group.
- */
- public void setInsertedObjectDefaultValues ( Map aMap )
- {
- insertedObjectDefaultValues = new NSDictionary( aMap );
- }
-
- /**
- * Sets the keys that are declared when instantiated from
- * an external resource file.
- */
- public void setLocalKeys ( List aKeyList )
- {
- localKeys = new NSArray( (Collection) aKeyList );
- }
-
- /**
- * Sets whether the first object in the list will be
- * selected after a fetch.
- */
- public void setSelectsFirstObjectAfterFetch (
- boolean selectsFirst )
- {
- selectsFirstObjectAfterFetch = selectsFirst;
- }
-
- /**
- * Sets the order of the keys by which this display group
- * will be ordered after a fetch or after a call to
- * updateDisplayedObjects(). The elements in the display
- * group will be sorted first by the first key, within
- * the first key, by the second key, and so on.
- */
- public void setSortOrderings ( List aList )
- {
- sortOrderings.removeAllObjects();
-
- Object o;
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- // handle the convenience of specifying just a key
- if ( ! ( o instanceof EOSortOrdering ) )
- {
- o = new EOSortOrdering(
- o.toString(), EOSortOrdering.CompareAscending );
- }
- sortOrderings.add( o );
- }
- }
-
- /**
- * Sets whether only changed objects are refreshed (optimistic),
- * or whether all objects are refreshed (pessimistic, default).
- * By default, when the display group receives notification that
- * one of its objects has changed, updateDisplayedObjects is called.
- */
- public void setUsesOptimisticRefresh ( boolean isOptimistic )
- {
- usesOptimisticRefresh = isOptimistic;
- }
-
- /**
- * Sets whether changes made by associations are validated
- * immediately, or when changes are saved.
- */
- public void setValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- validatesChangesImmediately = validatesImmediately;
- }
-
- /**
- * Returns a read-only List of sort orderings for this display group.
- */
- public NSArray sortOrderings()
- {
- return sortOrderingsProxy;
- }
-
- /**
- * Returns whether this display group refreshes only
- * the changed objects or all objects on refresh.
- */
- public boolean usesOptimisticRefresh()
- {
- return usesOptimisticRefresh;
- }
-
- /**
- * Returns whether this display group validates changes
- * immediately. Otherwise, validation should occur when
- * changes are saved. Default is the global default,
- * which is initially true.
- */
- public boolean validatesChangesImmediately()
- {
- return validatesChangesImmediately;
- }
-
-
- // qualification
-
- /**
- * Returns a qualifier that will be applied all the objects
- * in this display group to determine which objects will
- * be displayed.
- */
- public EOQualifier qualifier()
- {
- return qualifier;
- }
-
- /**
- * Returns a new qualifier built from the three query
- * value maps: greater than, equal to, and less than.
- */
- public EOQualifier qualifierFromQueryValues()
- {
- //TODO: assemble qualifier from query values
-
- return new EOQualifier()
- {
- // use inner class until we actually implement one
- public EOQualifier qualifierWithBindings(
- Map aMap,
- boolean requireAll )
- {
- return null;
- }
- public Throwable
- validateKeysWithRootClassDescription( Class aClass )
- {
- return null;
- }
- public boolean evaluateWithObject(Object o)
- {
- return false;
- }
- };
- }
-
- /**
- * Calls qualifierFromQueryValues(), applies the result
- * to the data source, and calls fetch().
- */
- public void qualifyDataSource()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Calls qualifierFromQueryValues(), sets the qualifier
- * with setQualifier(), and calls updateDisplayedObjects().
- */
- public void qualifyDisplayGroup()
- {
- setQualifier( qualifierFromQueryValues() );
- updateDisplayedObjects();
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSDictionary queryBindingValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values.
- */
- public NSMutableDictionary queryBindings()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a matching query.
- */
- public NSMutableDictionary queryMatch()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a minimum value query.
- */
- public NSMutableDictionary queryMin()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to binding query values for a maximum value query.
- */
- public NSMutableDictionary queryMax()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSMutableDictionary queryOperator()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a list containing all supported qualifier operators.
- */
- public NSArray allQualifierOperators()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to operator values.
- */
- public NSDictionary queryOperatorValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the qualifier that will be used by
- * updateDisplayedObjects() to filter displayed objects.
- */
- public void setQualifier ( EOQualifier aQualifier )
- {
- qualifier = aQualifier;
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to binding values.
- */
- public void setQueryBindingValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to operator values.
- */
- public void setQueryOperatorValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
-
-
- // qualifier query values
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for equality.
- */
- public NSDictionary equalToQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public NSDictionary greaterThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Returns a Map containing the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public NSDictionary lessThanQueryValues()
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the Map that contains the mappings of keys
- * to query values that will be used to test for equality.
- */
- public void setEqualToQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for greater value.
- */
- public void setGreaterThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Sets the mapping that contains the mappings of keys
- * to query values that will be used to test for lesser value.
- */
- public void setLessThanQueryValues ( Map aMap )
- {
- throw new RuntimeException( "Not implemented yet." );
- }
-
- /**
- * Deprecated: returns true.
- */
- public boolean endEditing()
- {
- return true;
- }
-
-
- // object management
-
- /**
- * Returns a read-only List containing all objects managed by the display group.
- * This includes those objects not visible due to disqualification.
- */
- public NSArray allObjects()
- { //System.out.println( "avoided allocation: allObjects" );
- return allObjectsProxy;
- }
-
- /**
- * Returns the total number of batches held by this display group.
- */
- public int batchCount()
- {
- if ( batchSize < 1 ) return 1;
- int count = displayedObjects.count();
- if ( count == 0 ) return 1;
- return ((count-1) / batchSize) + 1;
- }
-
- /**
- * Returns the index of the currently displayed batch.
- */
- public int currentBatchIndex()
- {
- return batchIndex;
- }
-
- /**
- * Sets the index of the currently displayed batch.
- */
- public void setCurrentBatchIndex( int aBatchIndex )
- {
- batchIndex = aBatchIndex;
- updateDisplayedObjects();
- }
-
- /**
- * Sets the displayed objects to the batch containing
- * the first selected object, and updates the current
- * batch index, and returns null to force a page reload.
- * Displays the first batch is there is no selection.
- */
- public Object displayBatchContainingSelectedObject()
- {
- if ( batchSize < 1 ) return null;
- NSArray indexes = selectionIndexes();
- if ( indexes.count() > 0 )
- {
- batchIndex =
- ((Number)indexes.objectAtIndex( 0 )).intValue() / batchSize;
- }
- else
- {
- batchIndex = 0;
- }
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no next batch
- * the first batch is displayed.
- */
- public Object displayNextBatch()
- {
- batchIndex = (batchIndex + 1) % batchCount();
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Sets the displayed objects to the next batch
- * and updates the current batch index, and returns null
- * to force a page reload. If there is no previous
- * batch, the last batch is displayed.
- */
- public Object displayPreviousBatch()
- {
- batchIndex--;
- if ( batchIndex < 0 ) batchIndex = batchCount() - 1;
- updateDisplayedObjects();
- return null;
- }
-
- /**
- * Returns whether the displayed objects have been batched.
- */
- public boolean hasMultipleBatches()
- {
- return batchCount() > 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first displayed object in the current batch.
- */
- public int indexOfFirstDisplayedObject()
- {
- if ( batchSize < 1 ) return 1;
- return batchIndex * batchSize + 1;
- }
-
- /**
- * Returns the one-based index within the displayed objects list
- * of the first last object in the current batch.
- */
- public int indexOfLastDisplayedObject()
- {
- if ( batchSize < 1 ) return displayedObjects.count();
- return Math.min(
- ((batchIndex+1) * batchSize),
- displayedObjects.count() );
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public int numberOfObjectsPerBatch()
- {
- return batchSize;
- }
-
- /**
- * Returns the number of objects per batch.
- */
- public void setNumberOfObjectsPerBatch( int aSize )
- {
- batchSize = aSize;
- updateDisplayedObjects();
- }
-
- /**
- * Clears the current selection.
- * @return True is the selection was cleared,
- * False if the selection could not be cleared
- * @see #setSelectionIndexes
- */
- public boolean clearSelection()
- {
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, new NSArray( selectedObjects ) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- selectionChanged = true;
- willChange();
-
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Convenience for binding to a component action:
- * calls deleteSelection() and then displayBatchContainingSelectedObject()
- * and returns null, which is a suitable result from a component action.
- */
- public Object delete()
- {
- deleteSelection();
- displayBatchContainingSelectedObject();
- return null;
- }
-
- /**
- * Deletes the object at the specified index,
- * notifying the delegate before and after the operation,
- * and then updating the selection if needed.
- * @return True if delete was successful, false if the
- * object was not deleted.
- */
- public boolean deleteObjectAtIndex ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- Object result = notifyDelegate(
- "displayGroupShouldDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return false;
- }
-
- deleteObjectAtIndexNoNotify( anIndex );
-
- if ( dataSource != null )
- {
- dataSource.deleteObject( target );
- }
-
- notifyDelegate(
- "displayGroupDidDeleteObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, target } );
-
- return true;
- }
-
- private void deleteObjectAtIndexNoNotify ( int anIndex )
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
-
- int i;
-
- // remove from selected objects if necessary
- i = indexOf( selectedObjects, target );
- if ( i != NSArray.NotFound )
- {
- selectionChanged = true;
- willChange(); // notify before removing
- selectedObjects.removeObjectAtIndex( i );
- selectedIndexes.remove( new Integer( i ) ); // comps by value
- }
- else // notify - no selection change needed
- {
- willChange();
- }
-
- // remove from all objects
- i = indexOf( allObjects, target );
- if ( i != NSArray.NotFound )
- {
- allObjects.removeObjectAtIndex( i );
- }
- else // otherwise should never happen
- {
+ * WODisplayGroup manages a set of objects, allowing them to be sorted, batched,
+ * and filtered. WODisplay also acts as a bridge to the wotonomy's control
+ * package, including WODisplayGroup and EOEditingContext.
+ *
+ * @author michael@mpowers.net
+ * @author $Author: cgruber $
+ * @version $Revision: 905 $
+ */
+public class WODisplayGroup extends Observable implements EOObserving, EOEditingContext.Editor, java.io.Serializable {
+ /**
+ * Notification sent when the display group is about to fetch.
+ */
+ public static final String DisplayGroupWillFetchNotification = "DisplayGroupWillFetchNotification";
+
+ private static boolean globalDefaultForValidatesChangesImmediately = true;
+ private static String globalDefaultStringMatchFormat = "caseInsensitiveLike";
+ private static String globalDefaultStringMatchOperator = "%@*";
+
+ protected NSMutableArray allObjects;
+ protected NSArray allObjectsProxy;
+ protected NSMutableArray displayedObjects;
+ protected NSArray displayedObjectsProxy;
+ protected NSMutableArray selectedObjects;
+ protected NSArray selectedObjectsProxy;
+ protected NSMutableArray selectedIndexes;
+
+ private String defaultStringMatchOperator;
+ private String defaultStringMatchFormat;
+
+ private boolean validatesChangesImmediately;
+ private Object delegate;
+ private EODataSource dataSource;
+ private EOQualifier qualifier;
+ private NSMutableArray sortOrderings;
+ private NSArray sortOrderingsProxy;
+
+ private NSArray localKeys;
+ private NSDictionary insertedObjectDefaultValues;
+ private boolean fetchesOnLoad;
+ private boolean selectsFirstObjectAfterFetch;
+ private boolean usesOptimisticRefresh;
+ private boolean inQueryMode;
+
+ // change detection: package access for helper classes
+ boolean selectionChanged;
+ int updatedObjectIndex;
+
+ // batching
+ private int batchIndex;
+ private int batchSize;
+
+ // this property is not in the spec
+ private boolean compareByReference = false;
+
+ private EOObserving lastGroupObserver;
+
+ /**
+ * Creates a new display group.
+ */
+ public WODisplayGroup() {
+ validatesChangesImmediately = globalDefaultForValidatesChangesImmediately();
+ defaultStringMatchOperator = globalDefaultStringMatchFormat();
+ defaultStringMatchFormat = globalDefaultStringMatchOperator();
+
+ allObjects = new ObservableArray(this);
+ allObjectsProxy = NSArray.arrayBackedByList(allObjects);
+ displayedObjects = new NSMutableArray();
+ displayedObjectsProxy = NSArray.arrayBackedByList(displayedObjects);
+ selectedObjects = new NSMutableArray();
+ selectedObjectsProxy = NSArray.arrayBackedByList(selectedObjects);
+ sortOrderings = new NSMutableArray();
+ sortOrderingsProxy = NSArray.arrayBackedByList(sortOrderings);
+ selectedIndexes = new NSMutableArray();
+
+ delegate = null;
+ dataSource = null;
+ qualifier = null;
+
+ localKeys = new NSArray(); // not implemented
+ insertedObjectDefaultValues = new NSDictionary();
+ fetchesOnLoad = false; // not implemented
+ selectsFirstObjectAfterFetch = false;
+ usesOptimisticRefresh = false;
+ inQueryMode = false; // not implemented
+
+ selectionChanged = false;
+ updatedObjectIndex = -1;
+
+ batchIndex = 0;
+ batchSize = 0;
+ }
+
+ // specify optional data source
+
+ /**
+ * Sets the data source that will be used by this display group.
+ */
+ public void setDataSource(EODataSource aDataSource) {
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // un-register for notifications from existing parent store
+ NSNotificationCenter.defaultCenter().removeObserver(this, null, dataSource.editingContext());
+ dataSource.editingContext().removeEditor(this);
+ if (dataSource.editingContext().messageHandler() == this) {
+ dataSource.editingContext().setMessageHandler(null);
+ }
+
+ }
+
+ dataSource = aDataSource;
+
+ if ((dataSource != null) && (dataSource.editingContext() != null)) {
+ // register for notifications from parent store
+ NSNotificationCenter.defaultCenter().addObserver(this,
+ new NSSelector("objectsInvalidatedInEditingContext", new Class[] { NSNotification.class }), null,
+ dataSource.editingContext());
+
+ // add ourselves as editor
+ dataSource.editingContext().addEditor(this);
+
+ // add ourselves as message handler if no such handler exists
+ if (dataSource.editingContext().messageHandler() == null) {
+ dataSource.editingContext().setMessageHandler(this);
+ }
+ }
+ }
+
+ /**
+ * Returns the current data source backing this display group, or null if no
+ * dataSource is currently used.
+ */
+ public EODataSource dataSource() {
+ return dataSource;
+ }
+
+ /**
+ * Returns the key by which this display group is bound a master display group,
+ * or null if this is not a detail display group.
+ */
+ public String detailKey() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).key();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the key by which this display group is bound a master display group.
+ * Does nothing if this is not a detail display group.
+ */
+ public void setDetailKey(String aKey) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setKey(aKey);
+ }
+ }
+
+ /**
+ * Returns whether the data source is a detail data source, suggesting that this
+ * is a detail display group.
+ */
+ public boolean hasDetailDataSource() {
+ return (dataSource instanceof PropertyDataSource);
+ }
+
+ /**
+ * Returns the selected object in the master display group, or null if this is
+ * not a detail display group.
+ */
+ public Object masterObject() {
+ if (dataSource instanceof PropertyDataSource) {
+ return ((PropertyDataSource) dataSource).source();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the master object in the detail data source. Does nothing if there is no
+ * detail data source.
+ */
+ public void setMasterObject(Object anObject) {
+ if (dataSource instanceof PropertyDataSource) {
+ ((PropertyDataSource) dataSource).setSource(anObject);
+ }
+ }
+
+ // specify optional delegate
+
+ /**
+ * Sets the display group delegate that will be used by this display group.
+ */
+ public void setDelegate(Object aDelegate) {
+ delegate = aDelegate;
+ }
+
+ /**
+ * Returns the current delegate for this display group, or null if no delegate
+ * is currently set.
+ */
+ public Object delegate() {
+ return delegate;
+ }
+
+ // display group configuration
+
+ /**
+ * Returns the current string matching format. If not set, defaults to "%@*".
+ */
+ public String defaultStringMatchFormat() {
+ return defaultStringMatchFormat;
+ }
+
+ /**
+ * Returns the current string matching operator. If not set, defaults to
+ * "caseInsensitiveLike".
+ */
+ public String defaultStringMatchOperator() {
+ return defaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the display group and associations to edit a "query by example" query
+ * object. This method is used for target/action connections.
+ */
+ public void enterQueryMode(Object aSender) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns whether this display group should immediate fetch when loaded.
+ */
+ public boolean fetchesOnLoad() {
+ return fetchesOnLoad;
+ }
+
+ /**
+ * Returns whether this display group is in "query by example" mode.
+ */
+ public boolean inQueryMode() {
+ return inQueryMode;
+ }
+
+ /**
+ * Returns a Map of default values that are applied to new objects that are
+ * inserted into the list.
+ */
+ public NSDictionary insertedObjectDefaultValues() {
+ return insertedObjectDefaultValues;
+ }
+
+ /**
+ * Returns the keys that were declared when read from an external resource file.
+ */
+ public NSArray localKeys() {
+ return localKeys;
+ }
+
+ /**
+ * Sets whether this display group will select the first object in the list
+ * after a fetch.
+ */
+ public boolean selectsFirstObjectAfterFetch() {
+ return selectsFirstObjectAfterFetch;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchFormat(String aFormat) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by this display
+ * group.
+ */
+ public void setDefaultStringMatchOperator(String anOperator) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets whether this display group will fetch objects from its data source on
+ * load.
+ */
+ public void setFetchesOnLoad(boolean willFetch) {
+ fetchesOnLoad = willFetch;
+ }
+
+ /**
+ * Sets whether this display group is in "query by example" mode. If true, all
+ * associations will bind to a special "example" object.
+ */
+ public void setInQueryMode(boolean isInQueryMode) {
+ inQueryMode = isInQueryMode;
+ }
+
+ /**
+ * Sets the mapping that contains the values that will be applied to new objects
+ * inserted into the display group.
+ */
+ public void setInsertedObjectDefaultValues(Map aMap) {
+ insertedObjectDefaultValues = new NSDictionary(aMap);
+ }
+
+ /**
+ * Sets the keys that are declared when instantiated from an external resource
+ * file.
+ */
+ public void setLocalKeys(List aKeyList) {
+ localKeys = new NSArray((Collection) aKeyList);
+ }
+
+ /**
+ * Sets whether the first object in the list will be selected after a fetch.
+ */
+ public void setSelectsFirstObjectAfterFetch(boolean selectsFirst) {
+ selectsFirstObjectAfterFetch = selectsFirst;
+ }
+
+ /**
+ * Sets the order of the keys by which this display group will be ordered after
+ * a fetch or after a call to updateDisplayedObjects(). The elements in the
+ * display group will be sorted first by the first key, within the first key, by
+ * the second key, and so on.
+ */
+ public void setSortOrderings(List aList) {
+ sortOrderings.removeAllObjects();
+
+ Object o;
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ // handle the convenience of specifying just a key
+ if (!(o instanceof EOSortOrdering)) {
+ o = new EOSortOrdering(o.toString(), EOSortOrdering.CompareAscending);
+ }
+ sortOrderings.add(o);
+ }
+ }
+
+ /**
+ * Sets whether only changed objects are refreshed (optimistic), or whether all
+ * objects are refreshed (pessimistic, default). By default, when the display
+ * group receives notification that one of its objects has changed,
+ * updateDisplayedObjects is called.
+ */
+ public void setUsesOptimisticRefresh(boolean isOptimistic) {
+ usesOptimisticRefresh = isOptimistic;
+ }
+
+ /**
+ * Sets whether changes made by associations are validated immediately, or when
+ * changes are saved.
+ */
+ public void setValidatesChangesImmediately(boolean validatesImmediately) {
+ validatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Returns a read-only List of sort orderings for this display group.
+ */
+ public NSArray sortOrderings() {
+ return sortOrderingsProxy;
+ }
+
+ /**
+ * Returns whether this display group refreshes only the changed objects or all
+ * objects on refresh.
+ */
+ public boolean usesOptimisticRefresh() {
+ return usesOptimisticRefresh;
+ }
+
+ /**
+ * Returns whether this display group validates changes immediately. Otherwise,
+ * validation should occur when changes are saved. Default is the global
+ * default, which is initially true.
+ */
+ public boolean validatesChangesImmediately() {
+ return validatesChangesImmediately;
+ }
+
+ // qualification
+
+ /**
+ * Returns a qualifier that will be applied all the objects in this display
+ * group to determine which objects will be displayed.
+ */
+ public EOQualifier qualifier() {
+ return qualifier;
+ }
+
+ /**
+ * Returns a new qualifier built from the three query value maps: greater than,
+ * equal to, and less than.
+ */
+ public EOQualifier qualifierFromQueryValues() {
+ // TODO: assemble qualifier from query values
+
+ return new EOQualifier() {
+ // use inner class until we actually implement one
+ public EOQualifier qualifierWithBindings(Map aMap, boolean requireAll) {
+ return null;
+ }
+
+ public Throwable validateKeysWithRootClassDescription(Class aClass) {
+ return null;
+ }
+
+ public boolean evaluateWithObject(Object o) {
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), applies the result to the data source, and
+ * calls fetch().
+ */
+ public void qualifyDataSource() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Calls qualifierFromQueryValues(), sets the qualifier with setQualifier(), and
+ * calls updateDisplayedObjects().
+ */
+ public void qualifyDisplayGroup() {
+ setQualifier(qualifierFromQueryValues());
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSDictionary queryBindingValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values.
+ */
+ public NSMutableDictionary queryBindings() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * matching query.
+ */
+ public NSMutableDictionary queryMatch() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * minimum value query.
+ */
+ public NSMutableDictionary queryMin() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to binding query values for a
+ * maximum value query.
+ */
+ public NSMutableDictionary queryMax() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSMutableDictionary queryOperator() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a list containing all supported qualifier operators.
+ */
+ public NSArray allQualifierOperators() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to operator values.
+ */
+ public NSDictionary queryOperatorValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the qualifier that will be used by updateDisplayedObjects() to filter
+ * displayed objects.
+ */
+ public void setQualifier(EOQualifier aQualifier) {
+ qualifier = aQualifier;
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to binding values.
+ */
+ public void setQueryBindingValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to operator values.
+ */
+ public void setQueryOperatorValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ // qualifier query values
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public NSDictionary equalToQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for greater value.
+ */
+ public NSDictionary greaterThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Returns a Map containing the mappings of keys to query values that will be
+ * used to test for lesser value.
+ */
+ public NSDictionary lessThanQueryValues() {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the Map that contains the mappings of keys to query values that will be
+ * used to test for equality.
+ */
+ public void setEqualToQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for greater value.
+ */
+ public void setGreaterThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Sets the mapping that contains the mappings of keys to query values that will
+ * be used to test for lesser value.
+ */
+ public void setLessThanQueryValues(Map aMap) {
+ throw new RuntimeException("Not implemented yet.");
+ }
+
+ /**
+ * Deprecated: returns true.
+ */
+ public boolean endEditing() {
+ return true;
+ }
+
+ // object management
+
+ /**
+ * Returns a read-only List containing all objects managed by the display group.
+ * This includes those objects not visible due to disqualification.
+ */
+ public NSArray allObjects() { // System.out.println( "avoided allocation: allObjects" );
+ return allObjectsProxy;
+ }
+
+ /**
+ * Returns the total number of batches held by this display group.
+ */
+ public int batchCount() {
+ if (batchSize < 1)
+ return 1;
+ int count = displayedObjects.count();
+ if (count == 0)
+ return 1;
+ return ((count - 1) / batchSize) + 1;
+ }
+
+ /**
+ * Returns the index of the currently displayed batch.
+ */
+ public int currentBatchIndex() {
+ return batchIndex;
+ }
+
+ /**
+ * Sets the index of the currently displayed batch.
+ */
+ public void setCurrentBatchIndex(int aBatchIndex) {
+ batchIndex = aBatchIndex;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Sets the displayed objects to the batch containing the first selected object,
+ * and updates the current batch index, and returns null to force a page reload.
+ * Displays the first batch is there is no selection.
+ */
+ public Object displayBatchContainingSelectedObject() {
+ if (batchSize < 1)
+ return null;
+ NSArray indexes = selectionIndexes();
+ if (indexes.count() > 0) {
+ batchIndex = ((Number) indexes.objectAtIndex(0)).intValue() / batchSize;
+ } else {
+ batchIndex = 0;
+ }
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no next batch the
+ * first batch is displayed.
+ */
+ public Object displayNextBatch() {
+ batchIndex = (batchIndex + 1) % batchCount();
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Sets the displayed objects to the next batch and updates the current batch
+ * index, and returns null to force a page reload. If there is no previous
+ * batch, the last batch is displayed.
+ */
+ public Object displayPreviousBatch() {
+ batchIndex--;
+ if (batchIndex < 0)
+ batchIndex = batchCount() - 1;
+ updateDisplayedObjects();
+ return null;
+ }
+
+ /**
+ * Returns whether the displayed objects have been batched.
+ */
+ public boolean hasMultipleBatches() {
+ return batchCount() > 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * displayed object in the current batch.
+ */
+ public int indexOfFirstDisplayedObject() {
+ if (batchSize < 1)
+ return 1;
+ return batchIndex * batchSize + 1;
+ }
+
+ /**
+ * Returns the one-based index within the displayed objects list of the first
+ * last object in the current batch.
+ */
+ public int indexOfLastDisplayedObject() {
+ if (batchSize < 1)
+ return displayedObjects.count();
+ return Math.min(((batchIndex + 1) * batchSize), displayedObjects.count());
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public int numberOfObjectsPerBatch() {
+ return batchSize;
+ }
+
+ /**
+ * Returns the number of objects per batch.
+ */
+ public void setNumberOfObjectsPerBatch(int aSize) {
+ batchSize = aSize;
+ updateDisplayedObjects();
+ }
+
+ /**
+ * Clears the current selection.
+ *
+ * @return True is the selection was cleared, False if the selection could not
+ * be cleared
+ * @see #setSelectionIndexes
+ */
+ public boolean clearSelection() {
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, new NSArray(selectedObjects) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ selectionChanged = true;
+ willChange();
+
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Convenience for binding to a component action: calls deleteSelection() and
+ * then displayBatchContainingSelectedObject() and returns null, which is a
+ * suitable result from a component action.
+ */
+ public Object delete() {
+ deleteSelection();
+ displayBatchContainingSelectedObject();
+ return null;
+ }
+
+ /**
+ * Deletes the object at the specified index, notifying the delegate before and
+ * after the operation, and then updating the selection if needed.
+ *
+ * @return True if delete was successful, false if the object was not deleted.
+ */
+ public boolean deleteObjectAtIndex(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ Object result = notifyDelegate("displayGroupShouldDeleteObject",
+ new Class[] { WODisplayGroup.class, Object.class }, new Object[] { this, target });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return false;
+ }
+
+ deleteObjectAtIndexNoNotify(anIndex);
+
+ if (dataSource != null) {
+ dataSource.deleteObject(target);
+ }
+
+ notifyDelegate("displayGroupDidDeleteObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, target });
+
+ return true;
+ }
+
+ private void deleteObjectAtIndexNoNotify(int anIndex) {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+
+ int i;
+
+ // remove from selected objects if necessary
+ i = indexOf(selectedObjects, target);
+ if (i != NSArray.NotFound) {
+ selectionChanged = true;
+ willChange(); // notify before removing
+ selectedObjects.removeObjectAtIndex(i);
+ selectedIndexes.remove(new Integer(i)); // comps by value
+ } else // notify - no selection change needed
+ {
+ willChange();
+ }
+
+ // remove from all objects
+ i = indexOf(allObjects, target);
+ if (i != NSArray.NotFound) {
+ allObjects.removeObjectAtIndex(i);
+ } else // otherwise should never happen
+ {
// throw new WotonomyException(
// "Displayed object not found in allObjects" );
- }
-
- // remove from displayed objects
- displayedObjects.removeObjectAtIndex( anIndex );
- }
-
- /**
- * Deletes the currently selected objects.
- * This implementation calls deleteObjectAtIndex() for
- * each index in the selection list, immediately returning
- * false if any delete operation fails.
- * @return True if all selected objects were deleted,
- * false if any deletion failed.
- */
- public boolean deleteSelection()
- {
- int i;
- boolean result = true;
-
- Enumeration e = new NSArray( selectedObjects ).objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i == NSArray.NotFound )
- {
- // should never happen
- throw new WotonomyException(
- "Selected object not found in displayedObjects" );
- }
- result = result && deleteObjectAtIndex( i );
- }
-
- return result;
- }
-
- /**
- * Returns a read-only List of all objects in the display group
- * that are currently displayed by the associations.
- */
- public NSArray displayedObjects()
- { // System.out.println( "avoided allocation: displayedObjects" );
- if ( batchSize < 1 ) return displayedObjectsProxy;
- return displayedObjectsProxy.subarrayWithRange(
- new NSRange( batchIndex * batchSize, batchSize ) );
- }
-
- /**
- * Requests a list of objects from the DataSource
- * and calls setObjectArray to populate the list.
- * More specifically, calls endEditing(), asks the
- * delegate, fetches the objects, notifies the delegate,
- * and populates the list. Returns null to force a
- * page reload.
- */
- public Object fetch()
- {
- endEditing();
-
- if ( dataSource == null )
- {
- return null;
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldFetch",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return null;
- }
-
- NSNotificationCenter.defaultCenter().postNotification(
- DisplayGroupWillFetchNotification, this, new NSDictionary() );
-
- NSArray objectList = dataSource.fetchObjects();
-
- notifyDelegate(
- "displayGroupDidFetchObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, objectList } );
-
- setObjectArray( objectList );
-
- if ( ( selectsFirstObjectAfterFetch ) && ( displayedObjects.size() > 0 ) )
- {
- setSelectionIndexes( new NSArray( new Integer( 0 ) ) );
- }
-
- return null;
- }
-
- /**
- * Convenience to call insertNewObjectAtIndex with the current selection plus one,
- * or at the end of the list if there is no selection.
- * Returns null to force a page reload.
- */
- public Object insert()
- {
- NSArray indexes = selectionIndexes();
- int size = indexes.count();
- if ( size == 0 )
- {
- insertNewObjectAtIndex( displayedObjects.count() );
- }
- else
- {
- insertNewObjectAtIndex(
- ((Number)selectedIndexes.objectAtIndex( size-1 )).intValue()+1 );
- }
- return null;
- }
-
- /**
- * Creates a new object at the specified index.
- * Calls insertObjectAtIndex() with the result
- * from sending createObject() to the data source.
- * @return the newly created object.
- */
- public Object insertNewObjectAtIndex ( int anIndex )
- {
- Object result = null;
- if ( dataSource != null )
- {
- result = dataSource.createObject();
- }
- if ( result != null )
- {
- if ( insertedObjectDefaultValues != null )
- {
- Duplicator.writePropertiesForObject(
- insertedObjectDefaultValues, result );
- }
- insertObjectAtIndex( result, anIndex );
- }
- else // create failed
- {
- if ( delegate() != null )
- {
- NSSelector selector = new NSSelector(
- "displayGroupCreateObjectFailed",
- new Class[] { WODisplayGroup.class, EODataSource.class } );
- if ( selector.implementedByObject( delegate() ) )
- {
- try
- {
- selector.invoke( delegate(), new Object[] { this, dataSource } );
- return result;
- }
- catch ( Exception exc )
- {
- System.err.println( "Error notifying delegate: displayGroupCreateObjectFailed" );
- exc.printStackTrace();
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Inserts the specified object into the list at
- * the specified index.
- */
- public void insertObjectAtIndex ( Object anObject, int anIndex )
- {
- Object result = notifyDelegate(
- "displayGroupShouldInsertObject",
- new Class[] { WODisplayGroup.class, Object.class, int.class },
- new Object[] { this, anObject, new Integer(anIndex) } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- return;
- }
-
- updatedObjectIndex = anIndex;
- willChange();
-
- int i;
-
- // add to all objects
- if ( anIndex == displayedObjects.size() )
- {
- allObjects.addObject( anObject );
- }
- else // insert before same object
- {
- Object target = displayedObjects.objectAtIndex( anIndex );
- int targetIndex = indexOf( allObjects, target );
- if ( targetIndex != NSArray.NotFound )
- {
- allObjects.insertObjectAtIndex( anObject, targetIndex );
- }
- else // should never happen
- {
- throw new WotonomyException(
- "Could not find displayed object in all objects list: "
- + target );
- }
- }
-
- // add to displayed objects
- displayedObjects.insertObjectAtIndex( anObject, anIndex );
-
- if ( dataSource != null )
- {
- if ( dataSource instanceof OrderedDataSource )
- {
- ((OrderedDataSource)dataSource).insertObjectAtIndex(
- anObject, anIndex );
- }
- else
- {
- dataSource.insertObject( anObject );
- }
- }
-
- notifyDelegate(
- "displayGroupDidInsertObject",
- new Class[] { WODisplayGroup.class, Object.class },
- new Object[] { this, anObject } );
- }
-
- /**
- * Sets contentsChanged to true and notifies all observers.
- */
- public void redisplay()
- {
- willChange();
- }
-
- /**
- * Sets the selection to the next displayed object after the current
- * selection. If the last object is selected, or if no object
- * is selected, then the first object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectNext()
- {
- int count = displayedObjects.count();
- if ( count == 0 ) return null;
- if ( count == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- int i = -1;
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = -1;
-
- // select next object
- i++;
- if ( i != displayedObjects.count() )
- {
- // set to next object
- selectedObject = displayedObjects.objectAtIndex( i );
- }
- else // out of range
- {
- // set to null
- selectedObject = displayedObjects.objectAtIndex( 0 );
- }
-
- selectObject( selectedObject );
- return null;
- }
-
- /**
- * Sets the selection to the specified object.
- * If the specified object is null or does not exist
- * in the list of displayed objects, the selection
- * will be cleared.
- * @return true if the object was selected.
- */
- public boolean selectObject ( Object anObject )
- {
- if ( ( anObject == null ) ||
- ( indexOf( displayedObjects, anObject )
- == NSArray.NotFound ) )
- {
- clearSelection();
- return false;
- }
-
- selectObjectsIdenticalTo( new NSArray( new Object[] { anObject } ) );
- return true;
- }
-
- /**
- * Sets the selection to the specified objects.
- * If the specified list is null or if none of the objects
- * in the list exist in the list of displayed objects, the
- * selection will be cleared.
- * @return true if all specified objects were selected.
- */
- public boolean selectObjectsIdenticalTo ( List anObjectList )
- {
- // optimization: check for resetting of selection
- if ( ( anObjectList != null ) && ( selectedObjects.size() == anObjectList.size() ) )
- {
- boolean identical = true;
- int size = selectedObjects.size();
- for ( int i = 0; ( i < size ) && identical; i++ )
- {
- // compare by reference
- if ( anObjectList.get( i ) != selectedObjects.get( i ) )
- {
- identical = false;
- }
- else if ( displayedObjects.indexOfIdenticalObject(
- anObjectList.get( i ) ) == NSArray.NotFound )
- {
- identical = false;
- }
- }
- if ( identical )
- {
- return true;
- }
- }
-
- Object result = notifyDelegate(
- "displayGroupShouldChangeSelection",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) )
- {
- // need to notify the calling component
- // to revert back to the previous selection
- selectionChanged = true;
- willChange();
- return false;
- }
-
- int i;
- selectionChanged = true;
- willChange();
- Object o;
- selectedObjects.removeAllObjects();
- selectedIndexes.removeAllObjects();
- Iterator it = anObjectList.iterator();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- != NSArray.NotFound )
- {
- selectedObjects.addObject( o );
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
-
- return true;
- }
-
- /**
- * Calls selectObjectsIdenticalTo and if false is returned
- * and selectFirstIfNoMatch is true, selects the first object.
- */
- public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(
- List anObjectList, boolean selectFirstIfNoMatch )
- {
- if ( selectObjectsIdenticalTo( anObjectList ) )
- {
- return true;
- }
- if ( selectFirstIfNoMatch )
- {
- clearSelection();
- selectNext();
- return true;
- }
- return false;
- }
-
- /**
- * Sets the selection to the previous displayed object before the current
- * selection. If the first object is selected, or if no object
- * is selected, then the last object becomes selected.
- * If multiple items are selected, the first selected item is
- * considered the selected item for the purposes of this method.
- * Does not call redisplay().
- * @return null to force a page reload.
- */
- public Object selectPrevious()
- {
- int i = displayedObjects.count();
- if ( i == 0 ) return null;
- if ( i == 1 )
- {
- selectObject( displayedObjects.objectAtIndex( 0 ) );
- return null;
- }
-
- Object selectedObject = selectedObject();
- if ( selectedObject != null )
- {
- i = indexOf( displayedObjects, selectedObject );
- }
- if ( i == NSArray.NotFound ) i = displayedObjects.count();
-
- // select next object
- i--;
- if ( i < 0 )
- {
- // out of range - select last object
- i = displayedObjects.count() - 1;
- }
-
- selectObject( displayedObjects.objectAtIndex( i ) );
- return null;
- }
-
- /**
- * Returns the currently selected object, or null if
- * there is no selection.
- */
- public Object selectedObject()
- {
- if ( selectedObjects.count() == 0 )
- {
- return null;
- }
- return selectedObjects.objectAtIndex( 0 );
- }
-
- /**
- * Returns a read-only List containing all selected objects, if any.
- * Returns an empty list if no objects are selected.
- */
- public NSArray selectedObjects()
- { // System.out.println( "avoided allocation: selectedObjects" );
- return selectedObjectsProxy;
- }
-
- /**
- * Returns a read-only List containing the indexes of all selected
- * objects, if any. The list contains instances of
- * java.lang.Number; call intValue() to retrieve the index.
- */
- public NSArray selectionIndexes()
- {
+ }
+
+ // remove from displayed objects
+ displayedObjects.removeObjectAtIndex(anIndex);
+ }
+
+ /**
+ * Deletes the currently selected objects. This implementation calls
+ * deleteObjectAtIndex() for each index in the selection list, immediately
+ * returning false if any delete operation fails.
+ *
+ * @return True if all selected objects were deleted, false if any deletion
+ * failed.
+ */
+ public boolean deleteSelection() {
+ int i;
+ boolean result = true;
+
+ Enumeration e = new NSArray(selectedObjects).objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i == NSArray.NotFound) {
+ // should never happen
+ throw new WotonomyException("Selected object not found in displayedObjects");
+ }
+ result = result && deleteObjectAtIndex(i);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a read-only List of all objects in the display group that are
+ * currently displayed by the associations.
+ */
+ public NSArray displayedObjects() { // System.out.println( "avoided allocation: displayedObjects" );
+ if (batchSize < 1)
+ return displayedObjectsProxy;
+ return displayedObjectsProxy.subarrayWithRange(new NSRange(batchIndex * batchSize, batchSize));
+ }
+
+ /**
+ * Requests a list of objects from the DataSource and calls setObjectArray to
+ * populate the list. More specifically, calls endEditing(), asks the delegate,
+ * fetches the objects, notifies the delegate, and populates the list. Returns
+ * null to force a page reload.
+ */
+ public Object fetch() {
+ endEditing();
+
+ if (dataSource == null) {
+ return null;
+ }
+
+ Object result = notifyDelegate("displayGroupShouldFetch", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return null;
+ }
+
+ NSNotificationCenter.defaultCenter().postNotification(DisplayGroupWillFetchNotification, this,
+ new NSDictionary());
+
+ NSArray objectList = dataSource.fetchObjects();
+
+ notifyDelegate("displayGroupDidFetchObjects", new Class[] { WODisplayGroup.class, List.class },
+ new Object[] { this, objectList });
+
+ setObjectArray(objectList);
+
+ if ((selectsFirstObjectAfterFetch) && (displayedObjects.size() > 0)) {
+ setSelectionIndexes(new NSArray(new Integer(0)));
+ }
+
+ return null;
+ }
+
+ /**
+ * Convenience to call insertNewObjectAtIndex with the current selection plus
+ * one, or at the end of the list if there is no selection. Returns null to
+ * force a page reload.
+ */
+ public Object insert() {
+ NSArray indexes = selectionIndexes();
+ int size = indexes.count();
+ if (size == 0) {
+ insertNewObjectAtIndex(displayedObjects.count());
+ } else {
+ insertNewObjectAtIndex(((Number) selectedIndexes.objectAtIndex(size - 1)).intValue() + 1);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new object at the specified index. Calls insertObjectAtIndex() with
+ * the result from sending createObject() to the data source.
+ *
+ * @return the newly created object.
+ */
+ public Object insertNewObjectAtIndex(int anIndex) {
+ Object result = null;
+ if (dataSource != null) {
+ result = dataSource.createObject();
+ }
+ if (result != null) {
+ if (insertedObjectDefaultValues != null) {
+ Duplicator.writePropertiesForObject(insertedObjectDefaultValues, result);
+ }
+ insertObjectAtIndex(result, anIndex);
+ } else // create failed
+ {
+ if (delegate() != null) {
+ NSSelector selector = new NSSelector("displayGroupCreateObjectFailed",
+ new Class[] { WODisplayGroup.class, EODataSource.class });
+ if (selector.implementedByObject(delegate())) {
+ try {
+ selector.invoke(delegate(), new Object[] { this, dataSource });
+ return result;
+ } catch (Exception exc) {
+ System.err.println("Error notifying delegate: displayGroupCreateObjectFailed");
+ exc.printStackTrace();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified object into the list at the specified index.
+ */
+ public void insertObjectAtIndex(Object anObject, int anIndex) {
+ Object result = notifyDelegate("displayGroupShouldInsertObject",
+ new Class[] { WODisplayGroup.class, Object.class, int.class },
+ new Object[] { this, anObject, new Integer(anIndex) });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ return;
+ }
+
+ updatedObjectIndex = anIndex;
+ willChange();
+
+ int i;
+
+ // add to all objects
+ if (anIndex == displayedObjects.size()) {
+ allObjects.addObject(anObject);
+ } else // insert before same object
+ {
+ Object target = displayedObjects.objectAtIndex(anIndex);
+ int targetIndex = indexOf(allObjects, target);
+ if (targetIndex != NSArray.NotFound) {
+ allObjects.insertObjectAtIndex(anObject, targetIndex);
+ } else // should never happen
+ {
+ throw new WotonomyException("Could not find displayed object in all objects list: " + target);
+ }
+ }
+
+ // add to displayed objects
+ displayedObjects.insertObjectAtIndex(anObject, anIndex);
+
+ if (dataSource != null) {
+ if (dataSource instanceof OrderedDataSource) {
+ ((OrderedDataSource) dataSource).insertObjectAtIndex(anObject, anIndex);
+ } else {
+ dataSource.insertObject(anObject);
+ }
+ }
+
+ notifyDelegate("displayGroupDidInsertObject", new Class[] { WODisplayGroup.class, Object.class },
+ new Object[] { this, anObject });
+ }
+
+ /**
+ * Sets contentsChanged to true and notifies all observers.
+ */
+ public void redisplay() {
+ willChange();
+ }
+
+ /**
+ * Sets the selection to the next displayed object after the current selection.
+ * If the last object is selected, or if no object is selected, then the first
+ * object becomes selected. If multiple items are selected, the first selected
+ * item is considered the selected item for the purposes of this method. Does
+ * not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectNext() {
+ int count = displayedObjects.count();
+ if (count == 0)
+ return null;
+ if (count == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ int i = -1;
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = -1;
+
+ // select next object
+ i++;
+ if (i != displayedObjects.count()) {
+ // set to next object
+ selectedObject = displayedObjects.objectAtIndex(i);
+ } else // out of range
+ {
+ // set to null
+ selectedObject = displayedObjects.objectAtIndex(0);
+ }
+
+ selectObject(selectedObject);
+ return null;
+ }
+
+ /**
+ * Sets the selection to the specified object. If the specified object is null
+ * or does not exist in the list of displayed objects, the selection will be
+ * cleared.
+ *
+ * @return true if the object was selected.
+ */
+ public boolean selectObject(Object anObject) {
+ if ((anObject == null) || (indexOf(displayedObjects, anObject) == NSArray.NotFound)) {
+ clearSelection();
+ return false;
+ }
+
+ selectObjectsIdenticalTo(new NSArray(new Object[] { anObject }));
+ return true;
+ }
+
+ /**
+ * Sets the selection to the specified objects. If the specified list is null or
+ * if none of the objects in the list exist in the list of displayed objects,
+ * the selection will be cleared.
+ *
+ * @return true if all specified objects were selected.
+ */
+ public boolean selectObjectsIdenticalTo(List anObjectList) {
+ // optimization: check for resetting of selection
+ if ((anObjectList != null) && (selectedObjects.size() == anObjectList.size())) {
+ boolean identical = true;
+ int size = selectedObjects.size();
+ for (int i = 0; (i < size) && identical; i++) {
+ // compare by reference
+ if (anObjectList.get(i) != selectedObjects.get(i)) {
+ identical = false;
+ } else if (displayedObjects.indexOfIdenticalObject(anObjectList.get(i)) == NSArray.NotFound) {
+ identical = false;
+ }
+ }
+ if (identical) {
+ return true;
+ }
+ }
+
+ Object result = notifyDelegate("displayGroupShouldChangeSelection",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if ((result != null) && (Boolean.FALSE.equals(result))) {
+ // need to notify the calling component
+ // to revert back to the previous selection
+ selectionChanged = true;
+ willChange();
+ return false;
+ }
+
+ int i;
+ selectionChanged = true;
+ willChange();
+ Object o;
+ selectedObjects.removeAllObjects();
+ selectedIndexes.removeAllObjects();
+ Iterator it = anObjectList.iterator();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) != NSArray.NotFound) {
+ selectedObjects.addObject(o);
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class }, new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+
+ return true;
+ }
+
+ /**
+ * Calls selectObjectsIdenticalTo and if false is returned and
+ * selectFirstIfNoMatch is true, selects the first object.
+ */
+ public boolean selectObjectsIdenticalToSelectFirstOnNoMatch(List anObjectList, boolean selectFirstIfNoMatch) {
+ if (selectObjectsIdenticalTo(anObjectList)) {
+ return true;
+ }
+ if (selectFirstIfNoMatch) {
+ clearSelection();
+ selectNext();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the selection to the previous displayed object before the current
+ * selection. If the first object is selected, or if no object is selected, then
+ * the last object becomes selected. If multiple items are selected, the first
+ * selected item is considered the selected item for the purposes of this
+ * method. Does not call redisplay().
+ *
+ * @return null to force a page reload.
+ */
+ public Object selectPrevious() {
+ int i = displayedObjects.count();
+ if (i == 0)
+ return null;
+ if (i == 1) {
+ selectObject(displayedObjects.objectAtIndex(0));
+ return null;
+ }
+
+ Object selectedObject = selectedObject();
+ if (selectedObject != null) {
+ i = indexOf(displayedObjects, selectedObject);
+ }
+ if (i == NSArray.NotFound)
+ i = displayedObjects.count();
+
+ // select next object
+ i--;
+ if (i < 0) {
+ // out of range - select last object
+ i = displayedObjects.count() - 1;
+ }
+
+ selectObject(displayedObjects.objectAtIndex(i));
+ return null;
+ }
+
+ /**
+ * Returns the currently selected object, or null if there is no selection.
+ */
+ public Object selectedObject() {
+ if (selectedObjects.count() == 0) {
+ return null;
+ }
+ return selectedObjects.objectAtIndex(0);
+ }
+
+ /**
+ * Returns a read-only List containing all selected objects, if any. Returns an
+ * empty list if no objects are selected.
+ */
+ public NSArray selectedObjects() { // System.out.println( "avoided allocation: selectedObjects" );
+ return selectedObjectsProxy;
+ }
+
+ /**
+ * Returns a read-only List containing the indexes of all selected objects, if
+ * any. The list contains instances of java.lang.Number; call intValue() to
+ * retrieve the index.
+ */
+ public NSArray selectionIndexes() {
// return selectedIndexes;
- int i;
- NSMutableArray result = new NSMutableArray();
- Enumeration e = selectedObjects.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- i = indexOf( displayedObjects, e.nextElement() );
- if ( i != NSArray.NotFound )
- {
- result.addObject( new Integer( i ) );
- }
- else
- {
- System.err.println(
- "Should never happen: selected objects not in displayed objects" );
- new RuntimeException().printStackTrace( System.err );
- }
- }
- return result;
- }
-
- /**
- * Sets the objects managed by this display group.
- * updateDisplayedObjects() is called to filter the
- * display objects. The previous selection will be
- * maintained if possible. The data source is not
- * notified.
- */
- public void setObjectArray ( List anObjectList )
- {
- if ( anObjectList == null ) anObjectList = new NSArray();
-
- Object result = notifyDelegate(
- "displayGroupDisplayArrayForObjects",
- new Class[] { WODisplayGroup.class, List.class },
- new Object[] { this, anObjectList } );
- if ( result != null )
- {
- anObjectList = (List) result;
- }
-
- willChange();
-
- NSArray oldSelectedObjects = new NSArray( selectedObjects ); // copy
-
- // reset allObjects to new list
- allObjects.removeAllObjects();
- allObjects.addObjectsFromArray( anObjectList );
-
- // update the displayed object list
- updateDisplayedObjects();
-
- // restore the selection if possible
- selectObjectsIdenticalTo( oldSelectedObjects );
-
- batchIndex = 0;
- displayBatchContainingSelectedObject();
- }
-
- /**
- * Sets the currently selected object, or clears the
- * selection if the object is not found or is null.
- * Note: it's not clear how this differs from
- * selectObject in the spec. It is recommended that
- * you call selectObject for now.
- */
- public void setSelectedObject ( Object anObject )
- {
- selectObject( anObject );
- }
-
- /**
- * Sets the current selection to the specified objects.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- * Note: it's not clear how this differs from
- * selectObjectsIdenticalTo in the spec.
- * It is recommended that you call that method for now.
- */
- public void setSelectedObjects ( List aList )
- {
- selectObjectsIdenticalTo( aList );
- }
-
- /**
- * Sets the current selection to the objects at the
- * specified indexes. Items in the list are assumed
- * to be instances of java.lang.Number.
- * The previous selection is cleared, and any objects
- * in the display group that are in the specified list
- * are then selected. If no items in the specified list
- * are found in the display group, then the selection is
- * effectively cleared.
- */
- public boolean setSelectionIndexes ( List aList )
- {
- Object o;
- int index;
- NSMutableArray objects = new NSMutableArray();
- Iterator it = aList.iterator();
- while ( it.hasNext() )
- {
- index = ((Number)it.next()).intValue();
- if ( index < displayedObjects.count() )
- {
- o = displayedObjects.objectAtIndex( index );
- if ( o != null )
- {
- objects.add( o );
- }
- }
- }
- return selectObjectsIdenticalTo( objects );
- }
-
- /**
- * Applies the qualifier to all objects and sorts
- * the results to update the list of displayed objects.
- * Observing associations are notified to reflect the changes.
- */
- public void updateDisplayedObjects()
- {
- updatedObjectIndex = -1;
- willChange();
-
- displayedObjects.removeAllObjects();
-
- displayedObjects.addObjectsFromArray( allObjects );
-
- // apply qualifier, if any
- if ( qualifier != null )
- {
- EOQualifier.filterArrayWithQualifier(
- displayedObjects, qualifier );
- }
-
- // apply sort orderings, if any
- NSArray orderings = sortOrderings();
- if ( orderings != null )
- {
- if ( orderings.count() > 0 )
- {
- selectionChanged = true;
- willChange();
- EOSortOrdering.sortArrayUsingKeyOrderArray(
- displayedObjects, orderings );
- }
- }
-
- // make sure the selectedObjects is a subset of displayedObjects
- int i;
- Object o;
- Iterator it = new LinkedList( selectedObjects ).iterator();
- boolean removeflag = false;
- selectedIndexes.removeAllObjects();
- while ( it.hasNext() )
- {
- o = it.next();
- if ( ( i = displayedObjects.indexOfIdenticalObject( o ) )
- == NSArray.NotFound )
- {
- selectedObjects.removeIdenticalObject( o );
- removeflag = true;
- }
- else
- {
- selectedIndexes.addObject( new Integer( i ) );
- }
- }
-
- //Note: it is important to put the
- //selectionChanged = true line below remove.
- if (removeflag)
- {
- selectionChanged = true;
- willChange();
-
- notifyDelegate(
- "displayGroupDidChangeSelection",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- notifyDelegate(
- "displayGroupDidChangeSelectedObjects",
- new Class[] { WODisplayGroup.class },
- new Object[] { this } );
- }
- }
-
- /**
- * Returns the index of the changed object. If more than
- * one object has changed, -1 is returned.
- */
- public int updatedObjectIndex()
- {
- return updatedObjectIndex;
- }
-
- // getting and setting values in objects
-
- /**
- * Returns a value on the selected object for the specified key.
- */
- public Object selectedObjectValueForKey ( String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return null;
- return valueForObject( selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * all selected objects.
- */
- public boolean setSelectedObjectValue (
- Object aValue, String aKey )
- {
- Object selectedObject = selectedObject();
- if ( selectedObject == null ) return false;
- return setValueForObject( aValue, selectedObject, aKey );
- }
-
- /**
- * Sets the specified value for the specified key on
- * the specified object. Validations may be triggered,
- * and error dialogs may appear to the user.
- * @return True if the value was set successfully,
- * false if the value could not be set and the update
- * operation should not continue.
- */
- public boolean setValueForObject (
- Object aValue, Object anObject, String aKey )
- {
- // notify object's observers:
- // this includes us, and will notify our observers
- EOObserverCenter.notifyObserversObjectWillChange( anObject );
-
- //TODO: if key is null, need to remove old object
- // and add new object instead of simply replacing it.
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- ((EOKeyValueCoding)anObject).takeValueForKey( aValue, aKey );
- }
- else
- {
- EOKeyValueCodingSupport.takeValueForKey( anObject, aValue, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return false;
- }
-
- notifyDelegate(
- "displayGroupDidSetValueForObject",
- new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
- new Object[] { this, aValue, anObject, aKey } );
-
- return true;
- }
-
- /**
- * Calls setValueForObject() for the object at
- * the specified index.
- */
- public boolean setValueForObjectAtIndex (
- Object aValue, int anIndex, String aKey )
- {
- return setValueForObject(
- aValue, displayedObjects.objectAtIndex( anIndex ), aKey );
- }
-
- /**
- * Returns the value for the specified key on the specified object.
- */
- public Object valueForObject ( Object anObject, String aKey )
- {
- // empty string is considered the identity property
- if ( aKey == null ) return anObject;
- if ( aKey.equals( "" ) ) return anObject;
-
- try
- {
- if ( anObject instanceof EOKeyValueCoding )
- {
- return ((EOKeyValueCoding)anObject).valueForKey( aKey );
- }
- else
- {
- return EOKeyValueCodingSupport.valueForKey( anObject, aKey );
- }
- }
- catch ( RuntimeException exc )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", exc.getMessage() } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- throw exc;
- }
- return null;
- }
- }
-
- /**
- * Calls valueForObject() for the object at the specified index.
- * Returns null if out of bounds.
- */
- public Object valueForObjectAtIndex ( int anIndex, String aKey )
- {
- if ( displayedObjects.count() <= anIndex ) return null;
- Object o = displayedObjects.objectAtIndex( anIndex );
- return valueForObject( o, aKey );
- }
-
- /**
- * Prints out the list of displayed objects.
- */
- public String toString()
- {
- return displayedObjects.toString();
- }
-
-
- /**
- * Handles notifications from the data source's editing context,
- * looking for InvalidatedAllObjectsInStoreNotification and
- * ObjectsChangedInEditingContextNotification, refetching in
- * the former case and updating displayed objects in the latter.
- * Note: This method is not in the public specification.
- */
- public void objectsInvalidatedInEditingContext( NSNotification aNotification )
- {
- if ( EOObjectStore.InvalidatedAllObjectsInStoreNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRefetch",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- fetch();
- }
- }
- else
- if ( EOEditingContext.ObjectsChangedInEditingContextNotification
- .equals( aNotification.name() ) )
- {
- Object result = notifyDelegate(
- "displayGroupShouldRedisplay",
- new Class[] { WODisplayGroup.class, NSNotification.class },
- new Object[] { this, aNotification } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- int index;
- Enumeration e;
- boolean didChange = false;
- NSDictionary userInfo = aNotification.userInfo();
-
- // inserts are ignored
-
- // mark updated objects as updated
- NSArray updates = (NSArray) userInfo.objectForKey(
- EOObjectStore.UpdatedKey );
- e = updates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: updated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // treat invalidated objects as updated
- NSArray invalidates = (NSArray) userInfo.objectForKey(
- EOObjectStore.InvalidatedKey );
- e = invalidates.objectEnumerator();
- while ( e.hasMoreElements() )
- {
- index = indexOf( displayedObjects, e.nextElement() );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: invalidated: " + index );
- if ( ! didChange )
- {
- didChange = true;
- willChange();
- updatedObjectIndex = index;
- }
- else
- {
- updatedObjectIndex = -1;
- }
- }
- }
-
- // remove deletes from display group if they exist
- NSArray deletes = (NSArray) userInfo.objectForKey(
- EOObjectStore.DeletedKey );
- e = deletes.objectEnumerator();
- Object o;
- while ( e.hasMoreElements() )
- {
- o = e.nextElement();
- index = indexOf( displayedObjects, o );
- if ( index != NSArray.NotFound )
- {
- //System.out.println( "WODisplayGroup: deleted: " + o );
- deleteObjectAtIndexNoNotify( index );
- }
- }
-
- if ( !usesOptimisticRefresh() )
- {
- updateDisplayedObjects();
- }
- }
- }
-
- }
-
- // static methods
-
- /**
- * Specifies the default behavior for whether changes
- * should be validated immediately for all display groups.
- */
- public static boolean
- globalDefaultForValidatesChangesImmediately()
- {
- return globalDefaultForValidatesChangesImmediately;
- }
-
- /**
- * Specifies the default string matching format for all
- * display groups.
- */
- public static String globalDefaultStringMatchFormat()
- {
- return globalDefaultStringMatchFormat;
- }
-
- /**
- * Specifies the default string matching operator for all
- * display groups.
- */
- public static String globalDefaultStringMatchOperator()
- {
- return globalDefaultStringMatchOperator;
- }
-
- /**
- * Sets the default behavior for validating changes
- * for all display groups.
- */
- public static void
- setGlobalDefaultForValidatesChangesImmediately (
- boolean validatesImmediately )
- {
- globalDefaultForValidatesChangesImmediately =
- validatesImmediately;
- }
-
- /**
- * Sets the default string matching format that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchFormat ( String aFormat )
- {
- globalDefaultStringMatchFormat = aFormat;
- }
-
- /**
- * Sets the default string matching operator that
- * will be used by all display groups.
- */
- public static void
- setGlobalDefaultStringMatchOperator ( String anOperator )
- {
- globalDefaultStringMatchOperator = anOperator;
- }
-
- /**
- * Needed because we don't inherit from NSObject.
- * Calls EOObserverCenter.notifyObserversObjectWillChange.
- */
- protected void willChange()
- {
- EOObserverCenter.notifyObserversObjectWillChange( this );
- }
-
- /**
- * Returns the index of the specified object in the
- * specified NSArray, comparing by value or by reference
- * as determined by the private instance variable
- * compareByReference. If not found, returns NSArray.NotFound.
- */
- private int indexOf( NSArray anArray, Object anObject )
- {
- if ( compareByReference )
- {
- return anArray.indexOfIdenticalObject( anObject );
- }
- else
- {
- return anArray.indexOf( anObject );
- }
- }
-
- // interface EOObserving
-
- /**
- * Receives notifications of changes from objects that
- * are managed by this display group. This implementation
- * sets updatedObjectIndex as appropriate.
- */
- public void objectWillChange(Object anObject)
- {
- int index = indexOf( displayedObjects, anObject );
- if ( index != NSArray.NotFound )
- {
- updatedObjectIndex = index;
- willChange();
- }
- }
-
- // interface EOEditingContext.Editor
-
- /**
- * Called before the editing context begins to save changes.
- * This implementation calls endEditing().
- */
- public void editingContextWillSaveChanges(
- EOEditingContext anEditingContext )
- {
- endEditing();
- }
-
- /**
- * Called to determine whether this editor has changes
- * that have not been committed to the object in the context.
- * This implementation returns false.
- */
- public boolean editorHasChangesForEditingContext(
- EOEditingContext anEditingContext )
- {
- return false;
- }
-
- // interface EOEditingContext.MessageHandler
-
- /**
- * Called to display a message for an error that occurred
- * in the specified editing context. If the delegate allows,
- * this implementation writes a message to the standard output.
- * Override to customize.
- */
- public void editingContextPresentErrorMessage(
- EOEditingContext anEditingContext,
- String aMessage )
- {
- Object result = notifyDelegate(
- "displayGroupShouldDisplayAlert",
- new Class[] { WODisplayGroup.class, String.class, String.class },
- new Object[] { this, "Error", aMessage } );
- if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) )
- {
- System.out.println( aMessage );
- }
- }
-
- /**
- * Called by the specified object store to determine whether
- * fetching should continue, where count is the current count
- * and limit is the limit as specified by the fetch specification.
- * This implementation returns true. Override to customize.
- */
- public boolean editingContextShouldContinueFetching(
- EOEditingContext anEditingContext,
- int count,
- int limit,
- EOObjectStore anObjectStore )
- {
- return true;
- }
-
- /**
- * Sends the specified message to the delegate.
- * Returns the return value of the method,
- * or null if no return value or no delegate
- * or no implementation.
- */
- private Object notifyDelegate(
- String aMethodName, Class[] types, Object[] params )
- {
- try
- {
- Object delegate = delegate();
- if ( delegate == null ) return null;
- return NSSelector.invoke(
- aMethodName, types, delegate, params );
- }
- catch ( NoSuchMethodException e )
- {
- // ignore: not implemented
- }
- catch ( Exception exc )
- {
- // log to standard error
- System.err.println(
- "Error while messaging delegate: " +
- delegate + " : " + aMethodName );
- exc.printStackTrace();
- }
-
- return null;
- }
-
- /**
- * DisplayGroups can delegate important decisions to a Delegate.
- * Note that DisplayGroup doesn't require its delegates to implement
- * this interface: rather, this interface defines the methods that
- * DisplayGroup will attempt to invoke dynamically on its delegate.
- * The delegate may choose to implement only a subset of the methods
- * on the interface.
- */
- public interface Delegate
- {
- /**
- * Called when the specified data source fails
- * to create an object for the specified display group.
- */
- void displayGroupCreateObjectFailed (
- WODisplayGroup aDisplayGroup,
- EODataSource aDataSource );
-
- /**
- * Called after the specified display group's
- * data source is changed.
- */
- void displayGroupDidChangeDataSource (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after a change occurs in the specified
- * display group's selected objects.
- */
- void displayGroupDidChangeSelectedObjects (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group's
- * selection has changed.
- */
- void displayGroupDidChangeSelection (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called after the specified display group has
- * deleted the specified object.
- */
- void displayGroupDidDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has fetched the specified object list.
- */
- void displayGroupDidFetchObjects (
- WODisplayGroup aDisplayGroup,
- List anObjectList );
-
- /**
- * Called after the specified display group
- * has inserted the specified object into
- * its internal object list.
- */
- void displayGroupDidInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called after the specified display group
- * has set the specified value for the specified
- * object and key.
- */
- void displayGroupDidSetValueForObject (
- WODisplayGroup aDisplayGroup,
- Object aValue,
- Object anObject,
- String aKey );
-
- /**
- * Called by the specified display group to
- * determine what objects should be displayed
- * for the objects in the specified list.
- * @return An NSArray containing the objects
- * to be displayed for the objects in the
- * specified list.
- */
- NSArray displayGroupDisplayArrayForObjects (
- WODisplayGroup aDisplayGroup,
- List aList );
-
- /**
- * Called by the specified display group before
- * it attempts to change the selection.
- * @return True to allow the selection to change,
- * false otherwise.
- */
- boolean displayGroupShouldChangeSelection (
- WODisplayGroup aDisplayGroup,
- List aSelectionList );
-
- /**
- * Called by the specified display group before
- * it attempts to delete the specified object.
- * @return True to allow the object to be deleted
- * false to prevent the deletion.
- */
- boolean displayGroupShouldDeleteObject (
- WODisplayGroup aDisplayGroup,
- Object anObject );
-
- /**
- * Called by the specified display group before
- * it attempts display the specified alert to
- * the user.
- * @return True to allow the message to be
- * displayed, false if you want to handle the
- * alert yourself and suppress the display group's
- * notification.
- */
- boolean displayGroupShouldDisplayAlert (
- WODisplayGroup aDisplayGroup,
- String aTitle,
- String aMessage );
-
- /**
- * Called by the specified display group before
- * it attempts fetch objects.
- * @return True to allow the fetch to take place,
- * false to prevent the fetch.
- */
- boolean displayGroupShouldFetch (
- WODisplayGroup aDisplayGroup );
-
- /**
- * Called by the specified display group before
- * it attempts to insert the specified object.
- * @return True to allow the object to be inserted
- * false to prevent the insertion.
- */
- boolean displayGroupShouldInsertObject (
- WODisplayGroup aDisplayGroup,
- Object anObject,
- int anIndex );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * ObjectsChangedInEditingContextNotification.
- * @return True to allow the display group to
- * update the display (recommended), false
- * to prevent the update.
- */
- boolean displayGroupShouldRedisplay (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- /**
- * Called by the specified display group when
- * it receives the specified
- * InvalidatedAllObjectsInStoreNotification.
- * @return True to allow the display group to
- * refetch (recommended), false to prevent the
- * refetch.
- */
- boolean displayGroupShouldRefetch (
- WODisplayGroup aDisplayGroup,
- NSNotification aNotification );
-
- }
+ int i;
+ NSMutableArray result = new NSMutableArray();
+ Enumeration e = selectedObjects.objectEnumerator();
+ while (e.hasMoreElements()) {
+ i = indexOf(displayedObjects, e.nextElement());
+ if (i != NSArray.NotFound) {
+ result.addObject(new Integer(i));
+ } else {
+ System.err.println("Should never happen: selected objects not in displayed objects");
+ new RuntimeException().printStackTrace(System.err);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the objects managed by this display group. updateDisplayedObjects() is
+ * called to filter the display objects. The previous selection will be
+ * maintained if possible. The data source is not notified.
+ */
+ public void setObjectArray(List anObjectList) {
+ if (anObjectList == null)
+ anObjectList = new NSArray();
+
+ Object result = notifyDelegate("displayGroupDisplayArrayForObjects",
+ new Class[] { WODisplayGroup.class, List.class }, new Object[] { this, anObjectList });
+ if (result != null) {
+ anObjectList = (List) result;
+ }
+
+ willChange();
+
+ NSArray oldSelectedObjects = new NSArray(selectedObjects); // copy
+
+ // reset allObjects to new list
+ allObjects.removeAllObjects();
+ allObjects.addObjectsFromArray(anObjectList);
+
+ // update the displayed object list
+ updateDisplayedObjects();
+
+ // restore the selection if possible
+ selectObjectsIdenticalTo(oldSelectedObjects);
+
+ batchIndex = 0;
+ displayBatchContainingSelectedObject();
+ }
+
+ /**
+ * Sets the currently selected object, or clears the selection if the object is
+ * not found or is null. Note: it's not clear how this differs from selectObject
+ * in the spec. It is recommended that you call selectObject for now.
+ */
+ public void setSelectedObject(Object anObject) {
+ selectObject(anObject);
+ }
+
+ /**
+ * Sets the current selection to the specified objects. The previous selection
+ * is cleared, and any objects in the display group that are in the specified
+ * list are then selected. If no items in the specified list are found in the
+ * display group, then the selection is effectively cleared. Note: it's not
+ * clear how this differs from selectObjectsIdenticalTo in the spec. It is
+ * recommended that you call that method for now.
+ */
+ public void setSelectedObjects(List aList) {
+ selectObjectsIdenticalTo(aList);
+ }
+
+ /**
+ * Sets the current selection to the objects at the specified indexes. Items in
+ * the list are assumed to be instances of java.lang.Number. The previous
+ * selection is cleared, and any objects in the display group that are in the
+ * specified list are then selected. If no items in the specified list are found
+ * in the display group, then the selection is effectively cleared.
+ */
+ public boolean setSelectionIndexes(List aList) {
+ Object o;
+ int index;
+ NSMutableArray objects = new NSMutableArray();
+ Iterator it = aList.iterator();
+ while (it.hasNext()) {
+ index = ((Number) it.next()).intValue();
+ if (index < displayedObjects.count()) {
+ o = displayedObjects.objectAtIndex(index);
+ if (o != null) {
+ objects.add(o);
+ }
+ }
+ }
+ return selectObjectsIdenticalTo(objects);
+ }
+
+ /**
+ * Applies the qualifier to all objects and sorts the results to update the list
+ * of displayed objects. Observing associations are notified to reflect the
+ * changes.
+ */
+ public void updateDisplayedObjects() {
+ updatedObjectIndex = -1;
+ willChange();
+
+ displayedObjects.removeAllObjects();
+
+ displayedObjects.addObjectsFromArray(allObjects);
+
+ // apply qualifier, if any
+ if (qualifier != null) {
+ EOQualifier.filterArrayWithQualifier(displayedObjects, qualifier);
+ }
+
+ // apply sort orderings, if any
+ NSArray orderings = sortOrderings();
+ if (orderings != null) {
+ if (orderings.count() > 0) {
+ selectionChanged = true;
+ willChange();
+ EOSortOrdering.sortArrayUsingKeyOrderArray(displayedObjects, orderings);
+ }
+ }
+
+ // make sure the selectedObjects is a subset of displayedObjects
+ int i;
+ Object o;
+ Iterator it = new LinkedList(selectedObjects).iterator();
+ boolean removeflag = false;
+ selectedIndexes.removeAllObjects();
+ while (it.hasNext()) {
+ o = it.next();
+ if ((i = displayedObjects.indexOfIdenticalObject(o)) == NSArray.NotFound) {
+ selectedObjects.removeIdenticalObject(o);
+ removeflag = true;
+ } else {
+ selectedIndexes.addObject(new Integer(i));
+ }
+ }
+
+ // Note: it is important to put the
+ // selectionChanged = true line below remove.
+ if (removeflag) {
+ selectionChanged = true;
+ willChange();
+
+ notifyDelegate("displayGroupDidChangeSelection", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { WODisplayGroup.class },
+ new Object[] { this });
+ }
+ }
+
+ /**
+ * Returns the index of the changed object. If more than one object has changed,
+ * -1 is returned.
+ */
+ public int updatedObjectIndex() {
+ return updatedObjectIndex;
+ }
+
+ // getting and setting values in objects
+
+ /**
+ * Returns a value on the selected object for the specified key.
+ */
+ public Object selectedObjectValueForKey(String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return null;
+ return valueForObject(selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on all selected objects.
+ */
+ public boolean setSelectedObjectValue(Object aValue, String aKey) {
+ Object selectedObject = selectedObject();
+ if (selectedObject == null)
+ return false;
+ return setValueForObject(aValue, selectedObject, aKey);
+ }
+
+ /**
+ * Sets the specified value for the specified key on the specified object.
+ * Validations may be triggered, and error dialogs may appear to the user.
+ *
+ * @return True if the value was set successfully, false if the value could not
+ * be set and the update operation should not continue.
+ */
+ public boolean setValueForObject(Object aValue, Object anObject, String aKey) {
+ // notify object's observers:
+ // this includes us, and will notify our observers
+ EOObserverCenter.notifyObserversObjectWillChange(anObject);
+
+ // TODO: if key is null, need to remove old object
+ // and add new object instead of simply replacing it.
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ ((EOKeyValueCoding) anObject).takeValueForKey(aValue, aKey);
+ } else {
+ EOKeyValueCodingSupport.takeValueForKey(anObject, aValue, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return false;
+ }
+
+ notifyDelegate("displayGroupDidSetValueForObject",
+ new Class[] { WODisplayGroup.class, Object.class, Object.class, String.class },
+ new Object[] { this, aValue, anObject, aKey });
+
+ return true;
+ }
+
+ /**
+ * Calls setValueForObject() for the object at the specified index.
+ */
+ public boolean setValueForObjectAtIndex(Object aValue, int anIndex, String aKey) {
+ return setValueForObject(aValue, displayedObjects.objectAtIndex(anIndex), aKey);
+ }
+
+ /**
+ * Returns the value for the specified key on the specified object.
+ */
+ public Object valueForObject(Object anObject, String aKey) {
+ // empty string is considered the identity property
+ if (aKey == null)
+ return anObject;
+ if (aKey.equals(""))
+ return anObject;
+
+ try {
+ if (anObject instanceof EOKeyValueCoding) {
+ return ((EOKeyValueCoding) anObject).valueForKey(aKey);
+ } else {
+ return EOKeyValueCodingSupport.valueForKey(anObject, aKey);
+ }
+ } catch (RuntimeException exc) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", exc.getMessage() });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ throw exc;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Calls valueForObject() for the object at the specified index. Returns null if
+ * out of bounds.
+ */
+ public Object valueForObjectAtIndex(int anIndex, String aKey) {
+ if (displayedObjects.count() <= anIndex)
+ return null;
+ Object o = displayedObjects.objectAtIndex(anIndex);
+ return valueForObject(o, aKey);
+ }
+
+ /**
+ * Prints out the list of displayed objects.
+ */
+ public String toString() {
+ return displayedObjects.toString();
+ }
+
+ /**
+ * Handles notifications from the data source's editing context, looking for
+ * InvalidatedAllObjectsInStoreNotification and
+ * ObjectsChangedInEditingContextNotification, refetching in the former case and
+ * updating displayed objects in the latter. Note: This method is not in the
+ * public specification.
+ */
+ public void objectsInvalidatedInEditingContext(NSNotification aNotification) {
+ if (EOObjectStore.InvalidatedAllObjectsInStoreNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRefetch",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ fetch();
+ }
+ } else if (EOEditingContext.ObjectsChangedInEditingContextNotification.equals(aNotification.name())) {
+ Object result = notifyDelegate("displayGroupShouldRedisplay",
+ new Class[] { WODisplayGroup.class, NSNotification.class }, new Object[] { this, aNotification });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ int index;
+ Enumeration e;
+ boolean didChange = false;
+ NSDictionary userInfo = aNotification.userInfo();
+
+ // inserts are ignored
+
+ // mark updated objects as updated
+ NSArray updates = (NSArray) userInfo.objectForKey(EOObjectStore.UpdatedKey);
+ e = updates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: updated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // treat invalidated objects as updated
+ NSArray invalidates = (NSArray) userInfo.objectForKey(EOObjectStore.InvalidatedKey);
+ e = invalidates.objectEnumerator();
+ while (e.hasMoreElements()) {
+ index = indexOf(displayedObjects, e.nextElement());
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: invalidated: " + index );
+ if (!didChange) {
+ didChange = true;
+ willChange();
+ updatedObjectIndex = index;
+ } else {
+ updatedObjectIndex = -1;
+ }
+ }
+ }
+
+ // remove deletes from display group if they exist
+ NSArray deletes = (NSArray) userInfo.objectForKey(EOObjectStore.DeletedKey);
+ e = deletes.objectEnumerator();
+ Object o;
+ while (e.hasMoreElements()) {
+ o = e.nextElement();
+ index = indexOf(displayedObjects, o);
+ if (index != NSArray.NotFound) {
+ // System.out.println( "WODisplayGroup: deleted: " + o );
+ deleteObjectAtIndexNoNotify(index);
+ }
+ }
+
+ if (!usesOptimisticRefresh()) {
+ updateDisplayedObjects();
+ }
+ }
+ }
+
+ }
+
+ // static methods
+
+ /**
+ * Specifies the default behavior for whether changes should be validated
+ * immediately for all display groups.
+ */
+ public static boolean globalDefaultForValidatesChangesImmediately() {
+ return globalDefaultForValidatesChangesImmediately;
+ }
+
+ /**
+ * Specifies the default string matching format for all display groups.
+ */
+ public static String globalDefaultStringMatchFormat() {
+ return globalDefaultStringMatchFormat;
+ }
+
+ /**
+ * Specifies the default string matching operator for all display groups.
+ */
+ public static String globalDefaultStringMatchOperator() {
+ return globalDefaultStringMatchOperator;
+ }
+
+ /**
+ * Sets the default behavior for validating changes for all display groups.
+ */
+ public static void setGlobalDefaultForValidatesChangesImmediately(boolean validatesImmediately) {
+ globalDefaultForValidatesChangesImmediately = validatesImmediately;
+ }
+
+ /**
+ * Sets the default string matching format that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchFormat(String aFormat) {
+ globalDefaultStringMatchFormat = aFormat;
+ }
+
+ /**
+ * Sets the default string matching operator that will be used by all display
+ * groups.
+ */
+ public static void setGlobalDefaultStringMatchOperator(String anOperator) {
+ globalDefaultStringMatchOperator = anOperator;
+ }
+
+ /**
+ * Needed because we don't inherit from NSObject. Calls
+ * EOObserverCenter.notifyObserversObjectWillChange.
+ */
+ protected void willChange() {
+ EOObserverCenter.notifyObserversObjectWillChange(this);
+ }
+
+ /**
+ * Returns the index of the specified object in the specified NSArray, comparing
+ * by value or by reference as determined by the private instance variable
+ * compareByReference. If not found, returns NSArray.NotFound.
+ */
+ private int indexOf(NSArray anArray, Object anObject) {
+ if (compareByReference) {
+ return anArray.indexOfIdenticalObject(anObject);
+ } else {
+ return anArray.indexOf(anObject);
+ }
+ }
+
+ // interface EOObserving
+
+ /**
+ * Receives notifications of changes from objects that are managed by this
+ * display group. This implementation sets updatedObjectIndex as appropriate.
+ */
+ public void objectWillChange(Object anObject) {
+ int index = indexOf(displayedObjects, anObject);
+ if (index != NSArray.NotFound) {
+ updatedObjectIndex = index;
+ willChange();
+ }
+ }
+
+ // interface EOEditingContext.Editor
+
+ /**
+ * Called before the editing context begins to save changes. This implementation
+ * calls endEditing().
+ */
+ public void editingContextWillSaveChanges(EOEditingContext anEditingContext) {
+ endEditing();
+ }
+
+ /**
+ * Called to determine whether this editor has changes that have not been
+ * committed to the object in the context. This implementation returns false.
+ */
+ public boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext) {
+ return false;
+ }
+
+ // interface EOEditingContext.MessageHandler
+
+ /**
+ * Called to display a message for an error that occurred in the specified
+ * editing context. If the delegate allows, this implementation writes a message
+ * to the standard output. Override to customize.
+ */
+ public void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage) {
+ Object result = notifyDelegate("displayGroupShouldDisplayAlert",
+ new Class[] { WODisplayGroup.class, String.class, String.class },
+ new Object[] { this, "Error", aMessage });
+ if ((result == null) || (Boolean.TRUE.equals(result))) {
+ System.out.println(aMessage);
+ }
+ }
+
+ /**
+ * Called by the specified object store to determine whether fetching should
+ * continue, where count is the current count and limit is the limit as
+ * specified by the fetch specification. This implementation returns true.
+ * Override to customize.
+ */
+ public boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit,
+ EOObjectStore anObjectStore) {
+ return true;
+ }
+
+ /**
+ * Sends the specified message to the delegate. Returns the return value of the
+ * method, or null if no return value or no delegate or no implementation.
+ */
+ private Object notifyDelegate(String aMethodName, Class[] types, Object[] params) {
+ try {
+ Object delegate = delegate();
+ if (delegate == null)
+ return null;
+ return NSSelector.invoke(aMethodName, types, delegate, params);
+ } catch (NoSuchMethodException e) {
+ // ignore: not implemented
+ } catch (Exception exc) {
+ // log to standard error
+ System.err.println("Error while messaging delegate: " + delegate + " : " + aMethodName);
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * DisplayGroups can delegate important decisions to a Delegate. Note that
+ * DisplayGroup doesn't require its delegates to implement this interface:
+ * rather, this interface defines the methods that DisplayGroup will attempt to
+ * invoke dynamically on its delegate. The delegate may choose to implement only
+ * a subset of the methods on the interface.
+ */
+ public interface Delegate {
+ /**
+ * Called when the specified data source fails to create an object for the
+ * specified display group.
+ */
+ void displayGroupCreateObjectFailed(WODisplayGroup aDisplayGroup, EODataSource aDataSource);
+
+ /**
+ * Called after the specified display group's data source is changed.
+ */
+ void displayGroupDidChangeDataSource(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after a change occurs in the specified display group's selected
+ * objects.
+ */
+ void displayGroupDidChangeSelectedObjects(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group's selection has changed.
+ */
+ void displayGroupDidChangeSelection(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called after the specified display group has deleted the specified object.
+ */
+ void displayGroupDidDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has fetched the specified object
+ * list.
+ */
+ void displayGroupDidFetchObjects(WODisplayGroup aDisplayGroup, List anObjectList);
+
+ /**
+ * Called after the specified display group has inserted the specified object
+ * into its internal object list.
+ */
+ void displayGroupDidInsertObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called after the specified display group has set the specified value for the
+ * specified object and key.
+ */
+ void displayGroupDidSetValueForObject(WODisplayGroup aDisplayGroup, Object aValue, Object anObject,
+ String aKey);
+
+ /**
+ * Called by the specified display group to determine what objects should be
+ * displayed for the objects in the specified list.
+ *
+ * @return An NSArray containing the objects to be displayed for the objects in
+ * the specified list.
+ */
+ NSArray displayGroupDisplayArrayForObjects(WODisplayGroup aDisplayGroup, List aList);
+
+ /**
+ * Called by the specified display group before it attempts to change the
+ * selection.
+ *
+ * @return True to allow the selection to change, false otherwise.
+ */
+ boolean displayGroupShouldChangeSelection(WODisplayGroup aDisplayGroup, List aSelectionList);
+
+ /**
+ * Called by the specified display group before it attempts to delete the
+ * specified object.
+ *
+ * @return True to allow the object to be deleted false to prevent the deletion.
+ */
+ boolean displayGroupShouldDeleteObject(WODisplayGroup aDisplayGroup, Object anObject);
+
+ /**
+ * Called by the specified display group before it attempts display the
+ * specified alert to the user.
+ *
+ * @return True to allow the message to be displayed, false if you want to
+ * handle the alert yourself and suppress the display group's
+ * notification.
+ */
+ boolean displayGroupShouldDisplayAlert(WODisplayGroup aDisplayGroup, String aTitle, String aMessage);
+
+ /**
+ * Called by the specified display group before it attempts fetch objects.
+ *
+ * @return True to allow the fetch to take place, false to prevent the fetch.
+ */
+ boolean displayGroupShouldFetch(WODisplayGroup aDisplayGroup);
+
+ /**
+ * Called by the specified display group before it attempts to insert the
+ * specified object.
+ *
+ * @return True to allow the object to be inserted false to prevent the
+ * insertion.
+ */
+ boolean displayGroupShouldInsertObject(WODisplayGroup aDisplayGroup, Object anObject, int anIndex);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * ObjectsChangedInEditingContextNotification.
+ *
+ * @return True to allow the display group to update the display (recommended),
+ * false to prevent the update.
+ */
+ boolean displayGroupShouldRedisplay(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ /**
+ * Called by the specified display group when it receives the specified
+ * InvalidatedAllObjectsInStoreNotification.
+ *
+ * @return True to allow the display group to refetch (recommended), false to
+ * prevent the refetch.
+ */
+ boolean displayGroupShouldRefetch(WODisplayGroup aDisplayGroup, NSNotification aNotification);
+
+ }
}
/*
- * $Log$
- * Revision 1.2 2006/02/19 01:44:02 cgruber
- * Add xmlrpc files
- * Remove jclark and replace with dom4j and javax.xml.sax stuff
- * Re-work dependencies and imports so it all compiles.
+ * $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
+ * and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
+ * imports so it all compiles.
*
- * Revision 1.1 2006/02/16 13:22:22 cgruber
- * Check in all sources in eclipse-friendly maven-enabled packages.
+ * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
+ * eclipse-friendly maven-enabled packages.
*
- * Revision 1.6 2003/08/07 00:15:15 chochos
- * general cleanup (mostly removing unused imports)
+ * Revision 1.6 2003/08/07 00:15:15 chochos general cleanup (mostly removing
+ * unused imports)
*
- * Revision 1.5 2003/01/22 23:01:06 mpowers
- * Better handling for index out of bounds.
+ * Revision 1.5 2003/01/22 23:01:06 mpowers Better handling for index out of
+ * bounds.
*
- * Revision 1.4 2003/01/21 22:27:02 mpowers
- * Corrected context id usage.
+ * Revision 1.4 2003/01/21 22:27:02 mpowers Corrected context id usage.
* Implemented backtracking.
*
- * Revision 1.3 2003/01/21 17:54:01 mpowers
- * Batch indices are one-based, not zero-based.
+ * Revision 1.3 2003/01/21 17:54:01 mpowers Batch indices are one-based, not
+ * zero-based.
*
- * Revision 1.2 2003/01/21 14:38:42 mpowers
- * Fixed batching.
+ * Revision 1.2 2003/01/21 14:38:42 mpowers Fixed batching.
*
- * Revision 1.1 2003/01/18 23:30:42 mpowers
- * WODisplayGroup now compiles.
+ * Revision 1.1 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles.
*
- * Revision 1.46 2002/10/24 21:15:36 mpowers
- * New implementations of NSArray and subclasses.
+ * Revision 1.46 2002/10/24 21:15:36 mpowers New implementations of NSArray and
+ * subclasses.
*
- * Revision 1.45 2002/10/24 18:20:20 mpowers
- * Because NSArray is read-only, we are returning our internal representations
- * to callers of allObjects(), displayedObjects(), and selectedObjects().
+ * Revision 1.45 2002/10/24 18:20:20 mpowers Because NSArray is read-only, we
+ * are returning our internal representations to callers of allObjects(),
+ * displayedObjects(), and selectedObjects().
*
- * Revision 1.44 2002/08/06 18:20:25 mpowers
- * Now posting DisplayGroupWillFetch notifications before fetch.
- * Implemented support for usesOptimisticRefresh.
- * No longer supporting inserted/updated/deleted lists: not part of spec.
+ * Revision 1.44 2002/08/06 18:20:25 mpowers Now posting DisplayGroupWillFetch
+ * notifications before fetch. Implemented support for usesOptimisticRefresh. No
+ * longer supporting inserted/updated/deleted lists: not part of spec.
*
- * Revision 1.43 2002/05/17 15:01:49 mpowers
- * Implemented dynamic lookup of delegate methods so delegates no longer
- * need to implement the DisplayGroup.Delegate interface.
+ * Revision 1.43 2002/05/17 15:01:49 mpowers Implemented dynamic lookup of
+ * delegate methods so delegates no longer need to implement the
+ * DisplayGroup.Delegate interface.
*
- * Revision 1.42 2002/03/26 21:46:06 mpowers
- * Contributing EditingContext as a java-friendly convenience.
+ * Revision 1.42 2002/03/26 21:46:06 mpowers Contributing EditingContext as a
+ * java-friendly convenience.
*
- * Revision 1.41 2002/03/11 03:17:56 mpowers
- * Provided control point for coalesced changes.
+ * Revision 1.41 2002/03/11 03:17:56 mpowers Provided control point for
+ * coalesced changes.
*
- * Revision 1.40 2002/03/05 23:18:28 mpowers
- * Added documentation.
- * Added isSelectionPaintedImmediate and isSelectionTracking attributes
- * to TableAssociation.
- * Added getTableAssociation to TableColumnAssociation.
+ * Revision 1.40 2002/03/05 23:18:28 mpowers Added documentation. Added
+ * isSelectionPaintedImmediate and isSelectionTracking attributes to
+ * TableAssociation. Added getTableAssociation to TableColumnAssociation.
*
- * Revision 1.39 2002/02/19 22:26:04 mpowers
- * Implemented EOEditingContext.MessageHandler support.
+ * Revision 1.39 2002/02/19 22:26:04 mpowers Implemented
+ * EOEditingContext.MessageHandler support.
*
- * Revision 1.38 2002/02/19 16:37:38 mpowers
- * Implemented support for EOEditingContext.Editor
+ * Revision 1.38 2002/02/19 16:37:38 mpowers Implemented support for
+ * EOEditingContext.Editor
*
- * Revision 1.37 2001/12/11 22:17:48 mpowers
- * Now properly handling exceptions in valueForObject.
- * No longer trying to retain selection based only on index.
+ * Revision 1.37 2001/12/11 22:17:48 mpowers Now properly handling exceptions in
+ * valueForObject. No longer trying to retain selection based only on index.
*
- * Revision 1.36 2001/11/08 21:42:00 mpowers
- * Now we know what to do with shouldRefetch and shouldRedisplay.
+ * Revision 1.36 2001/11/08 21:42:00 mpowers Now we know what to do with
+ * shouldRefetch and shouldRedisplay.
*
- * Revision 1.35 2001/11/04 18:26:58 mpowers
- * Fixed bug where exceptions were not properly reported when updating
- * a value and the display group did not have a delegate.
+ * Revision 1.35 2001/11/04 18:26:58 mpowers Fixed bug where exceptions were not
+ * properly reported when updating a value and the display group did not have a
+ * delegate.
*
- * Revision 1.34 2001/11/02 20:59:36 mpowers
- * Now correctly ensuring selected objects are a subset of displayed objects.
+ * Revision 1.34 2001/11/02 20:59:36 mpowers Now correctly ensuring selected
+ * objects are a subset of displayed objects.
*
- * Revision 1.33 2001/10/30 22:56:45 mpowers
- * Added support for EOQualifier.
+ * Revision 1.33 2001/10/30 22:56:45 mpowers Added support for EOQualifier.
*
- * Revision 1.32 2001/10/23 22:27:53 mpowers
- * Now running at ObserverPrioritySixth.
+ * Revision 1.32 2001/10/23 22:27:53 mpowers Now running at
+ * ObserverPrioritySixth.
*
- * Revision 1.31 2001/10/23 18:45:05 mpowers
- * Rolling back changes.
+ * Revision 1.31 2001/10/23 18:45:05 mpowers Rolling back changes.
*
- * Revision 1.28 2001/08/22 19:23:41 mpowers
- * No longer asserting objects in all objects list.
+ * Revision 1.28 2001/08/22 19:23:41 mpowers No longer asserting objects in all
+ * objects list.
*
- * Revision 1.27 2001/07/30 16:17:01 mpowers
- * Minor code cleanup.
+ * Revision 1.27 2001/07/30 16:17:01 mpowers Minor code cleanup.
*
- * Revision 1.26 2001/07/10 22:49:07 mpowers
- * Fixed bug in optimization for selectObjectsIdenticalTo (found by Dongzhi).
+ * Revision 1.26 2001/07/10 22:49:07 mpowers Fixed bug in optimization for
+ * selectObjectsIdenticalTo (found by Dongzhi).
*
- * Revision 1.25 2001/06/19 15:40:21 mpowers
- * Now only changing the selection if the new selection is different
- * from the old.
+ * Revision 1.25 2001/06/19 15:40:21 mpowers Now only changing the selection if
+ * the new selection is different from the old.
*
- * Revision 1.24 2001/05/24 17:36:15 mpowers
- * Fixed problem with selectedObjectsIdenticalTo: it was using compare
- * by value instead of compare by reference.
+ * Revision 1.24 2001/05/24 17:36:15 mpowers Fixed problem with
+ * selectedObjectsIdenticalTo: it was using compare by value instead of compare
+ * by reference.
*
- * Revision 1.23 2001/05/18 21:09:19 mpowers
- * Now throwing exceptions if the delegate cannot handle error from update.
+ * Revision 1.23 2001/05/18 21:09:19 mpowers Now throwing exceptions if the
+ * delegate cannot handle error from update.
*
- * Revision 1.22 2001/05/14 15:26:12 mpowers
- * Now checking for null delegate before and after selection change.
+ * Revision 1.22 2001/05/14 15:26:12 mpowers Now checking for null delegate
+ * before and after selection change.
*
- * Revision 1.21 2001/05/08 18:47:34 mpowers
- * Minor fixes for d3.
+ * Revision 1.21 2001/05/08 18:47:34 mpowers Minor fixes for d3.
*
- * Revision 1.20 2001/04/29 22:02:45 mpowers
- * Work on id transposing between editing contexts.
+ * Revision 1.20 2001/04/29 22:02:45 mpowers Work on id transposing between
+ * editing contexts.
*
- * Revision 1.19 2001/04/13 16:38:09 mpowers
- * Alpha3 release.
+ * Revision 1.19 2001/04/13 16:38:09 mpowers Alpha3 release.
*
- * Revision 1.18 2001/04/03 20:36:01 mpowers
- * Fixed refaulting/reverting/invalidating to be self-consistent.
+ * Revision 1.18 2001/04/03 20:36:01 mpowers Fixed
+ * refaulting/reverting/invalidating to be self-consistent.
*
- * Revision 1.17 2001/03/29 03:31:13 mpowers
- * No longer using Introspector.
+ * Revision 1.17 2001/03/29 03:31:13 mpowers No longer using Introspector.
*
- * Revision 1.16 2001/02/27 03:32:18 mpowers
- * Implemented default values for new objects.
+ * Revision 1.16 2001/02/27 03:32:18 mpowers Implemented default values for new
+ * objects.
*
- * Revision 1.15 2001/02/27 02:11:17 mpowers
- * Now throwing exception when cloning fails.
- * Removed debugging printlns.
+ * Revision 1.15 2001/02/27 02:11:17 mpowers Now throwing exception when cloning
+ * fails. Removed debugging printlns.
*
- * Revision 1.14 2001/02/26 22:41:51 mpowers
- * Implemented null placeholder classes.
- * Duplicator now uses NSNull.
- * No longer catching base exception class.
+ * Revision 1.14 2001/02/26 22:41:51 mpowers Implemented null placeholder
+ * classes. Duplicator now uses NSNull. No longer catching base exception class.
*
- * Revision 1.13 2001/02/26 15:53:22 mpowers
- * Fine-tuning notification firing.
+ * Revision 1.13 2001/02/26 15:53:22 mpowers Fine-tuning notification firing.
* Child display groups now update properly after parent save or invalidate.
*
- * Revision 1.12 2001/02/22 20:55:06 mpowers
- * Implemented notification handling.
+ * Revision 1.12 2001/02/22 20:55:06 mpowers Implemented notification handling.
*
- * Revision 1.11 2001/02/21 20:40:42 mpowers
- * setObjectArray now falls back to index when trying to retain the
- * same selection.
+ * Revision 1.11 2001/02/21 20:40:42 mpowers setObjectArray now falls back to
+ * index when trying to retain the same selection.
*
- * Revision 1.10 2001/02/20 16:38:55 mpowers
- * MasterDetailAssociations now observe their controlled display group's
- * objects for changes to that the parent object will be marked as updated.
- * Before, only inserts and deletes to an object's items are registered.
- * Also, moved ObservableArray to package access.
+ * Revision 1.10 2001/02/20 16:38:55 mpowers MasterDetailAssociations now
+ * observe their controlled display group's objects for changes to that the
+ * parent object will be marked as updated. Before, only inserts and deletes to
+ * an object's items are registered. Also, moved ObservableArray to package
+ * access.
*
- * Revision 1.9 2001/02/17 17:23:49 mpowers
- * More changes to support compiling with jdk1.1 collections.
+ * Revision 1.9 2001/02/17 17:23:49 mpowers More changes to support compiling
+ * with jdk1.1 collections.
*
- * Revision 1.8 2001/02/17 16:52:05 mpowers
- * Changes in imports to support building with jdk1.1 collections.
+ * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support
+ * building with jdk1.1 collections.
*
- * Revision 1.7 2001/01/24 16:35:37 mpowers
- * Improved documentation on TreeAssociation.
- * SortOrderings are now inherited from parent nodes.
- * Updates after sorting are still lost on TreeController.
+ * Revision 1.7 2001/01/24 16:35:37 mpowers Improved documentation on
+ * TreeAssociation. SortOrderings are now inherited from parent nodes. Updates
+ * after sorting are still lost on TreeController.
*
- * Revision 1.6 2001/01/24 14:23:05 mpowers
- * Added support for OrderedDataSource.
+ * Revision 1.6 2001/01/24 14:23:05 mpowers Added support for OrderedDataSource.
*
- * Revision 1.5 2001/01/12 17:21:37 mpowers
- * Implicit creation of EOSortOrderings now happens in setSortOrderings.
+ * Revision 1.5 2001/01/12 17:21:37 mpowers Implicit creation of EOSortOrderings
+ * now happens in setSortOrderings.
*
- * Revision 1.4 2001/01/11 20:34:26 mpowers
- * Implemented EOSortOrdering and added support in framework.
- * Added header-click to sort table columns.
+ * Revision 1.4 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added
+ * support in framework. Added header-click to sort table columns.
*
- * Revision 1.3 2001/01/10 22:49:44 mpowers
- * Implemented similarly named selection methods instead of
- * throwing exceptions.
+ * Revision 1.3 2001/01/10 22:49:44 mpowers Implemented similarly named
+ * selection methods instead of throwing exceptions.
*
- * Revision 1.2 2001/01/09 20:12:52 mpowers
- * Moved inner classes to package access.
+ * Revision 1.2 2001/01/09 20:12:52 mpowers Moved inner classes to package
+ * access.
*
- * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers
- * Contributing wotonomy.
+ * Revision 1.1.1.1 2000/12/21 15:48:20 mpowers Contributing wotonomy.
*
- * Revision 1.21 2000/12/20 16:25:39 michael
- * Added log to all files.
+ * Revision 1.21 2000/12/20 16:25:39 michael Added log to all files.
*
- * Revision 1.20 2000/12/15 15:04:42 michael
- * Added doc.
+ * Revision 1.20 2000/12/15 15:04:42 michael Added doc.
*
- * Revision 1.19 2000/12/11 13:32:48 michael
- * Finish the much better TreeAssociation implementation.
- * TreeAssociation now has no gui dependencies.
+ * Revision 1.19 2000/12/11 13:32:48 michael Finish the much better
+ * TreeAssociation implementation. TreeAssociation now has no gui dependencies.
*
- * Revision 1.18 2000/12/05 17:41:46 michael
- * Broadcasts selection change after delegate refuses selection change
- * so the initiating association gets refreshed.
+ * Revision 1.18 2000/12/05 17:41:46 michael Broadcasts selection change after
+ * delegate refuses selection change so the initiating association gets
+ * refreshed.
*
*/
-