diff options
Diffstat (limited to 'projects/net.wotonomy.ui/src/main/java')
9 files changed, 3570 insertions, 4519 deletions
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java index 8e9fae2..3512c2a 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java @@ -24,310 +24,200 @@ import net.wotonomy.control.EODataSource; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSNotification; - /** - * A display group delegate that prints messages for each - * of the delegate methods. - * - * @author michael@mpowers.net - * @author $Author: cgruber $ - * @version $Revision: 904 $ - */ - public class DebuggingDelegate implements EODisplayGroup.Delegate - { - /** - * Called when the specified data source fails - * to create an object for the specified display group. - */ - public void displayGroupCreateObjectFailed ( - EODisplayGroup aDisplayGroup, - EODataSource aDataSource ) - { - report( "displayGroupCreateObjectFailed", - aDisplayGroup, - new Object[] { aDataSource } ); - } - - /** - * Called after the specified display group's - * data source is changed. - */ - public void displayGroupDidChangeDataSource ( - EODisplayGroup aDisplayGroup ) - { - report( "displayGroupDidChangeDataSource", - aDisplayGroup, - new Object[] { } ); - } - - /** - * Called after the specified display group's - * selection has changed. - */ - public void displayGroupDidChangeSelectedObjects ( - EODisplayGroup aDisplayGroup ) - { - report( "displayGroupDidChangeSelectedObjects", - aDisplayGroup, - new Object[] { } ); - } - - /** - * Called after the specified display group's - * selection has changed. - */ - public void displayGroupDidChangeSelection ( - EODisplayGroup aDisplayGroup ) - { - report( "displayGroupDidChangeSelection", - aDisplayGroup, - new Object[] { } ); - } - - /** - * Called after the specified object display group's - * selection has changed. - */ - public void displayGroupDidDeleteObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - report( "displayGroupDidDeleteObject", - aDisplayGroup, - new Object[] { anObject } ); - } - - /** - * Called after the specified display group - * has fetched the specified object list. - */ - public void displayGroupDidFetchObjects ( - EODisplayGroup aDisplayGroup, - List anObjectList ) - { - report( "displayGroupDidFetchObjects", - aDisplayGroup, - new Object[] { anObjectList } ); - } - - /** - * Called after the specified display group - * has inserted the specified object into - * its internal object list. - */ - public void displayGroupDidInsertObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - report( "displayGroupDidInsertObject", - aDisplayGroup, - new Object[] { anObject } ); - } - - /** - * Called after the specified display group - * has set the specified value for the specified - * object and key. - */ - public void displayGroupDidSetValueForObject ( - EODisplayGroup aDisplayGroup, - Object aValue, - Object anObject, - String aKey ) - { - report( "displayGroupDidSetValueForObject", - aDisplayGroup, - new Object[] { aValue, anObject, 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. - */ - public NSArray displayGroupDisplayArrayForObjects ( - EODisplayGroup aDisplayGroup, - List aList ) - { - return get( "displayGroupDisplayArrayForObjects", - aDisplayGroup, - aList ); - } - - /** - * Called by the specified display group before - * it attempts to change the selection. - * This implementation returns true. - * @return True to allow the selection to change, - * false otherwise. - */ - public boolean displayGroupShouldChangeSelection ( - EODisplayGroup aDisplayGroup, - List aSelectionList ) - { - return ask( "displayGroupShouldChangeSelection", - aDisplayGroup, - new Object[] { aSelectionList } ); - } - - /** - * Called by the specified display group before - * it attempts to delete the specified object. - * This implementation returns true. - * @return True to allow the object to be deleted - * false to prevent the deletion. - */ - public boolean displayGroupShouldDeleteObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - return ask( "displayGroupShouldDeleteObject", - aDisplayGroup, - new Object[] { anObject } ); - } - - /** - * Called by the specified display group before - * it attempts display the specified alert to - * the user. - * This implementation returns true. - * @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. - */ - public boolean displayGroupShouldDisplayAlert ( - EODisplayGroup aDisplayGroup, - String aTitle, - String aMessage ) - { - return ask( "displayGroupShouldDisplayAlert", - aDisplayGroup, - new Object[] { aTitle, aMessage } ); - } - - /** - * Called by the specified display group before - * it attempts fetch objects. - * This implementation returns true. - * @return True to allow the fetch to take place, - * false to prevent the fetch. - */ - public boolean displayGroupShouldFetch ( - EODisplayGroup aDisplayGroup ) - { - return ask( "displayGroupShouldFetch", - aDisplayGroup, - new Object[] { } ); - } - - /** - * Called by the specified display group before - * it attempts to insert the specified object. - * This implementation returns true. - * @return True to allow the object to be inserted - * false to prevent the insertion. - */ - public boolean displayGroupShouldInsertObject ( - EODisplayGroup aDisplayGroup, - Object anObject, - int anIndex ) - { - return ask( "displayGroupShouldInsertObject", - aDisplayGroup, - new Object[] { anObject, new Integer( anIndex ) } ); - } - - /** - * No idea what this might indicate, - * nor what the notification indicates. - * This implementation returns true. - */ - public boolean displayGroupShouldRedisplay ( - EODisplayGroup aDisplayGroup, - NSNotification aNotification ) - { - return ask( "displayGroupShouldRedisplay", - aDisplayGroup, - new Object[] { aNotification } ); - } - - /** - * No idea what this might indicate, - * nor what the notification indicates. - */ - public boolean displayGroupShouldRefetch ( - EODisplayGroup aDisplayGroup, - NSNotification aNotification ) - { - return ask( "displayGroupShouldRefetch", - aDisplayGroup, - new Object[] { aNotification } ); - } - - /** - * This method is called by all delegate methods that - * return void. - * This implementation calls System.out.println. - * Override to customize or replace the output. - */ - protected void report( String aTitle, - EODisplayGroup aDisplayGroup, - Object[] aParameterArray ) - { - String result = aTitle + " : " + aDisplayGroup; - for ( int i = 0; i < aParameterArray.length; i++ ) - { - result += " : " + aParameterArray[i]; - } - System.out.println( result ); - } - - /** - * This method is called by displayGroupDisplayArrayForObjects. - * This implementation calls report - * and returns a copy of the specified list. - */ - protected NSArray get( String aTitle, - EODisplayGroup aDisplayGroup, - List anObjectList ) - { - report( aTitle, aDisplayGroup, new Object[] { anObjectList } ); - return new NSArray( anObjectList ); - } - - /** - * This method is called by the methods that - * return a boolean. - * This implementation calls report and return true. - */ - protected boolean ask( String aTitle, - EODisplayGroup aDisplayGroup, - Object[] aParameterArray ) - { - report( aTitle, aDisplayGroup, aParameterArray ); - return true; - } - - - } +/** + * A display group delegate that prints messages for each of the delegate + * methods. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class DebuggingDelegate implements EODisplayGroup.Delegate { + /** + * Called when the specified data source fails to create an object for the + * specified display group. + */ + public void displayGroupCreateObjectFailed(EODisplayGroup aDisplayGroup, EODataSource aDataSource) { + report("displayGroupCreateObjectFailed", aDisplayGroup, new Object[] { aDataSource }); + } + + /** + * Called after the specified display group's data source is changed. + */ + public void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup) { + report("displayGroupDidChangeDataSource", aDisplayGroup, new Object[] {}); + } + + /** + * Called after the specified display group's selection has changed. + */ + public void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup) { + report("displayGroupDidChangeSelectedObjects", aDisplayGroup, new Object[] {}); + } + + /** + * Called after the specified display group's selection has changed. + */ + public void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup) { + report("displayGroupDidChangeSelection", aDisplayGroup, new Object[] {}); + } + + /** + * Called after the specified object display group's selection has changed. + */ + public void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) { + report("displayGroupDidDeleteObject", aDisplayGroup, new Object[] { anObject }); + } + + /** + * Called after the specified display group has fetched the specified object + * list. + */ + public void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList) { + report("displayGroupDidFetchObjects", aDisplayGroup, new Object[] { anObjectList }); + } + + /** + * Called after the specified display group has inserted the specified object + * into its internal object list. + */ + public void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject) { + report("displayGroupDidInsertObject", aDisplayGroup, new Object[] { anObject }); + } + + /** + * Called after the specified display group has set the specified value for the + * specified object and key. + */ + public void displayGroupDidSetValueForObject(EODisplayGroup aDisplayGroup, Object aValue, Object anObject, + String aKey) { + report("displayGroupDidSetValueForObject", aDisplayGroup, new Object[] { aValue, anObject, 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. + */ + public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) { + return get("displayGroupDisplayArrayForObjects", aDisplayGroup, aList); + } + + /** + * Called by the specified display group before it attempts to change the + * selection. This implementation returns true. + * + * @return True to allow the selection to change, false otherwise. + */ + public boolean displayGroupShouldChangeSelection(EODisplayGroup aDisplayGroup, List aSelectionList) { + return ask("displayGroupShouldChangeSelection", aDisplayGroup, new Object[] { aSelectionList }); + } + + /** + * Called by the specified display group before it attempts to delete the + * specified object. This implementation returns true. + * + * @return True to allow the object to be deleted false to prevent the deletion. + */ + public boolean displayGroupShouldDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) { + return ask("displayGroupShouldDeleteObject", aDisplayGroup, new Object[] { anObject }); + } + + /** + * Called by the specified display group before it attempts display the + * specified alert to the user. This implementation returns true. + * + * @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. + */ + public boolean displayGroupShouldDisplayAlert(EODisplayGroup aDisplayGroup, String aTitle, String aMessage) { + return ask("displayGroupShouldDisplayAlert", aDisplayGroup, new Object[] { aTitle, aMessage }); + } + + /** + * Called by the specified display group before it attempts fetch objects. This + * implementation returns true. + * + * @return True to allow the fetch to take place, false to prevent the fetch. + */ + public boolean displayGroupShouldFetch(EODisplayGroup aDisplayGroup) { + return ask("displayGroupShouldFetch", aDisplayGroup, new Object[] {}); + } + + /** + * Called by the specified display group before it attempts to insert the + * specified object. This implementation returns true. + * + * @return True to allow the object to be inserted false to prevent the + * insertion. + */ + public boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex) { + return ask("displayGroupShouldInsertObject", aDisplayGroup, new Object[] { anObject, new Integer(anIndex) }); + } + + /** + * No idea what this might indicate, nor what the notification indicates. This + * implementation returns true. + */ + public boolean displayGroupShouldRedisplay(EODisplayGroup aDisplayGroup, NSNotification aNotification) { + return ask("displayGroupShouldRedisplay", aDisplayGroup, new Object[] { aNotification }); + } + + /** + * No idea what this might indicate, nor what the notification indicates. + */ + public boolean displayGroupShouldRefetch(EODisplayGroup aDisplayGroup, NSNotification aNotification) { + return ask("displayGroupShouldRefetch", aDisplayGroup, new Object[] { aNotification }); + } + + /** + * This method is called by all delegate methods that return void. This + * implementation calls System.out.println. Override to customize or replace the + * output. + */ + protected void report(String aTitle, EODisplayGroup aDisplayGroup, Object[] aParameterArray) { + String result = aTitle + " : " + aDisplayGroup; + for (int i = 0; i < aParameterArray.length; i++) { + result += " : " + aParameterArray[i]; + } + System.out.println(result); + } + + /** + * This method is called by displayGroupDisplayArrayForObjects. This + * implementation calls report and returns a copy of the specified list. + */ + protected NSArray get(String aTitle, EODisplayGroup aDisplayGroup, List anObjectList) { + report(aTitle, aDisplayGroup, new Object[] { anObjectList }); + return new NSArray(anObjectList); + } + + /** + * This method is called by the methods that return a boolean. This + * implementation calls report and return true. + */ + protected boolean ask(String aTitle, EODisplayGroup aDisplayGroup, Object[] aParameterArray) { + report(aTitle, aDisplayGroup, aParameterArray); + return true; + } + +} /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2001/01/24 14:37:24 mpowers - * Contributing a delegate useful for debugging. + * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for + * debugging. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java index ed572f4..e801406 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java @@ -24,234 +24,168 @@ import net.wotonomy.control.EODataSource; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSNotification; - /** - * A convenience class for creating display group delegates. - * All methods of the delegate interface are implemented - * to do nothing. - * - * @author michael@mpowers.net - * @author $Author: cgruber $ - * @version $Revision: 904 $ - */ - public class DelegateAdapter implements EODisplayGroup.Delegate - { - /** - * Called when the specified data source fails - * to create an object for the specified display group. - */ - public void displayGroupCreateObjectFailed ( - EODisplayGroup aDisplayGroup, - EODataSource aDataSource ) - { - - } - - /** - * Called after the specified display group's - * data source is changed. - */ - public void displayGroupDidChangeDataSource ( - EODisplayGroup aDisplayGroup ) - { - - } - - /** - * Called after the specified display group's - * selection has changed. - */ - public void displayGroupDidChangeSelectedObjects ( - EODisplayGroup aDisplayGroup ) - { - - } - - /** - * Called after the specified display group's - * selection has changed. - */ - public void displayGroupDidChangeSelection ( - EODisplayGroup aDisplayGroup ) - { - - } - - /** - * Called after the specified object display group's - * selection has changed. - */ - public void displayGroupDidDeleteObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - - } - - /** - * Called after the specified display group - * has fetched the specified object list. - */ - public void displayGroupDidFetchObjects ( - EODisplayGroup aDisplayGroup, - List anObjectList ) - { - - } - - /** - * Called after the specified display group - * has inserted the specified object into - * its internal object list. - */ - public void displayGroupDidInsertObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - - } - - /** - * Called after the specified display group - * has set the specified value for the specified - * object and key. - */ - public void displayGroupDidSetValueForObject ( - EODisplayGroup 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. - */ - public NSArray displayGroupDisplayArrayForObjects ( - EODisplayGroup aDisplayGroup, - List aList ) - { - return new NSArray( aList ); - } - - /** - * Called by the specified display group before - * it attempts to change the selection. - * This implementation returns true. - * @return True to allow the selection to change, - * false otherwise. - */ - public boolean displayGroupShouldChangeSelection ( - EODisplayGroup aDisplayGroup, - List aSelectionList ) - { - return true; - } - - /** - * Called by the specified display group before - * it attempts to delete the specified object. - * This implementation returns true. - * @return True to allow the object to be deleted - * false to prevent the deletion. - */ - public boolean displayGroupShouldDeleteObject ( - EODisplayGroup aDisplayGroup, - Object anObject ) - { - return true; - } - - /** - * Called by the specified display group before - * it attempts display the specified alert to - * the user. - * This implementation returns true. - * @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. - */ - public boolean displayGroupShouldDisplayAlert ( - EODisplayGroup aDisplayGroup, - String aTitle, - String aMessage ) - { - return true; - } - - /** - * Called by the specified display group before - * it attempts fetch objects. - * This implementation returns true. - * @return True to allow the fetch to take place, - * false to prevent the fetch. - */ - public boolean displayGroupShouldFetch ( - EODisplayGroup aDisplayGroup ) - { - return true; - } - - /** - * Called by the specified display group before - * it attempts to insert the specified object. - * This implementation returns true. - * @return True to allow the object to be inserted - * false to prevent the insertion. - */ - public boolean displayGroupShouldInsertObject ( - EODisplayGroup aDisplayGroup, - Object anObject, - int anIndex ) - { - return true; - } - - /** - * No idea what this might indicate, - * nor what the notification indicates. - * This implementation returns true. - */ - public boolean displayGroupShouldRedisplay ( - EODisplayGroup aDisplayGroup, - NSNotification aNotification ) - { - return true; - } - - /** - * No idea what this might indicate, - * nor what the notification indicates. - */ - public boolean displayGroupShouldRefetch ( - EODisplayGroup aDisplayGroup, - NSNotification aNotification ) - { - return true; - } - - } +/** + * A convenience class for creating display group delegates. All methods of the + * delegate interface are implemented to do nothing. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class DelegateAdapter implements EODisplayGroup.Delegate { + /** + * Called when the specified data source fails to create an object for the + * specified display group. + */ + public void displayGroupCreateObjectFailed(EODisplayGroup aDisplayGroup, EODataSource aDataSource) { + + } + + /** + * Called after the specified display group's data source is changed. + */ + public void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup) { + + } + + /** + * Called after the specified display group's selection has changed. + */ + public void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup) { + + } + + /** + * Called after the specified display group's selection has changed. + */ + public void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup) { + + } + + /** + * Called after the specified object display group's selection has changed. + */ + public void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) { + + } + + /** + * Called after the specified display group has fetched the specified object + * list. + */ + public void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList) { + + } + + /** + * Called after the specified display group has inserted the specified object + * into its internal object list. + */ + public void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject) { + + } + + /** + * Called after the specified display group has set the specified value for the + * specified object and key. + */ + public void displayGroupDidSetValueForObject(EODisplayGroup 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. + */ + public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) { + return new NSArray(aList); + } + + /** + * Called by the specified display group before it attempts to change the + * selection. This implementation returns true. + * + * @return True to allow the selection to change, false otherwise. + */ + public boolean displayGroupShouldChangeSelection(EODisplayGroup aDisplayGroup, List aSelectionList) { + return true; + } + + /** + * Called by the specified display group before it attempts to delete the + * specified object. This implementation returns true. + * + * @return True to allow the object to be deleted false to prevent the deletion. + */ + public boolean displayGroupShouldDeleteObject(EODisplayGroup aDisplayGroup, Object anObject) { + return true; + } + + /** + * Called by the specified display group before it attempts display the + * specified alert to the user. This implementation returns true. + * + * @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. + */ + public boolean displayGroupShouldDisplayAlert(EODisplayGroup aDisplayGroup, String aTitle, String aMessage) { + return true; + } + + /** + * Called by the specified display group before it attempts fetch objects. This + * implementation returns true. + * + * @return True to allow the fetch to take place, false to prevent the fetch. + */ + public boolean displayGroupShouldFetch(EODisplayGroup aDisplayGroup) { + return true; + } + + /** + * Called by the specified display group before it attempts to insert the + * specified object. This implementation returns true. + * + * @return True to allow the object to be inserted false to prevent the + * insertion. + */ + public boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex) { + return true; + } + + /** + * No idea what this might indicate, nor what the notification indicates. This + * implementation returns true. + */ + public boolean displayGroupShouldRedisplay(EODisplayGroup aDisplayGroup, NSNotification aNotification) { + return true; + } + + /** + * No idea what this might indicate, nor what the notification indicates. + */ + public boolean displayGroupShouldRefetch(EODisplayGroup aDisplayGroup, NSNotification aNotification) { + return true; + } + +} /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2001/01/24 14:23:17 mpowers - * Contributing DelegateAdapter. + * Revision 1.1 2001/01/24 14:23:17 mpowers Contributing DelegateAdapter. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java index 9fcbe34..d7dd8d8 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DisplayGroup.java @@ -25,276 +25,236 @@ import net.wotonomy.control.EODataSource; import net.wotonomy.control.EOQualifier; /** -* DisplayGroup provides an abstraction of a user interface, -* comprising of an ordered collection of data objects, some -* of which are displayed, and of those some are selected. -* This class extends EODisplayGroup to provide java-friendly -* convenience methods. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class DisplayGroup extends EODisplayGroup -{ - /** - * Returns the current data source backing this display group, - * or null if no dataSource is currently used. - */ - public EODataSource getDataSource() - { - return super.dataSource(); - } - - /** - * Returns the current delegate for this display group, - * or null if no delegate is currently set. - */ - public Object getDelegate() - { - return delegate(); - } - - /** - * Returns the current string matching format. - * If not set, defaults to "%@*". - */ - public String getDefaultStringMatchFormat() - { - return defaultStringMatchFormat(); - } - - /** - * Returns the current string matching operator. - * If not set, defaults to "caseInsensitiveLike". - */ - public String getdefaultStringMatchOperator() - { - return defaultStringMatchOperator(); - } - - /** - * Returns a Map of default values that are applied - * to new objects that are inserted into the list. - */ - public Map getInsertedObjectDefaultValues() - { - return insertedObjectDefaultValues(); - } - - /** - * Returns the keys that were declared when read from - * an external resource file. - */ - public List getLocalKeys() - { - return localKeys(); - } - - /** - * Returns the List of sort orderings for this display group. - */ - public List getSortOrderings () - { - return sortOrderings(); - } - - /** - * Returns a qualifier that will be applied all the objects - * in this display group to determine which objects will - * be displayed. - */ - public EOQualifier getQualifier () - { - return qualifier(); - } - - /** - * Returns a new qualifier built from the three query - * value maps: greater than, equal to, and less than. - */ - public EOQualifier getQualifierFromQueryValues () - { - return qualifierFromQueryValues(); - } - - /** - * Returns a Map containing the mappings of keys - * to binding query values. - */ - public Map getQueryBindingValues() - { - return queryBindingValues(); - } - - /** - * Returns a Map containing the mappings of keys - * to operator values. - */ - public Map getQueryOperatorValues() - { - return queryOperatorValues(); - } - - /** - * Returns a Map containing the mappings of keys - * to query values that will be used to test for equality. - */ - public Map getEqualToQueryValues() - { - return equalToQueryValues(); - } - - /** - * Returns a Map containing the mappings of keys - * to query values that will be used to test for greater value. - */ - public Map getGreaterThanQueryValues() - { - return greaterThanQueryValues(); - } - - /** - * Returns a Map containing the mappings of keys - * to query values that will be used to test for lesser value. - */ - public Map getLessThanQueryValues() - { - return lessThanQueryValues(); - } - - /** - * Returns the association that is currently being edited, - * or null if no editing is taking place. - */ - public EOAssociation getEditingAssociation () - { - return editingAssociation(); - } - - /** - * Returns a List of associations that are observing - * this display group. - */ - public List getObservingAssociations() - { - return observingAssociations(); - } - - /** - * Returns a List containing all objects managed by the display group. - * This includes those objects not visible due to disqualification. - */ - public List getAllObjects() - { - return allObjects(); - } - - /** - * Returns a List of all objects in the display group - * that are currently displayed by the associations. - * The list is a copy of the internal displayed object list. - */ - public List getDisplayedObjects() - { - return displayedObjects(); - } - - /** - * Returns the currently selected object, or null if - * there is no selection. - */ - public Object getSelectedObject() - { - return selectedObject(); - } - - /** - * Returns a List containing all selected objects, if any. - * Returns an empty list if no objects are selected. - */ - public List getSelectedObjects() - { - return selectedObjects(); - } - - /** - * Returns a List containing the indexes of all selected - * objects, if any. The list contains instances of - * java.lang.Number; call intValue() retrieve the index. - */ - public List getSelectionIndexes() - { - return selectionIndexes(); - } - - /** - * Returns the index of the changed object. If more than - * one object has changed, -1 is returned. - */ - public int getUpdatedObjectIndex() - { - return updatedObjectIndex(); - } - - /** - * Returns a value on the selected object for the specified key. - */ - public Object getSelectedObjectValueForKey ( String aKey ) - { - return selectedObjectValueForKey( aKey ); - } - - /** - * Returns the value for the specified key on the specified object. - */ - public Object getValueForObject ( Object anObject, String aKey ) - { - return valueForObject( anObject, aKey ); - } - - /** - * Calls valueForObject() for the object at the specified index. - */ - public Object getValueForObjectAtIndex ( int anIndex, String aKey ) - { - return valueForObjectAtIndex( anIndex, aKey ); - } - - /** - * Specifies the default string matching format for all - * display groups. - */ - public static String getGlobalDefaultStringMatchFormat () - { - return globalDefaultStringMatchFormat(); - } - - /** - * Specifies the default string matching operator for all - * display groups. - */ - public static String getGlobalDefaultStringMatchOperator () - { - return globalDefaultStringMatchOperator(); - } -} + * DisplayGroup provides an abstraction of a user interface, comprising of an + * ordered collection of data objects, some of which are displayed, and of those + * some are selected. This class extends EODisplayGroup to provide java-friendly + * convenience methods. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class DisplayGroup extends EODisplayGroup { + /** + * Returns the current data source backing this display group, or null if no + * dataSource is currently used. + */ + public EODataSource getDataSource() { + return super.dataSource(); + } + + /** + * Returns the current delegate for this display group, or null if no delegate + * is currently set. + */ + public Object getDelegate() { + return delegate(); + } + + /** + * Returns the current string matching format. If not set, defaults to "%@*". + */ + public String getDefaultStringMatchFormat() { + return defaultStringMatchFormat(); + } + + /** + * Returns the current string matching operator. If not set, defaults to + * "caseInsensitiveLike". + */ + public String getdefaultStringMatchOperator() { + return defaultStringMatchOperator(); + } + + /** + * Returns a Map of default values that are applied to new objects that are + * inserted into the list. + */ + public Map getInsertedObjectDefaultValues() { + return insertedObjectDefaultValues(); + } + + /** + * Returns the keys that were declared when read from an external resource file. + */ + public List getLocalKeys() { + return localKeys(); + } + + /** + * Returns the List of sort orderings for this display group. + */ + public List getSortOrderings() { + return sortOrderings(); + } + + /** + * Returns a qualifier that will be applied all the objects in this display + * group to determine which objects will be displayed. + */ + public EOQualifier getQualifier() { + return qualifier(); + } + + /** + * Returns a new qualifier built from the three query value maps: greater than, + * equal to, and less than. + */ + public EOQualifier getQualifierFromQueryValues() { + return qualifierFromQueryValues(); + } + + /** + * Returns a Map containing the mappings of keys to binding query values. + */ + public Map getQueryBindingValues() { + return queryBindingValues(); + } + + /** + * Returns a Map containing the mappings of keys to operator values. + */ + public Map getQueryOperatorValues() { + return queryOperatorValues(); + } + + /** + * Returns a Map containing the mappings of keys to query values that will be + * used to test for equality. + */ + public Map getEqualToQueryValues() { + return equalToQueryValues(); + } + + /** + * Returns a Map containing the mappings of keys to query values that will be + * used to test for greater value. + */ + public Map getGreaterThanQueryValues() { + return greaterThanQueryValues(); + } + + /** + * Returns a Map containing the mappings of keys to query values that will be + * used to test for lesser value. + */ + public Map getLessThanQueryValues() { + return lessThanQueryValues(); + } + + /** + * Returns the association that is currently being edited, or null if no editing + * is taking place. + */ + public EOAssociation getEditingAssociation() { + return editingAssociation(); + } + + /** + * Returns a List of associations that are observing this display group. + */ + public List getObservingAssociations() { + return observingAssociations(); + } + + /** + * Returns a List containing all objects managed by the display group. This + * includes those objects not visible due to disqualification. + */ + public List getAllObjects() { + return allObjects(); + } + + /** + * Returns a List of all objects in the display group that are currently + * displayed by the associations. The list is a copy of the internal displayed + * object list. + */ + public List getDisplayedObjects() { + return displayedObjects(); + } + + /** + * Returns the currently selected object, or null if there is no selection. + */ + public Object getSelectedObject() { + return selectedObject(); + } + + /** + * Returns a List containing all selected objects, if any. Returns an empty list + * if no objects are selected. + */ + public List getSelectedObjects() { + return selectedObjects(); + } + + /** + * Returns a List containing the indexes of all selected objects, if any. The + * list contains instances of java.lang.Number; call intValue() retrieve the + * index. + */ + public List getSelectionIndexes() { + return selectionIndexes(); + } + + /** + * Returns the index of the changed object. If more than one object has changed, + * -1 is returned. + */ + public int getUpdatedObjectIndex() { + return updatedObjectIndex(); + } + + /** + * Returns a value on the selected object for the specified key. + */ + public Object getSelectedObjectValueForKey(String aKey) { + return selectedObjectValueForKey(aKey); + } + + /** + * Returns the value for the specified key on the specified object. + */ + public Object getValueForObject(Object anObject, String aKey) { + return valueForObject(anObject, aKey); + } + + /** + * Calls valueForObject() for the object at the specified index. + */ + public Object getValueForObjectAtIndex(int anIndex, String aKey) { + return valueForObjectAtIndex(anIndex, aKey); + } + + /** + * Specifies the default string matching format for all display groups. + */ + public static String getGlobalDefaultStringMatchFormat() { + return globalDefaultStringMatchFormat(); + } + + /** + * Specifies the default string matching operator for all display groups. + */ + public static String getGlobalDefaultStringMatchOperator() { + return globalDefaultStringMatchOperator(); + } +} /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.2 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.2 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.1 2002/03/26 21:24:43 mpowers - * Contributing DisplayGroup as convenience for people coming from java. + * Revision 1.1 2002/03/26 21:24:43 mpowers Contributing DisplayGroup as + * convenience for people coming from java. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java index 635c5b9..8fb0527 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EOAssociation.java @@ -27,36 +27,34 @@ import net.wotonomy.foundation.NSMutableArray; import net.wotonomy.foundation.NSMutableDictionary; /** -* Associations observe DisplayGroups and associate -* a user interface component with one or more keys -* on the objects in the display group. <br><br> -* -* Associations are created with a ui component in -* the constructor. Then, one or more aspects are -* bound to display groups and/or property keys with -* the bindAspect() method. Finally, the association -* is initialized with the establishConnection() -* method. <br><br> -* -* Per the openstep convention, you do not need to -* retain a reference to the association after it is -* created; the association will be garbage-collected -* when the ui component is garbage-collected. <br><br> -* -* (Because java components don't have delegates like -* openstep components do, java-based associations -* will likely need to implement some sort of listener -* and add itself to the component's list of listeners -* so that the component will have a strong reference -* (and the only reference) to the association.) <br><br> -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class EOAssociation extends EODelayedObserver -{ - // aspect constants + * Associations observe DisplayGroups and associate a user interface component + * with one or more keys on the objects in the display group. <br> + * <br> + * + * Associations are created with a ui component in the constructor. Then, one or + * more aspects are bound to display groups and/or property keys with the + * bindAspect() method. Finally, the association is initialized with the + * establishConnection() method. <br> + * <br> + * + * Per the openstep convention, you do not need to retain a reference to the + * association after it is created; the association will be garbage-collected + * when the ui component is garbage-collected. <br> + * <br> + * + * (Because java components don't have delegates like openstep components do, + * java-based associations will likely need to implement some sort of listener + * and add itself to the component's list of listeners so that the component + * will have a strong reference (and the only reference) to the association.) + * <br> + * <br> + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class EOAssociation extends EODelayedObserver { + // aspect constants public static final String ActionAspect = "action"; public static final String EnabledAspect = "enabled"; public static final String SourceAspect = "source"; @@ -77,489 +75,405 @@ public class EOAssociation extends EODelayedObserver public static final String ObjectsAspect = "objects"; // not in spec public static final String LabelAspect = "label"; // not in spec public static final String IconAspect = "icon"; // not in spec - + public static final String AttributeAspectSignature = "A"; public static final String NullAspectSignature = ""; - public static final String AttributeToOneAspectSignature = "A1"; + public static final String AttributeToOneAspectSignature = "A1"; public static final String ToOneAspectSignature = "1"; - public static final String AttributeToOneToManyAspectSignature = "A1M"; + public static final String AttributeToOneToManyAspectSignature = "A1M"; public static final String ToOneToManyAspectSignature = "1M"; public static final String AttributeToManyAspectSignature = "AM"; public static final String ToManyAspectSignature = "M"; - - protected Object control; - protected NSMutableDictionary aspectToGroup; - protected NSMutableDictionary aspectToKey; - - /** - * Default constructor. - */ - public EOAssociation () - { - aspectToGroup = new NSMutableDictionary(); - aspectToKey = new NSMutableDictionary(); - control = null; - } - - /** - * Constructor specifying the object to be controlled by this - * association. Does not establish connection. - */ - public EOAssociation ( Object anObject ) - { - this(); - control = anObject; - } - - /** - * Returns a List of aspect signatures whose contents - * correspond with the aspects list. Each element is - * a string whose characters represent a capability of - * the corresponding aspect. <ul> - * <li>"A" attribute: the aspect can be bound to - * an attribute.</li> - * <li>"1" to-one: the aspect can be bound to a - * property that returns a single object.</li> - * <li>"M" to-one: the aspect can be bound to a - * property that returns multiple objects.</li> - * </ul> - * An empty signature "" means that the aspect can - * bind without needing a key. - * This implementation returns "A1M" for each - * element in the aspects array. - */ - public static NSArray aspectSignatures () - { - int size = aspects().count(); - NSMutableArray result = new NSMutableArray(); - for ( int i = 0; i < size; i++ ) - { - result.addObject( AttributeToOneToManyAspectSignature ); - } - return result; - } - - /** - * Returns a List that describes the aspects supported - * by this class. Each element in the list is the string - * name of the aspect. This implementation returns an - * empty list. - * - * TODO: Is this static in the WebObjects published API? If not, fix. - */ - public static NSArray aspects () - { - return new NSArray(); - } - - /** - * Returns all registered subclasses of EOAssociation - * for which usableWithObject with the specified object - * returns true. You should only call this method on - * the EOAssociation class. - */ - public static NSArray associationClassesForObject ( - Object anObject ) - { - throw new RuntimeException( "Not implemented yet." ); - } - - /** - * Returns a List of EOAssociation subclasses that, - * for the objects that are usable for this association, - * are less suitable than this association. - * This implementation returns an empty list. - */ - public static NSArray associationClassesSuperseded () - { - return new NSArray(); - } - - - /** - * Binds the specified aspect of this association to the - * specified key on the specified display group. - */ - public void bindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey ) - { + + protected Object control; + protected NSMutableDictionary aspectToGroup; + protected NSMutableDictionary aspectToKey; + + /** + * Default constructor. + */ + public EOAssociation() { + aspectToGroup = new NSMutableDictionary(); + aspectToKey = new NSMutableDictionary(); + control = null; + } + + /** + * Constructor specifying the object to be controlled by this association. Does + * not establish connection. + */ + public EOAssociation(Object anObject) { + this(); + control = anObject; + } + + /** + * Returns a List of aspect signatures whose contents correspond with the + * aspects list. Each element is a string whose characters represent a + * capability of the corresponding aspect. + * <ul> + * <li>"A" attribute: the aspect can be bound to an attribute.</li> + * <li>"1" to-one: the aspect can be bound to a property that returns a single + * object.</li> + * <li>"M" to-one: the aspect can be bound to a property that returns multiple + * objects.</li> + * </ul> + * An empty signature "" means that the aspect can bind without needing a key. + * This implementation returns "A1M" for each element in the aspects array. + */ + public static NSArray aspectSignatures() { + int size = aspects().count(); + NSMutableArray result = new NSMutableArray(); + for (int i = 0; i < size; i++) { + result.addObject(AttributeToOneToManyAspectSignature); + } + return result; + } + + /** + * Returns a List that describes the aspects supported by this class. Each + * element in the list is the string name of the aspect. This implementation + * returns an empty list. + * + * TODO: Is this static in the WebObjects published API? If not, fix. + */ + public static NSArray aspects() { + return new NSArray(); + } + + /** + * Returns all registered subclasses of EOAssociation for which usableWithObject + * with the specified object returns true. You should only call this method on + * the EOAssociation class. + */ + public static NSArray associationClassesForObject(Object anObject) { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Returns a List of EOAssociation subclasses that, for the objects that are + * usable for this association, are less suitable than this association. This + * implementation returns an empty list. + */ + public static NSArray associationClassesSuperseded() { + return new NSArray(); + } + + /** + * Binds the specified aspect of this association to the specified key on the + * specified display group. + */ + public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { // unattach old group, if any - EODisplayGroup oldGroup = displayGroupForAspect( anAspect ); - if ( oldGroup != null ) - { - EOObserverCenter.removeObserver( this, oldGroup ); + EODisplayGroup oldGroup = displayGroupForAspect(anAspect); + if (oldGroup != null) { + EOObserverCenter.removeObserver(this, oldGroup); } // attach new group - if ( aDisplayGroup != null ) - { - aspectToGroup.setObjectForKey( aDisplayGroup, anAspect ); - } - else - { - aspectToGroup.removeObjectForKey( anAspect ); + if (aDisplayGroup != null) { + aspectToGroup.setObjectForKey(aDisplayGroup, anAspect); + } else { + aspectToGroup.removeObjectForKey(anAspect); } // attach new key - if ( aKey != null ) - { - aspectToKey.setObjectForKey( aKey, anAspect ); + if (aKey != null) { + aspectToKey.setObjectForKey(aKey, anAspect); + } else { + aspectToKey.removeObjectForKey(anAspect); } - else - { - aspectToKey.removeObjectForKey( anAspect ); + } + + /** + * Breaks the connection between this association and its object. Override to + * stop listening for events from the object, but remember to call this method. + * This implementation unregisters this association from observing each bound + * display group. + */ + public void breakConnection() { + discardPendingNotification(); + Enumeration e = aspectToGroup.objectEnumerator(); + while (e.hasMoreElements()) { + EOObserverCenter.removeObserver(this, e.nextElement()); } - } - - /** - * Breaks the connection between this association and - * its object. Override to stop listening for events - * from the object, but remember to call this method. - * This implementation unregisters this association - * from observing each bound display group. - */ - public void breakConnection () - { - discardPendingNotification(); - Enumeration e = aspectToGroup.objectEnumerator(); - while ( e.hasMoreElements() ) - { - EOObserverCenter.removeObserver( this, e.nextElement() ); + } + + /** + * Returns whether this association can bind to the specified display group on + * the specified key for the specified aspect. This implementation returns + * false. + */ + public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + return false; + } + + /** + * Copies the binding for each aspect in this association that has a matching + * aspect in the specified association. + */ + public void copyMatchingBindingsFromAssociation(EOAssociation anAssociation) { + // FIXME: this is broken: aspects() returns EOAssociation.aspects() + // NOTE: This is actually quite crazy - should this even be static? -ceg + NSMutableArray ourAspects = new NSMutableArray(this.aspects()); + NSArray theirAspects = anAssociation.aspects(); + + String aspect; + Enumeration e = ourAspects.objectEnumerator(); + while (e.hasMoreElements()) { + aspect = e.nextElement().toString(); + if (theirAspects.containsObject(aspect)) { + this.bindAspect(aspect, anAssociation.displayGroupForAspect(aspect), + anAssociation.displayGroupKeyForAspect(aspect)); + } } - } - - /** - * Returns whether this association can bind to the - * specified display group on the specified key for - * the specified aspect. - * This implementation returns false. - */ - public boolean canBindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey) - { - return false; - } - - /** - * Copies the binding for each aspect in this association - * that has a matching aspect in the specified association. - */ - public void copyMatchingBindingsFromAssociation ( - EOAssociation anAssociation ) - { - //FIXME: this is broken: aspects() returns EOAssociation.aspects() - //NOTE: This is actually quite crazy - should this even be static? -ceg - NSMutableArray ourAspects = new NSMutableArray( this.aspects() ); - NSArray theirAspects = anAssociation.aspects(); - - String aspect; - Enumeration e = ourAspects.objectEnumerator(); - while ( e.hasMoreElements() ) - { - aspect = e.nextElement().toString(); - if ( theirAspects.containsObject( aspect ) ) - { - this.bindAspect( - aspect, - anAssociation.displayGroupForAspect( aspect ), - anAssociation.displayGroupKeyForAspect( aspect ) ); - } - } - } - - /** - * Returns the display group that is bound the specified - * aspect, or null if no display group is currently - * bound to that aspect. - */ - public EODisplayGroup displayGroupForAspect ( String anAspect ) - { - return (EODisplayGroup) aspectToGroup.objectForKey( anAspect ); - } - - /** - * Returns the key for the display group bound to the - * specified aspect, or null if no display group is currently - * bound to that aspect. - */ - public String displayGroupKeyForAspect ( String anAspect ) - { - return (String) aspectToKey.objectForKey( anAspect ); - } - - /** - * The human-readable descriptive name for this association. - * This implementation returns the class name. - */ - public String displayName () // was static - can static method get class name? - { - String className = getClass().getName(); - int index = className.lastIndexOf( "." ); - if ( index == -1 ) return className; - return className.substring( index+1 ); - } - - /** - * Forces this association to cause the object to - * stop editing and validate the user's input. - * This implementation returns true. - * @return false if there were problems validating, - * or true to continue. - */ - public boolean endEditing () - { - return true; - } - - /** - * Establishes a connection between this association - * and the controlled object. Subclasses should populate - * their controlled object from the display group and begin - * listening for events from their controlled object here, - * but remember to call this method. Any existing value - * in the controlled object will be overwritten. - * This implementation registers this assocation to - * observer changes to each of the bound display groups. - */ - public void establishConnection () - { - Enumeration e = aspectToGroup.objectEnumerator(); - while ( e.hasMoreElements() ) - { - EOObserverCenter.addObserver( this, e.nextElement() ); + } + + /** + * Returns the display group that is bound the specified aspect, or null if no + * display group is currently bound to that aspect. + */ + public EODisplayGroup displayGroupForAspect(String anAspect) { + return (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + } + + /** + * Returns the key for the display group bound to the specified aspect, or null + * if no display group is currently bound to that aspect. + */ + public String displayGroupKeyForAspect(String anAspect) { + return (String) aspectToKey.objectForKey(anAspect); + } + + /** + * The human-readable descriptive name for this association. This implementation + * returns the class name. + */ + public String displayName() // was static - can static method get class name? + { + String className = getClass().getName(); + int index = className.lastIndexOf("."); + if (index == -1) + return className; + return className.substring(index + 1); + } + + /** + * Forces this association to cause the object to stop editing and validate the + * user's input. This implementation returns true. + * + * @return false if there were problems validating, or true to continue. + */ + public boolean endEditing() { + return true; + } + + /** + * Establishes a connection between this association and the controlled object. + * Subclasses should populate their controlled object from the display group and + * begin listening for events from their controlled object here, but remember to + * call this method. Any existing value in the controlled object will be + * overwritten. This implementation registers this assocation to observer + * changes to each of the bound display groups. + */ + public void establishConnection() { + Enumeration e = aspectToGroup.objectEnumerator(); + while (e.hasMoreElements()) { + EOObserverCenter.addObserver(this, e.nextElement()); } - } - - /** - * Returns whether this class can control the specified - * object. This implementation returns false. - */ - public static boolean isUsableWithObject ( Object anObject ) - { - return false; - } - - /** - * Returns the object that is currently controlled by this - * association, or null if no object is currently controlled. - */ - public Object object () - { - return control; - } - - /** - * Returns a List of properties of the controlled object - * that are controlled by this class. For example, - * "stringValue", or "selected". - * This implementation returns an empty list. - */ - public static NSArray objectKeysTaken () - { - return new NSArray(); - } - - /** - * Returns the aspect that is considered primary - * or default. This is typically "value" or somesuch. - * This implementation returns null. - */ - public static String primaryAspect () - { - return null; - } - - /** - * Writes the specified value for the display group - * and key currently bound to the specified aspect. - * This implementation calls - * EODisplayGroup.setSelectedObjectValue(). - * @return True if the value was successfully set, - * otherwise false. - */ - public boolean setValueForAspect ( - Object aValue, - String anAspect ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return false; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return false; - - //FIXME: is this the right method to call - return group.setSelectedObjectValue( aValue, key ); - } - - - /** - * Writes the specified value for the display group - * and key currently bound to the specified aspect, - * at the specified index (assuming it's an indexed - * property). - * This implementation calls - * EODisplayGroup.setValueForObjectAtIndex(). - * @return True if the value was successfully set, - * otherwise false. - */ - public boolean setValueForAspectAtIndex ( - Object aValue, - String anAspect, - int anIndex ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return false; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return false; - - //FIXME: is this the right method to call? - return group.setValueForObjectAtIndex( aValue, anIndex, key ); - } - - /** - * Called by subclasses to notify that the user's input - * failed validation. Notifies the display group for - * the aspect, returning the result. - * This implementation calls - * EODisplayGroup.associationFailedToValidateValue() - * with the display group's selected object. - * @return True if the user should be allowed to continue, - * meaning that the display group with handle user notification, - * otherwise false meaning the caller should notify the user. - */ - public boolean shouldEndEditing ( - String anAspect, - String anInvalidInput, - String anErrorDescription ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return false; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return false; - return group.associationFailedToValidateValue( - this, anInvalidInput, key, - group.selectedObject(), //FIXME: is this correct? - anErrorDescription ); - } - - /** - * Called by subclasses to notify that the user's input - * failed validation. Notifies the display group for - * the aspect, returning the result. - * This implementation calls - * EODisplayGroup.associationFailedToValidateValue() - * with the object in the display group's displayed - * objects array at the specified index. - * @return True if the user should be allowed to continue, - * meaning that the display group with handle user notification, - * otherwise false meaning the caller should notify the user. - */ - public boolean shouldEndEditingAtIndex ( - String anAspect, - String anInvalidInput, - String anErrorDescription, - int anIndex ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return false; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return false; - return group.associationFailedToValidateValue( - this, anInvalidInput, key, - group.displayedObjects().objectAtIndex( anIndex ), - //FIXME: is this correct? - anErrorDescription ); - } - - /** - * Called when either the selection or the contents of - * an associated display group have changed. - * This implementation does nothing. - */ - public void subjectChanged () - { - // does nothing - } - - /** - * Returns the current value for the display group - * and key associated with the specified aspect. - */ - public Object valueForAspect ( String anAspect ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return null; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return null; - - //FIXME: is this correct? use selected object? - return group.valueForObject( group.selectedObject(), key ); - } - - /** - * Returns the current value for the display group - * and key associated with the specified aspect, - * and the specified index (assuming multiple values). - */ - public Object valueForAspectAtIndex ( - String anAspect, int anIndex ) - { - EODisplayGroup group = (EODisplayGroup) - aspectToGroup.objectForKey( anAspect ); - if ( group == null ) return null; - String key = (String) - aspectToKey.objectForKey( anAspect ); - if ( key == null ) return null; - - //FIXME: is this the right method to call? - return group.valueForObjectAtIndex( anIndex, key ); - } - + } + + /** + * Returns whether this class can control the specified object. This + * implementation returns false. + */ + public static boolean isUsableWithObject(Object anObject) { + return false; + } + + /** + * Returns the object that is currently controlled by this association, or null + * if no object is currently controlled. + */ + public Object object() { + return control; + } + + /** + * Returns a List of properties of the controlled object that are controlled by + * this class. For example, "stringValue", or "selected". This implementation + * returns an empty list. + */ + public static NSArray objectKeysTaken() { + return new NSArray(); + } + + /** + * Returns the aspect that is considered primary or default. This is typically + * "value" or somesuch. This implementation returns null. + */ + public static String primaryAspect() { + return null; + } + + /** + * Writes the specified value for the display group and key currently bound to + * the specified aspect. This implementation calls + * EODisplayGroup.setSelectedObjectValue(). + * + * @return True if the value was successfully set, otherwise false. + */ + public boolean setValueForAspect(Object aValue, String anAspect) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return false; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return false; + + // FIXME: is this the right method to call + return group.setSelectedObjectValue(aValue, key); + } + + /** + * Writes the specified value for the display group and key currently bound to + * the specified aspect, at the specified index (assuming it's an indexed + * property). This implementation calls + * EODisplayGroup.setValueForObjectAtIndex(). + * + * @return True if the value was successfully set, otherwise false. + */ + public boolean setValueForAspectAtIndex(Object aValue, String anAspect, int anIndex) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return false; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return false; + + // FIXME: is this the right method to call? + return group.setValueForObjectAtIndex(aValue, anIndex, key); + } + + /** + * Called by subclasses to notify that the user's input failed validation. + * Notifies the display group for the aspect, returning the result. This + * implementation calls EODisplayGroup.associationFailedToValidateValue() with + * the display group's selected object. + * + * @return True if the user should be allowed to continue, meaning that the + * display group with handle user notification, otherwise false meaning + * the caller should notify the user. + */ + public boolean shouldEndEditing(String anAspect, String anInvalidInput, String anErrorDescription) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return false; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return false; + return group.associationFailedToValidateValue(this, anInvalidInput, key, group.selectedObject(), // FIXME: is + // this + // correct? + anErrorDescription); + } + + /** + * Called by subclasses to notify that the user's input failed validation. + * Notifies the display group for the aspect, returning the result. This + * implementation calls EODisplayGroup.associationFailedToValidateValue() with + * the object in the display group's displayed objects array at the specified + * index. + * + * @return True if the user should be allowed to continue, meaning that the + * display group with handle user notification, otherwise false meaning + * the caller should notify the user. + */ + public boolean shouldEndEditingAtIndex(String anAspect, String anInvalidInput, String anErrorDescription, + int anIndex) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return false; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return false; + return group.associationFailedToValidateValue(this, anInvalidInput, key, + group.displayedObjects().objectAtIndex(anIndex), + // FIXME: is this correct? + anErrorDescription); + } + + /** + * Called when either the selection or the contents of an associated display + * group have changed. This implementation does nothing. + */ + public void subjectChanged() { + // does nothing + } + + /** + * Returns the current value for the display group and key associated with the + * specified aspect. + */ + public Object valueForAspect(String anAspect) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return null; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return null; + + // FIXME: is this correct? use selected object? + return group.valueForObject(group.selectedObject(), key); + } + + /** + * Returns the current value for the display group and key associated with the + * specified aspect, and the specified index (assuming multiple values). + */ + public Object valueForAspectAtIndex(String anAspect, int anIndex) { + EODisplayGroup group = (EODisplayGroup) aspectToGroup.objectForKey(anAspect); + if (group == null) + return null; + String key = (String) aspectToKey.objectForKey(anAspect); + if (key == null) + return null; + + // FIXME: is this the right method to call? + return group.valueForObjectAtIndex(anIndex, key); + } + } /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.7 2005/05/11 15:21:53 cgruber - * Change enum to enumeration, since enum is now a keyword as of Java 5.0 + * Revision 1.7 2005/05/11 15:21:53 cgruber Change enum to enumeration, since + * enum is now a keyword as of Java 5.0 * * A few other comments in the code. * - * Revision 1.6 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.6 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.5 2003/06/06 20:29:45 mpowers - * Now dequeuing the association when connection is broken. - * Coalesced change events had been processed even after breaking connection. + * Revision 1.5 2003/06/06 20:29:45 mpowers Now dequeuing the association when + * connection is broken. Coalesced change events had been processed even after + * breaking connection. * - * Revision 1.4 2001/03/06 23:43:46 mpowers - * Implemented icon aspect for text association. + * Revision 1.4 2001/03/06 23:43:46 mpowers Implemented icon aspect for text + * association. * - * Revision 1.3 2001/02/17 16:52:05 mpowers - * Changes in imports to support building with jdk1.1 collections. + * Revision 1.3 2001/02/17 16:52:05 mpowers Changes in imports to support + * building with jdk1.1 collections. * - * Revision 1.2 2001/01/25 17:46:11 mpowers - * Clarified usage and gc expectations. + * Revision 1.2 2001/01/25 17:46:11 mpowers Clarified usage and gc expectations. * - * Revision 1.1.1.1 2000/12/21 15:48:07 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:48:07 mpowers Contributing wotonomy. * - * Revision 1.11 2000/12/20 16:25:39 michael - * Added log to all files. + * Revision 1.11 2000/12/20 16:25:39 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java index ed65b1c..fd80713 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java @@ -51,2309 +51,1867 @@ import net.wotonomy.foundation.internal.Duplicator; import net.wotonomy.foundation.internal.WotonomyException; /** -* EODisplayGroup provides an abstraction of a user interface, -* comprising of an ordered collection of data objects, some -* of which are displayed, and of those some are selected. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class EODisplayGroup extends Observable - implements EOObserving, EOEditingContext.Editor -{ - /** - * 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 EOAssociation editingAssociation; - 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 contentsChanged; - boolean selectionChanged; - int updatedObjectIndex; - - // this property is not in the spec - private boolean compareByReference = false; - - private EOObserving lastGroupObserver; - - /** - * Creates a new display group. - */ - public EODisplayGroup () - { - 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; - editingAssociation = null; - qualifier = null; - - localKeys = new NSArray(); // not implemented - insertedObjectDefaultValues = new NSDictionary(); - fetchesOnLoad = false; // not implemented - selectsFirstObjectAfterFetch = false; - usesOptimisticRefresh = false; - inQueryMode = false; // not implemented - - contentsChanged = false; - selectionChanged = false; - updatedObjectIndex = -1; - - // create our private delayed observer - lastGroupObserver = new LastGroupObserver( this ); - EOObserverCenter.addObserver( lastGroupObserver, this ); - } - - - - // 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; - } - - - - // 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 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." ); - } - - - // interface to associations - - /** - * Called by an association when it begins editing. - */ - public void associationDidBeginEditing ( EOAssociation anAssociation ) - { // System.out.println( "EODisplayGroup.associationDidBeginEditing: " + anAssociation ); - if ( dataSource != null ) - { - if ( dataSource.editingContext() != null ) - { - dataSource.editingContext().setMessageHandler( this ); - } - } - editingAssociation = anAssociation; - } - - /** - * Called by an association when it is finished editing. - */ - public void associationDidEndEditing ( EOAssociation anAssociation ) - { // System.out.println( "EODisplayGroup.associationDidEndEditing: " + anAssociation ); - editingAssociation = null; - } - - /** - * Called by associations to determine whether the contents - * of any objects have been changed. Returns true if the - * contents have changed and not all observers have been - * notified. - */ - public boolean contentsChanged () - { - return contentsChanged; - } - - /** - * Called by associations to determine whether the - * selection has been changed. Returns true if the - * selection has changed and not all observers have - * been notified. - */ - public boolean selectionChanged () - { - return selectionChanged; - } - - /** - * Called by an association when a user-specified value fails the association's - * validation rules. This implementation returns true, unless the delegate - * prevents this. - * @return True to allow the association to handle user notification, - * otherwise return false to let the association know that the - * display group notified the user. - */ - public boolean associationFailedToValidateValue ( - EOAssociation anAssociation, - String aValue, - String aKey, - Object anObject, - String anErrorDescription ) - { - Object result = notifyDelegate( - "displayGroupShouldDisplayAlert", - new Class[] { EODisplayGroup.class, String.class, String.class }, - new Object[] { this, "Validation Failed", anErrorDescription } ); - if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) ) - { - return true; - } - return false; - } - - /** - * Called by an association to determine whether it should enable - * a component that displayes a value for the specified key. - * @return true if an object is selected, or if - * the specified key is a query key. Otherwise false. - */ - public boolean enabledToSetSelectedObjectValueForKey ( String aKey ) - { - if ( ( aKey != null ) && ( aKey.startsWith( "@" ) ) ) return true; - return ( selectedObject() != null ); - } - - - // association management - - /** - * Returns the association that is currently being edited, - * or null if no editing is taking place. - */ - public EOAssociation editingAssociation () - { - return editingAssociation; - } - - /** - * Asks the association currently editing to stop editing. - * @returns true if editing was stopped, false if the - * association refused to stop editing (if a modal dialog - * is displayed or a value failed to validate). - */ - public boolean endEditing () - { - if ( editingAssociation == null ) return true; - return editingAssociation.endEditing(); - } - - /** - * Returns a read-only List of associations that are observing - * this display group. - */ - public NSArray observingAssociations () - { - NSArray observers = - EOObserverCenter.observersForObject( this ); - NSMutableArray result = new NSMutableArray(); - - Object o; - Enumeration e = observers.objectEnumerator(); - while ( e.hasMoreElements() ) - { - o = e.nextElement(); - if ( o instanceof EOAssociation ) - { - result.addObject( o ); - } - } - return result; - } - - - - // 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; - } - - /** - * 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[] { EODisplayGroup.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[] { EODisplayGroup.class }, - new Object[] { this } ); - notifyDelegate( - "displayGroupDidChangeSelectedObjects", - new Class[] { EODisplayGroup.class }, - new Object[] { this } ); - - return true; - } - - /** - * 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[] { EODisplayGroup.class, Object.class }, - new Object[] { this, target } ); - if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) ) - { - return false; - } - - contentsChanged = true; - - deleteObjectAtIndexNoNotify( anIndex ); - - if ( dataSource != null ) - { - dataSource.deleteObject( target ); - } - - notifyDelegate( - "displayGroupDidDeleteObject", - new Class[] { EODisplayGroup.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 - { + * EODisplayGroup provides an abstraction of a user interface, comprising of an + * ordered collection of data objects, some of which are displayed, and of those + * some are selected. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class EODisplayGroup extends Observable implements EOObserving, EOEditingContext.Editor { + /** + * 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 EOAssociation editingAssociation; + 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 contentsChanged; + boolean selectionChanged; + int updatedObjectIndex; + + // this property is not in the spec + private boolean compareByReference = false; + + private EOObserving lastGroupObserver; + + /** + * Creates a new display group. + */ + public EODisplayGroup() { + 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; + editingAssociation = null; + qualifier = null; + + localKeys = new NSArray(); // not implemented + insertedObjectDefaultValues = new NSDictionary(); + fetchesOnLoad = false; // not implemented + selectsFirstObjectAfterFetch = false; + usesOptimisticRefresh = false; + inQueryMode = false; // not implemented + + contentsChanged = false; + selectionChanged = false; + updatedObjectIndex = -1; + + // create our private delayed observer + lastGroupObserver = new LastGroupObserver(this); + EOObserverCenter.addObserver(lastGroupObserver, this); + } + + // 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; + } + + // 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 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."); + } + + // interface to associations + + /** + * Called by an association when it begins editing. + */ + public void associationDidBeginEditing(EOAssociation anAssociation) { // System.out.println( + // "EODisplayGroup.associationDidBeginEditing: + // " + anAssociation ); + if (dataSource != null) { + if (dataSource.editingContext() != null) { + dataSource.editingContext().setMessageHandler(this); + } + } + editingAssociation = anAssociation; + } + + /** + * Called by an association when it is finished editing. + */ + public void associationDidEndEditing(EOAssociation anAssociation) { // System.out.println( + // "EODisplayGroup.associationDidEndEditing: " + + // anAssociation ); + editingAssociation = null; + } + + /** + * Called by associations to determine whether the contents of any objects have + * been changed. Returns true if the contents have changed and not all observers + * have been notified. + */ + public boolean contentsChanged() { + return contentsChanged; + } + + /** + * Called by associations to determine whether the selection has been changed. + * Returns true if the selection has changed and not all observers have been + * notified. + */ + public boolean selectionChanged() { + return selectionChanged; + } + + /** + * Called by an association when a user-specified value fails the association's + * validation rules. This implementation returns true, unless the delegate + * prevents this. + * + * @return True to allow the association to handle user notification, otherwise + * return false to let the association know that the display group + * notified the user. + */ + public boolean associationFailedToValidateValue(EOAssociation anAssociation, String aValue, String aKey, + Object anObject, String anErrorDescription) { + Object result = notifyDelegate("displayGroupShouldDisplayAlert", + new Class[] { EODisplayGroup.class, String.class, String.class }, + new Object[] { this, "Validation Failed", anErrorDescription }); + if ((result == null) || (Boolean.TRUE.equals(result))) { + return true; + } + return false; + } + + /** + * Called by an association to determine whether it should enable a component + * that displayes a value for the specified key. + * + * @return true if an object is selected, or if the specified key is a query + * key. Otherwise false. + */ + public boolean enabledToSetSelectedObjectValueForKey(String aKey) { + if ((aKey != null) && (aKey.startsWith("@"))) + return true; + return (selectedObject() != null); + } + + // association management + + /** + * Returns the association that is currently being edited, or null if no editing + * is taking place. + */ + public EOAssociation editingAssociation() { + return editingAssociation; + } + + /** + * Asks the association currently editing to stop editing. + * + * @returns true if editing was stopped, false if the association refused to + * stop editing (if a modal dialog is displayed or a value failed to + * validate). + */ + public boolean endEditing() { + if (editingAssociation == null) + return true; + return editingAssociation.endEditing(); + } + + /** + * Returns a read-only List of associations that are observing this display + * group. + */ + public NSArray observingAssociations() { + NSArray observers = EOObserverCenter.observersForObject(this); + NSMutableArray result = new NSMutableArray(); + + Object o; + Enumeration e = observers.objectEnumerator(); + while (e.hasMoreElements()) { + o = e.nextElement(); + if (o instanceof EOAssociation) { + result.addObject(o); + } + } + return result; + } + + // 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; + } + + /** + * 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[] { EODisplayGroup.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[] { EODisplayGroup.class }, new Object[] { this }); + notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.class }, + new Object[] { this }); + + return true; + } + + /** + * 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[] { EODisplayGroup.class, Object.class }, new Object[] { this, target }); + if ((result != null) && (Boolean.FALSE.equals(result))) { + return false; + } + + contentsChanged = true; + + deleteObjectAtIndexNoNotify(anIndex); + + if (dataSource != null) { + dataSource.deleteObject(target); + } + + notifyDelegate("displayGroupDidDeleteObject", new Class[] { EODisplayGroup.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" ); - return displayedObjectsProxy; - } - - /** - * 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. - */ - public boolean fetch () - { - endEditing(); - - if ( dataSource == null ) - { - return false; - } - - Object result = notifyDelegate( - "displayGroupShouldFetch", - new Class[] { EODisplayGroup.class }, - new Object[] { this } ); - if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) ) - { - return false; - } - - NSNotificationCenter.defaultCenter().postNotification( - DisplayGroupWillFetchNotification, this, new NSDictionary() ); - - NSArray objectList = dataSource.fetchObjects(); - - notifyDelegate( - "displayGroupDidFetchObjects", - new Class[] { EODisplayGroup.class, List.class }, - new Object[] { this, objectList } ); - - if ( selectsFirstObjectAfterFetch ) - { - //note: there's a good chance this logic ought to be in master-detail assoc: - // we're doing this because changes in the master object trigger a refetch - // on the child display group which annoyingly changes the selection. - NSArray original = new NSArray( allObjects ); - setObjectArray( objectList ); - if ( displayedObjects.size() > 0 - && !original.equals( allObjects ) ) // don't change if no change - { - setSelectionIndexes( new NSArray( new Integer( 0 ) ) ); - } - } - else - { - setObjectArray( objectList ); - } - - return true; - } - - /** - * Creates a new object at the specified index. - * Calls insertObjectAtIndex() with the result - * from sending createObject() to the data source. - * Presents a JOptionPane if the create fails, unless - * the delegate implements displayGroupCreateObjectFailed. - * @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[] { EODisplayGroup.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(); - } - } - } - - // no delegate or delegate does not implement displayGroupCreateObjectFailed - - String message = "Data source could not create new object"; - Object delegateResult = notifyDelegate( - "displayGroupShouldDisplayAlert", - new Class[] { EODisplayGroup.class, String.class, String.class }, - new Object[] { this, "Error", message } ); - if ( ( delegateResult == null ) || ( Boolean.TRUE.equals( delegateResult ) ) ) - { - JOptionPane.showMessageDialog( null, message ); - } - } - 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[] { EODisplayGroup.class, Object.class, int.class }, - new Object[] { this, anObject, new Integer(anIndex) } ); - if ( ( result != null ) && ( Boolean.FALSE.equals( result ) ) ) - { - return; - } - - contentsChanged = true; - updatedObjectIndex = anIndex; - willChange(); - - - // 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[] { EODisplayGroup.class, Object.class }, - new Object[] { this, anObject } ); - } - - /** - * Sets contentsChanged to true and notifies all observers. - */ - public void redisplay () - { - contentsChanged = true; - 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 true if an object was selected. - */ - public boolean selectNext () - { - int count = displayedObjects.count(); - if ( count == 0 ) return false; - if ( count == 1 ) - { - selectObject( displayedObjects.objectAtIndex( 0 ) ); - return true; - } - - 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 ); - } - - return selectObject( selectedObject ); - } - - /** - * 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[] { EODisplayGroup.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[] { EODisplayGroup.class }, - new Object[] { this } ); - notifyDelegate( - "displayGroupDidChangeSelectedObjects", - new Class[] { EODisplayGroup.class }, - new Object[] { this } ); - - return true; - } - - /** - * 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 true if an object was selected. - */ - public boolean selectPrevious () - { - int i = displayedObjects.count(); - if ( i == 0 ) return false; - if ( i == 1 ) - { - selectObject( displayedObjects.objectAtIndex( 0 ) ); - return true; - } - - 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; - } - - return selectObject( displayedObjects.objectAtIndex( i ) ); - } - - /** - * 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" ); + return displayedObjectsProxy; + } + + /** + * 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. + */ + public boolean fetch() { + endEditing(); + + if (dataSource == null) { + return false; + } + + Object result = notifyDelegate("displayGroupShouldFetch", new Class[] { EODisplayGroup.class }, + new Object[] { this }); + if ((result != null) && (Boolean.FALSE.equals(result))) { + return false; + } + + NSNotificationCenter.defaultCenter().postNotification(DisplayGroupWillFetchNotification, this, + new NSDictionary()); + + NSArray objectList = dataSource.fetchObjects(); + + notifyDelegate("displayGroupDidFetchObjects", new Class[] { EODisplayGroup.class, List.class }, + new Object[] { this, objectList }); + + if (selectsFirstObjectAfterFetch) { + // note: there's a good chance this logic ought to be in master-detail assoc: + // we're doing this because changes in the master object trigger a refetch + // on the child display group which annoyingly changes the selection. + NSArray original = new NSArray(allObjects); + setObjectArray(objectList); + if (displayedObjects.size() > 0 && !original.equals(allObjects)) // don't change if no change + { + setSelectionIndexes(new NSArray(new Integer(0))); + } + } else { + setObjectArray(objectList); + } + + return true; + } + + /** + * Creates a new object at the specified index. Calls insertObjectAtIndex() with + * the result from sending createObject() to the data source. Presents a + * JOptionPane if the create fails, unless the delegate implements + * displayGroupCreateObjectFailed. + * + * @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[] { EODisplayGroup.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(); + } + } + } + + // no delegate or delegate does not implement displayGroupCreateObjectFailed + + String message = "Data source could not create new object"; + Object delegateResult = notifyDelegate("displayGroupShouldDisplayAlert", + new Class[] { EODisplayGroup.class, String.class, String.class }, + new Object[] { this, "Error", message }); + if ((delegateResult == null) || (Boolean.TRUE.equals(delegateResult))) { + JOptionPane.showMessageDialog(null, message); + } + } + 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[] { EODisplayGroup.class, Object.class, int.class }, + new Object[] { this, anObject, new Integer(anIndex) }); + if ((result != null) && (Boolean.FALSE.equals(result))) { + return; + } + + contentsChanged = true; + updatedObjectIndex = anIndex; + willChange(); + + // 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[] { EODisplayGroup.class, Object.class }, + new Object[] { this, anObject }); + } + + /** + * Sets contentsChanged to true and notifies all observers. + */ + public void redisplay() { + contentsChanged = true; + 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 true if an object was selected. + */ + public boolean selectNext() { + int count = displayedObjects.count(); + if (count == 0) + return false; + if (count == 1) { + selectObject(displayedObjects.objectAtIndex(0)); + return true; + } + + 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); + } + + return selectObject(selectedObject); + } + + /** + * 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[] { EODisplayGroup.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[] { EODisplayGroup.class }, new Object[] { this }); + notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.class }, + new Object[] { this }); + + return true; + } + + /** + * 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 true if an object was selected. + */ + public boolean selectPrevious() { + int i = displayedObjects.count(); + if (i == 0) + return false; + if (i == 1) { + selectObject(displayedObjects.objectAtIndex(0)); + return true; + } + + 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; + } + + return selectObject(displayedObjects.objectAtIndex(i)); + } + + /** + * 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[] { EODisplayGroup.class, List.class }, - new Object[] { this, anObjectList } ); - if ( result != null ) - { - anObjectList = (List) result; - } - - contentsChanged = true; - 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 ); - } - - /** - * 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 () - { - contentsChanged = true; - 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[] { EODisplayGroup.class }, - new Object[] { this } ); - notifyDelegate( - "displayGroupDidChangeSelectedObjects", - new Class[] { EODisplayGroup.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[] { EODisplayGroup.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[] { EODisplayGroup.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[] { EODisplayGroup.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. - */ - public Object valueForObjectAtIndex ( int anIndex, String aKey ) - { - 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[] { EODisplayGroup.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[] { EODisplayGroup.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( "EODisplayGroup: updated: " + index ); - if ( ! didChange ) - { - didChange = true; - contentsChanged = 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( "EODisplayGroup: invalidated: " + index ); - if ( ! didChange ) - { - didChange = true; - contentsChanged = 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( "EODisplayGroup: 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 ); - } - - /** - * Called by LastGroupObserver to clear flags. - */ - protected void processRecentChanges() - { - contentsChanged = false; - selectionChanged = false; - } - - /** - * 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 and contentsChanged as appropriate. - */ - public void objectWillChange(Object anObject) - { - int index = indexOf( displayedObjects, anObject ); - if ( index != NSArray.NotFound ) - { - updatedObjectIndex = index; - contentsChanged = true; - 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. - */ - public boolean editorHasChangesForEditingContext( - EOEditingContext anEditingContext ) - { - return ( editingAssociation() != null ); - } - - // interface EOEditingContext.MessageHandler - - /** - * Called to display a message for an error that occurred - * in the specified editing context. If the delegate allows, - * this implementation presents an informational JOptionPane. - * Override to customize. - */ - public void editingContextPresentErrorMessage( - EOEditingContext anEditingContext, - String aMessage ) - { - Object result = notifyDelegate( - "displayGroupShouldDisplayAlert", - new Class[] { EODisplayGroup.class, String.class, String.class }, - new Object[] { this, "Error", aMessage } ); - if ( ( result == null ) || ( Boolean.TRUE.equals( result ) ) ) - { - JOptionPane.showMessageDialog( null, 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 presents an JOptionPane allowing the user - * to specify whether to continue. Override to customize. - */ - public boolean editingContextShouldContinueFetching( - EOEditingContext anEditingContext, - int count, - int limit, - EOObjectStore anObjectStore ) - { - return ( JOptionPane.showConfirmDialog( null, - "Fetch limit reached: do you wish to continue?", - "Continue?", - JOptionPane.YES_NO_OPTION ) == JOptionPane.YES_OPTION ); - } - - /** - * 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 ( - EODisplayGroup aDisplayGroup, - EODataSource aDataSource ); - - /** - * Called after the specified display group's - * data source is changed. - */ - void displayGroupDidChangeDataSource ( - EODisplayGroup aDisplayGroup ); - - /** - * Called after a change occurs in the specified - * display group's selected objects. - */ - void displayGroupDidChangeSelectedObjects ( - EODisplayGroup aDisplayGroup ); - - /** - * Called after the specified display group's - * selection has changed. - */ - void displayGroupDidChangeSelection ( - EODisplayGroup aDisplayGroup ); - - /** - * Called after the specified display group has - * deleted the specified object. - */ - void displayGroupDidDeleteObject ( - EODisplayGroup aDisplayGroup, - Object anObject ); - - /** - * Called after the specified display group - * has fetched the specified object list. - */ - void displayGroupDidFetchObjects ( - EODisplayGroup aDisplayGroup, - List anObjectList ); - - /** - * Called after the specified display group - * has inserted the specified object into - * its internal object list. - */ - void displayGroupDidInsertObject ( - EODisplayGroup aDisplayGroup, - Object anObject ); - - /** - * Called after the specified display group - * has set the specified value for the specified - * object and key. - */ - void displayGroupDidSetValueForObject ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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 ( - EODisplayGroup 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[] { EODisplayGroup.class, List.class }, new Object[] { this, anObjectList }); + if (result != null) { + anObjectList = (List) result; + } + + contentsChanged = true; + 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); + } + + /** + * 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() { + contentsChanged = true; + 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[] { EODisplayGroup.class }, + new Object[] { this }); + notifyDelegate("displayGroupDidChangeSelectedObjects", new Class[] { EODisplayGroup.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[] { EODisplayGroup.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[] { EODisplayGroup.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[] { EODisplayGroup.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. + */ + public Object valueForObjectAtIndex(int anIndex, String aKey) { + 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[] { EODisplayGroup.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[] { EODisplayGroup.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( "EODisplayGroup: updated: " + index ); + if (!didChange) { + didChange = true; + contentsChanged = 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( "EODisplayGroup: invalidated: " + index ); + if (!didChange) { + didChange = true; + contentsChanged = 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( "EODisplayGroup: 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); + } + + /** + * Called by LastGroupObserver to clear flags. + */ + protected void processRecentChanges() { + contentsChanged = false; + selectionChanged = false; + } + + /** + * 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 and + * contentsChanged as appropriate. + */ + public void objectWillChange(Object anObject) { + int index = indexOf(displayedObjects, anObject); + if (index != NSArray.NotFound) { + updatedObjectIndex = index; + contentsChanged = true; + 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. + */ + public boolean editorHasChangesForEditingContext(EOEditingContext anEditingContext) { + return (editingAssociation() != null); + } + + // interface EOEditingContext.MessageHandler + + /** + * Called to display a message for an error that occurred in the specified + * editing context. If the delegate allows, this implementation presents an + * informational JOptionPane. Override to customize. + */ + public void editingContextPresentErrorMessage(EOEditingContext anEditingContext, String aMessage) { + Object result = notifyDelegate("displayGroupShouldDisplayAlert", + new Class[] { EODisplayGroup.class, String.class, String.class }, + new Object[] { this, "Error", aMessage }); + if ((result == null) || (Boolean.TRUE.equals(result))) { + JOptionPane.showMessageDialog(null, 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 presents an + * JOptionPane allowing the user to specify whether to continue. Override to + * customize. + */ + public boolean editingContextShouldContinueFetching(EOEditingContext anEditingContext, int count, int limit, + EOObjectStore anObjectStore) { + return (JOptionPane.showConfirmDialog(null, "Fetch limit reached: do you wish to continue?", "Continue?", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION); + } + + /** + * 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(EODisplayGroup aDisplayGroup, EODataSource aDataSource); + + /** + * Called after the specified display group's data source is changed. + */ + void displayGroupDidChangeDataSource(EODisplayGroup aDisplayGroup); + + /** + * Called after a change occurs in the specified display group's selected + * objects. + */ + void displayGroupDidChangeSelectedObjects(EODisplayGroup aDisplayGroup); + + /** + * Called after the specified display group's selection has changed. + */ + void displayGroupDidChangeSelection(EODisplayGroup aDisplayGroup); + + /** + * Called after the specified display group has deleted the specified object. + */ + void displayGroupDidDeleteObject(EODisplayGroup aDisplayGroup, Object anObject); + + /** + * Called after the specified display group has fetched the specified object + * list. + */ + void displayGroupDidFetchObjects(EODisplayGroup aDisplayGroup, List anObjectList); + + /** + * Called after the specified display group has inserted the specified object + * into its internal object list. + */ + void displayGroupDidInsertObject(EODisplayGroup aDisplayGroup, Object anObject); + + /** + * Called after the specified display group has set the specified value for the + * specified object and key. + */ + void displayGroupDidSetValueForObject(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup 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(EODisplayGroup aDisplayGroup, NSNotification aNotification); + + } } - /** - * A private class that will serve to clear the contentsChanged - * and selectionChanged flags after all Associations have been - * notified. - */ - class LastGroupObserver extends EODelayedObserver - { - Reference ref; - - public LastGroupObserver( EODisplayGroup aDisplayGroup ) - { - ref = new WeakReference( aDisplayGroup ); - } - - /** - * We want to be informed last, after all Associations - * have been notified to changes in the DisplayGroup. - */ - public int priority() - { - return ObserverPrioritySixth; - } - - /** - * After all Associations have been notified, - * clear the contentsChanged and selectionChanged flags. - */ - public void subjectChanged () - { - EODisplayGroup group = (EODisplayGroup) ref.get(); - if ( group != null ) - { - group.processRecentChanges(); - } - } - } +/** + * A private class that will serve to clear the contentsChanged and + * selectionChanged flags after all Associations have been notified. + */ +class LastGroupObserver extends EODelayedObserver { + Reference ref; + + public LastGroupObserver(EODisplayGroup aDisplayGroup) { + ref = new WeakReference(aDisplayGroup); + } + + /** + * We want to be informed last, after all Associations have been notified to + * changes in the DisplayGroup. + */ + public int priority() { + return ObserverPrioritySixth; + } + + /** + * After all Associations have been notified, clear the contentsChanged and + * selectionChanged flags. + */ + public void subjectChanged() { + EODisplayGroup group = (EODisplayGroup) ref.get(); + if (group != null) { + group.processRecentChanges(); + } + } +} /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.51 2004/01/28 18:35:40 mpowers - * Slight optimization: only comparing list in fetch if we have to. + * Revision 1.51 2004/01/28 18:35:40 mpowers Slight optimization: only comparing + * list in fetch if we have to. * - * Revision 1.50 2004/01/27 20:42:30 mpowers - * No longer reselecting first after fetch if contents are identical. + * Revision 1.50 2004/01/27 20:42:30 mpowers No longer reselecting first after + * fetch if contents are identical. * - * Revision 1.49 2003/12/18 11:37:45 mpowers - * Now calling qualifier internally. + * Revision 1.49 2003/12/18 11:37:45 mpowers Now calling qualifier internally. * - * Revision 1.48 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.48 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.47 2003/01/18 23:30:42 mpowers - * WODisplayGroup now compiles. + * Revision 1.47 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. * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java index 3a4ff08..3310f19 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java @@ -28,346 +28,282 @@ import net.wotonomy.control.EOObserverCenter; import net.wotonomy.foundation.NSArray; /** -* GenericAssociation binds one or more properties on an -* observable object to a display group. The controlled -* object is expected to use the ObserverCenter and will -* be observed by this association. <br><br> -* -* Bindings for this association are <i>generic</i>: the -* name of the aspect will be treated as a property key -* on the displayed object(s) and synchronized with the -* bound property on the controlled object. <br><br> -* -* NOTE: because we cannot assume that the controlled -* object will retain a reference to this association, -* you must explicitly retain a reference to prevent -* the association from getting garbage collected. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class GenericAssociation extends EOAssociation -{ - protected boolean objectModified; - protected Set aspectsModified; - - static final NSArray aspects = - new NSArray( new Object[] { - } ); - static final NSArray aspectSignatures = - new NSArray( new Object[] { - } ); - static final NSArray objectKeysTaken = - new NSArray( new Object[] { - } ); - - /** - * Constructor specifying the object to be controlled by this - * association. Does not establish connection. - */ - public GenericAssociation ( Object anObject ) - { - super( anObject ); - objectModified = false; - aspectsModified = new HashSet(); - } - - /** - * Returns a List of aspect signatures whose contents - * correspond with the aspects list. Each element is - * a string whose characters represent a capability of - * the corresponding aspect. <ul> - * <li>"A" attribute: the aspect can be bound to - * an attribute.</li> - * <li>"1" to-one: the aspect can be bound to a - * property that returns a single object.</li> - * <li>"M" to-one: the aspect can be bound to a - * property that returns multiple objects.</li> - * </ul> - * An empty signature "" means that the aspect can - * bind without needing a key. - * This implementation returns "A1M" for each - * element in the aspects array. - */ - public static NSArray aspectSignatures () - { - return aspectSignatures; - } - - /** - * Returns a List that describes the aspects supported - * by this class. Each element in the list is the string - * name of the aspect. This implementation returns an - * empty list. - */ - public static NSArray aspects () - { - return aspects; - } - - /** - * Returns a List of EOAssociation subclasses that, - * for the objects that are usable for this association, - * are less suitable than this association. - */ - public static NSArray associationClassesSuperseded () - { - return new NSArray(); - } - - /** - * Returns whether this class can control the specified - * object. - */ - public static boolean isUsableWithObject ( Object anObject ) - { - return true; - } - - /** - * Returns a List of properties of the controlled object - * that are controlled by this class. For example, - * "stringValue", or "selected". - */ - public static NSArray objectKeysTaken () - { - return objectKeysTaken; - } - - /** - * Returns the aspect that is considered primary - * or default. This is typically "value" or somesuch. - */ - public static String primaryAspect () - { - return ""; - } - - /** - * Returns whether this association can bind to the - * specified display group on the specified key for - * the specified aspect. - */ - public boolean canBindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey) - { - return true; - } - - /** - * Establishes a connection between this association - * and the controlled object. This implementation - * registers with ObserverCenter for change notifications - * from the controlled object. - */ - public void establishConnection () - { - EOObserverCenter.addObserver( this, object() ); - super.establishConnection(); - + * GenericAssociation binds one or more properties on an observable object to a + * display group. The controlled object is expected to use the ObserverCenter + * and will be observed by this association. <br> + * <br> + * + * Bindings for this association are <i>generic</i>: the name of the aspect will + * be treated as a property key on the displayed object(s) and synchronized with + * the bound property on the controlled object. <br> + * <br> + * + * NOTE: because we cannot assume that the controlled object will retain a + * reference to this association, you must explicitly retain a reference to + * prevent the association from getting garbage collected. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class GenericAssociation extends EOAssociation { + protected boolean objectModified; + protected Set aspectsModified; + + static final NSArray aspects = new NSArray(new Object[] {}); + static final NSArray aspectSignatures = new NSArray(new Object[] {}); + static final NSArray objectKeysTaken = new NSArray(new Object[] {}); + + /** + * Constructor specifying the object to be controlled by this association. Does + * not establish connection. + */ + public GenericAssociation(Object anObject) { + super(anObject); + objectModified = false; + aspectsModified = new HashSet(); + } + + /** + * Returns a List of aspect signatures whose contents correspond with the + * aspects list. Each element is a string whose characters represent a + * capability of the corresponding aspect. + * <ul> + * <li>"A" attribute: the aspect can be bound to an attribute.</li> + * <li>"1" to-one: the aspect can be bound to a property that returns a single + * object.</li> + * <li>"M" to-one: the aspect can be bound to a property that returns multiple + * objects.</li> + * </ul> + * An empty signature "" means that the aspect can bind without needing a key. + * This implementation returns "A1M" for each element in the aspects array. + */ + public static NSArray aspectSignatures() { + return aspectSignatures; + } + + /** + * Returns a List that describes the aspects supported by this class. Each + * element in the list is the string name of the aspect. This implementation + * returns an empty list. + */ + public static NSArray aspects() { + return aspects; + } + + /** + * Returns a List of EOAssociation subclasses that, for the objects that are + * usable for this association, are less suitable than this association. + */ + public static NSArray associationClassesSuperseded() { + return new NSArray(); + } + + /** + * Returns whether this class can control the specified object. + */ + public static boolean isUsableWithObject(Object anObject) { + return true; + } + + /** + * Returns a List of properties of the controlled object that are controlled by + * this class. For example, "stringValue", or "selected". + */ + public static NSArray objectKeysTaken() { + return objectKeysTaken; + } + + /** + * Returns the aspect that is considered primary or default. This is typically + * "value" or somesuch. + */ + public static String primaryAspect() { + return ""; + } + + /** + * Returns whether this association can bind to the specified display group on + * the specified key for the specified aspect. + */ + public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + return true; + } + + /** + * Establishes a connection between this association and the controlled object. + * This implementation registers with ObserverCenter for change notifications + * from the controlled object. + */ + public void establishConnection() { + EOObserverCenter.addObserver(this, object()); + super.establishConnection(); + // forces update from bindings subjectChanged(); - } - - /** - * Breaks the connection between this association and - * its object. Override to stop listening for events - * from the object. - */ - public void breakConnection () - { - EOObserverCenter.removeObserver( this, object() ); - super.breakConnection(); - } - - /** - * Overridden to track which observed object is changing. - */ - public void objectWillChange( Object anObject ) - { - if ( object() == anObject ) - { - objectModified = true; - } - else - { - aspectsModified.add( aspectToGroup.allKeysForObject( anObject ) ); - } - } - - /** - * Called when either the selection or the contents - * of an associated display group have changed. - */ - public void subjectChanged () - { - String aspect; - String key; - Object value; - EODisplayGroup displayGroup; - Iterator iterator; - - iterator = aspectsModified.iterator(); - while ( iterator.hasNext() ) - { - aspect = (String) iterator.next(); - key = displayGroupKeyForAspect( aspect ); - displayGroup = displayGroupForAspect( aspect ); - - value = readValueFromDisplayGroupForKey( displayGroup, key ); - writeValueForKey( object(), value, key ); - } - aspectsModified.clear(); - - if ( objectModified ) - { - iterator = aspectToGroup.keySet().iterator(); - while ( iterator.hasNext() ) - { - aspect = (String) iterator.next(); - key = displayGroupKeyForAspect( aspect ); - value = readValueForKey( object(), key ); - displayGroup = displayGroupForAspect( aspect ); - displayGroup.setSelectedObjectValue( value, key ); - } - } - } - - protected Object readValueForKey( Object object, String key ) - { - if ( object instanceof EOKeyValueCoding ) - { - return ((EOKeyValueCoding)object).valueForKey( key ); - } - return EOKeyValueCodingSupport.valueForKey( object, key ); - } - - protected void writeValueForKey( Object object, Object value, String key ) - { - if ( object instanceof EOKeyValueCoding ) - { - ((EOKeyValueCoding)object).takeValueForKey( value, key ); - } - else - { - EOKeyValueCodingSupport.takeValueForKey( object, value, key ); - } - } - - protected Object readValueFromDisplayGroupForKey( - EODisplayGroup displayGroup, String key ) - { - Object value; - - if ( displayGroup.selectedObjects().size() > 1 ) - { - // if there're more than one object selected, set - // the value to blank for all of them. - Object previousValue; - - Iterator indexIterator = displayGroup.selectionIndexes(). - iterator(); - - // get value for the first selected object. - int initialIndex = ( (Integer)indexIterator.next() ).intValue(); - previousValue = displayGroup.valueForObjectAtIndex( - initialIndex, key ); - value = null; - - // go through the rest of the selected objects, compare each - // value with the previous one. continue comparing if two - // values are equal, break the while loop if they're different. - // the final value will be the common value of all selected objects - // if there is one, or be blank if there is not. - while ( indexIterator.hasNext() ) - { - int index = ( (Integer)indexIterator.next() ).intValue(); - Object currentValue = displayGroup.valueForObjectAtIndex( - index, key ); - if ( currentValue != null && !currentValue.equals( previousValue ) ) - { - value = null; - break; - } - else - { - // currentValue is the same as the previous one - value = currentValue; - } - - } // end while - - } else { - - value = displayGroup.selectedObjectValueForKey( key ); - } // end checking size of displayGroup - - return value; - } - + } + /** - * Writes the value currently in the component - * to the selected object in the display group - * bound to the value aspect. - * @return false if there were problems validating, - * or true to continue. - */ - protected boolean writeValueForAspect( Object value, String aspect ) - { - EODisplayGroup displayGroup = - displayGroupForAspect( aspect ); - if ( displayGroup != null ) - { - String key = displayGroupKeyForAspect( aspect ); - - boolean returnValue = true; - Iterator selectedIterator = displayGroup.selectionIndexes().iterator(); - while ( selectedIterator.hasNext() ) - { - int index = ( (Integer)selectedIterator.next() ).intValue(); - - if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) ) - { - returnValue = false; - } - } - return returnValue; + * Breaks the connection between this association and its object. Override to + * stop listening for events from the object. + */ + public void breakConnection() { + EOObserverCenter.removeObserver(this, object()); + super.breakConnection(); + } + + /** + * Overridden to track which observed object is changing. + */ + public void objectWillChange(Object anObject) { + if (object() == anObject) { + objectModified = true; + } else { + aspectsModified.add(aspectToGroup.allKeysForObject(anObject)); + } + } + + /** + * Called when either the selection or the contents of an associated display + * group have changed. + */ + public void subjectChanged() { + String aspect; + String key; + Object value; + EODisplayGroup displayGroup; + Iterator iterator; + + iterator = aspectsModified.iterator(); + while (iterator.hasNext()) { + aspect = (String) iterator.next(); + key = displayGroupKeyForAspect(aspect); + displayGroup = displayGroupForAspect(aspect); + + value = readValueFromDisplayGroupForKey(displayGroup, key); + writeValueForKey(object(), value, key); + } + aspectsModified.clear(); + + if (objectModified) { + iterator = aspectToGroup.keySet().iterator(); + while (iterator.hasNext()) { + aspect = (String) iterator.next(); + key = displayGroupKeyForAspect(aspect); + value = readValueForKey(object(), key); + displayGroup = displayGroupForAspect(aspect); + displayGroup.setSelectedObjectValue(value, key); + } + } + } + + protected Object readValueForKey(Object object, String key) { + if (object instanceof EOKeyValueCoding) { + return ((EOKeyValueCoding) object).valueForKey(key); + } + return EOKeyValueCodingSupport.valueForKey(object, key); + } + + protected void writeValueForKey(Object object, Object value, String key) { + if (object instanceof EOKeyValueCoding) { + ((EOKeyValueCoding) object).takeValueForKey(value, key); + } else { + EOKeyValueCodingSupport.takeValueForKey(object, value, key); + } + } + + protected Object readValueFromDisplayGroupForKey(EODisplayGroup displayGroup, String key) { + Object value; + + if (displayGroup.selectedObjects().size() > 1) { + // if there're more than one object selected, set + // the value to blank for all of them. + Object previousValue; + + Iterator indexIterator = displayGroup.selectionIndexes().iterator(); + + // get value for the first selected object. + int initialIndex = ((Integer) indexIterator.next()).intValue(); + previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key); + value = null; + + // go through the rest of the selected objects, compare each + // value with the previous one. continue comparing if two + // values are equal, break the while loop if they're different. + // the final value will be the common value of all selected objects + // if there is one, or be blank if there is not. + while (indexIterator.hasNext()) { + int index = ((Integer) indexIterator.next()).intValue(); + Object currentValue = displayGroup.valueForObjectAtIndex(index, key); + if (currentValue != null && !currentValue.equals(previousValue)) { + value = null; + break; + } else { + // currentValue is the same as the previous one + value = currentValue; + } + + } // end while + + } else { + + value = displayGroup.selectedObjectValueForKey(key); + } // end checking size of displayGroup + + return value; + } + + /** + * Writes the value currently in the component to the selected object in the + * display group bound to the value aspect. + * + * @return false if there were problems validating, or true to continue. + */ + protected boolean writeValueForAspect(Object value, String aspect) { + EODisplayGroup displayGroup = displayGroupForAspect(aspect); + if (displayGroup != null) { + String key = displayGroupKeyForAspect(aspect); + + boolean returnValue = true; + Iterator selectedIterator = displayGroup.selectionIndexes().iterator(); + while (selectedIterator.hasNext()) { + int index = ((Integer) selectedIterator.next()).intValue(); + + if (!displayGroup.setValueForObjectAtIndex(value, index, key)) { + returnValue = false; + } + } + return returnValue; } return false; } - /** - * Forces this association to cause the object to - * stop editing and validate the user's input. - * @return false if there were problems validating, - * or true to continue. - */ - public boolean endEditing () - { - return false; + /** + * Forces this association to cause the object to stop editing and validate the + * user's input. + * + * @return false if there were problems validating, or true to continue. + */ + public boolean endEditing() { + return false; //! return writeValueToDisplayGroup(); - } - + } + } /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.3 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.2 2001/11/08 19:51:24 mpowers - * Draft implementation. + * Revision 1.2 2001/11/08 19:51:24 mpowers Draft implementation. * - * Revision 1.1 2001/11/02 23:15:04 mpowers - * Contributing "generic association". + * Revision 1.1 2001/11/02 23:15:04 mpowers Contributing "generic association". * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java index 2aea8d3..54cd04e 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MasterDetailAssociation.java @@ -27,380 +27,303 @@ import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSMutableArray; /** -* MasterDetailAssociation binds a display group to a property -* on the selected object of another display group. -* Bindings are: -* <ul> -* <li>parent: The property on the selected object of the -* bound display group that is expected to be an indexed property.</li> -* </ul> -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class MasterDetailAssociation extends EOAssociation -{ - static final NSArray aspects = - new NSArray( new Object[] { - ParentAspect - } ); - static final NSArray aspectSignatures = - new NSArray( new Object[] { - AttributeToOneAspectSignature - } ); - static final NSArray objectKeysTaken = - new NSArray( new Object[] { - "allObjects" - } ); - - /** - * Used to be notified of changes to objects in the - * controlled display group. requalify() should place - * all objects fetched into the controlled group into - * this array. - * Otherwise, the parent object is only marked as - * changed for inserts and deletes. - */ - protected NSMutableArray observableArray; - - /** - * Constructor expecting an EODisplayGroup. - * If the controlled display group does not have a data source, - * a new PropertyDataSource will be used. - */ - public MasterDetailAssociation ( Object anObject ) - { - super( anObject ); - observableArray = new ObservableArray( this ); - } - - /** - * Returns a List of aspect signatures whose contents - * correspond with the aspects list. Each element is - * a string whose characters represent a capability of - * the corresponding aspect. <ul> - * <li>"A" attribute: the aspect can be bound to - * an attribute.</li> - * <li>"1" to-one: the aspect can be bound to a - * property that returns a single object.</li> - * <li>"M" to-one: the aspect can be bound to a - * property that returns multiple objects.</li> - * </ul> - * An empty signature "" means that the aspect can - * bind without needing a key. - * This implementation returns "A1M" for each - * element in the aspects array. - */ - public static NSArray aspectSignatures () - { - return aspectSignatures; - } - - /** - * Returns a List that describes the aspects supported - * by this class. Each element in the list is the string - * name of the aspect. This implementation returns an - * empty list. - */ - public static NSArray aspects () - { - return aspects; - } - - /** - * Returns a List of EOAssociation subclasses that, - * for the objects that are usable for this association, - * are less suitable than this association. - */ - public static NSArray associationClassesSuperseded () - { - return new NSArray(); - } - - /** - * Returns whether this class can control the specified - * object. - */ - public static boolean isUsableWithObject ( Object anObject ) - { - return ( anObject instanceof EODisplayGroup ); - } - - /** - * Returns a List of properties of the controlled object - * that are controlled by this class. For example, - * "stringValue", or "selected". - */ - public static NSArray objectKeysTaken () - { - return objectKeysTaken; - } - - /** - * Returns the aspect that is considered primary - * or default. This is typically "value" or somesuch. - */ - public static String primaryAspect () - { - return ParentAspect; - } - - /** - * Returns whether this association can bind to the - * specified display group on the specified key for - * the specified aspect. - */ - public boolean canBindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey) - { - return ( aspects.containsObject( anAspect ) ); - } - - /** - * Establishes a connection between this association - * and the controlled object. Subclasses should begin - * listening for events from their controlled object here. - */ - public void establishConnection () - { - //NOTE: if nothing refers to this assocation, it gets gc'd. - // otherwise, this is not needed. - component().addObserver( this ); - - EODisplayGroup displayGroup = - displayGroupForAspect( ParentAspect ); - String key = - displayGroupKeyForAspect( ParentAspect ); - - // obtain and qualify new data source from existing source if necessary - if ( component().dataSource() == null ) - { - if ( ( displayGroup != null ) && ( displayGroup.dataSource() != null ) ) - { - component().setDataSource( - displayGroup.dataSource(). - dataSourceQualifiedByKey( key ) ); - } - } - - // set up proxy data source if necessary - if ( component().dataSource() == null ) - { - // get context and class desc from master group - EOEditingContext editingContext = null; - EOClassDescription classDesc = null; - if ( displayGroup != null ) - { - EODataSource dataSource = displayGroup.dataSource(); - if ( dataSource != null ) - { - editingContext = dataSource.editingContext(); - EOClassDescription parentDesc = dataSource.classDescriptionForObjects(); - if ( parentDesc != null ) - { - classDesc = parentDesc.classDescriptionForDestinationKey( key ); - } - } - } - - //FIXME: should this be called DetailDataSource? - component().setDataSource( - new PropertyDataSource( editingContext, classDesc ) ); - } - - super.establishConnection(); + * MasterDetailAssociation binds a display group to a property on the selected + * object of another display group. Bindings are: + * <ul> + * <li>parent: The property on the selected object of the bound display group + * that is expected to be an indexed property.</li> + * </ul> + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class MasterDetailAssociation extends EOAssociation { + static final NSArray aspects = new NSArray(new Object[] { ParentAspect }); + static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature }); + static final NSArray objectKeysTaken = new NSArray(new Object[] { "allObjects" }); + + /** + * Used to be notified of changes to objects in the controlled display group. + * requalify() should place all objects fetched into the controlled group into + * this array. Otherwise, the parent object is only marked as changed for + * inserts and deletes. + */ + protected NSMutableArray observableArray; + + /** + * Constructor expecting an EODisplayGroup. If the controlled display group does + * not have a data source, a new PropertyDataSource will be used. + */ + public MasterDetailAssociation(Object anObject) { + super(anObject); + observableArray = new ObservableArray(this); + } + + /** + * Returns a List of aspect signatures whose contents correspond with the + * aspects list. Each element is a string whose characters represent a + * capability of the corresponding aspect. + * <ul> + * <li>"A" attribute: the aspect can be bound to an attribute.</li> + * <li>"1" to-one: the aspect can be bound to a property that returns a single + * object.</li> + * <li>"M" to-one: the aspect can be bound to a property that returns multiple + * objects.</li> + * </ul> + * An empty signature "" means that the aspect can bind without needing a key. + * This implementation returns "A1M" for each element in the aspects array. + */ + public static NSArray aspectSignatures() { + return aspectSignatures; + } + + /** + * Returns a List that describes the aspects supported by this class. Each + * element in the list is the string name of the aspect. This implementation + * returns an empty list. + */ + public static NSArray aspects() { + return aspects; + } + + /** + * Returns a List of EOAssociation subclasses that, for the objects that are + * usable for this association, are less suitable than this association. + */ + public static NSArray associationClassesSuperseded() { + return new NSArray(); + } + + /** + * Returns whether this class can control the specified object. + */ + public static boolean isUsableWithObject(Object anObject) { + return (anObject instanceof EODisplayGroup); + } + + /** + * Returns a List of properties of the controlled object that are controlled by + * this class. For example, "stringValue", or "selected". + */ + public static NSArray objectKeysTaken() { + return objectKeysTaken; + } + + /** + * Returns the aspect that is considered primary or default. This is typically + * "value" or somesuch. + */ + public static String primaryAspect() { + return ParentAspect; + } + + /** + * Returns whether this association can bind to the specified display group on + * the specified key for the specified aspect. + */ + public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + return (aspects.containsObject(anAspect)); + } + + /** + * Establishes a connection between this association and the controlled object. + * Subclasses should begin listening for events from their controlled object + * here. + */ + public void establishConnection() { + // NOTE: if nothing refers to this assocation, it gets gc'd. + // otherwise, this is not needed. + component().addObserver(this); + + EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect); + String key = displayGroupKeyForAspect(ParentAspect); + + // obtain and qualify new data source from existing source if necessary + if (component().dataSource() == null) { + if ((displayGroup != null) && (displayGroup.dataSource() != null)) { + component().setDataSource(displayGroup.dataSource().dataSourceQualifiedByKey(key)); + } + } + + // set up proxy data source if necessary + if (component().dataSource() == null) { + // get context and class desc from master group + EOEditingContext editingContext = null; + EOClassDescription classDesc = null; + if (displayGroup != null) { + EODataSource dataSource = displayGroup.dataSource(); + if (dataSource != null) { + editingContext = dataSource.editingContext(); + EOClassDescription parentDesc = dataSource.classDescriptionForObjects(); + if (parentDesc != null) { + classDesc = parentDesc.classDescriptionForDestinationKey(key); + } + } + } + + // FIXME: should this be called DetailDataSource? + component().setDataSource(new PropertyDataSource(editingContext, classDesc)); + } + + super.establishConnection(); requalify(); - } - - /** - * Breaks the connection between this association and - * its object. Override to stop listening for events - * from the object. - */ - public void breakConnection () - { - //NOTE: if nothing refers to this assocation, it gets gc'd. - // otherwise, this is not needed. - component().deleteObserver( this ); - - super.breakConnection(); - } - - /** - * Called when either the selection or the contents - * of an associated display group have changed. - */ - public void subjectChanged () - { + } + + /** + * Breaks the connection between this association and its object. Override to + * stop listening for events from the object. + */ + public void breakConnection() { + // NOTE: if nothing refers to this assocation, it gets gc'd. + // otherwise, this is not needed. + component().deleteObserver(this); + + super.breakConnection(); + } + + /** + * Called when either the selection or the contents of an associated display + * group have changed. + */ + public void subjectChanged() { EODisplayGroup displayGroup; // parent aspect - displayGroup = displayGroupForAspect( ParentAspect ); - if ( displayGroup != null ) - { - if ( displayGroup.selectionChanged() ) - { - requalify(); + displayGroup = displayGroupForAspect(ParentAspect); + if (displayGroup != null) { + if (displayGroup.selectionChanged()) { + requalify(); + } else if (displayGroup.contentsChanged()) { + requalify(); } - else - if ( displayGroup.contentsChanged() ) - { - requalify(); + } + } + + /** + * Overridden to intercept notifications of changes to objects in the controlled + * display group and broadcast a change on the parent group's selected object. + * All other notifications are passed to the super implementation. + */ + public void objectWillChange(Object anObject) { + // if child display group is notifying + if (!(anObject instanceof EODisplayGroup)) { + // mark parent group's object as changed + EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect); + if (displayGroup != null) { + Object selected = displayGroup.selectedObject(); + if (selected != null) { + // only notify if childrenKey is an attribute of parentDesc + // (and therefore not a toOne or toMany relationship) + EOClassDescription parentDesc = EOClassDescription.classDescriptionForClass(selected.getClass()); + String key = displayGroupKeyForAspect(ParentAspect); + if (key != null) { + int idx = key.indexOf('.'); + if (idx != -1) + key = key.substring(0, idx); + if (parentDesc.attributeKeys().contains(key)) { + // only notify if we are an attribute key + EOObserverCenter.notifyObserversObjectWillChange(selected); + } + } + } } + } else // display group is notifying + { + // call super so subjectChanged will be called + super.objectWillChange(anObject); } - } - - /** - * Overridden to intercept notifications of changes to objects - * in the controlled display group and broadcast a change on the - * parent group's selected object. All other notifications are - * passed to the super implementation. - */ - public void objectWillChange ( Object anObject ) - { - // if child display group is notifying - if ( ! ( anObject instanceof EODisplayGroup ) ) - { - // mark parent group's object as changed - EODisplayGroup displayGroup = displayGroupForAspect( ParentAspect ); - if ( displayGroup != null ) - { - Object selected = displayGroup.selectedObject(); - if ( selected != null ) - { - // only notify if childrenKey is an attribute of parentDesc - // (and therefore not a toOne or toMany relationship) - EOClassDescription parentDesc = - EOClassDescription.classDescriptionForClass( - selected.getClass() ); - String key = displayGroupKeyForAspect( ParentAspect ); - if ( key != null ) - { - int idx = key.indexOf( '.' ); - if ( idx != -1 ) key = key.substring( 0, idx ); - if ( parentDesc.attributeKeys().contains( key ) ) - { - // only notify if we are an attribute key - EOObserverCenter.notifyObserversObjectWillChange( selected ); - } - } - } - } - } - else // display group is notifying - { - // call super so subjectChanged will be called - super.objectWillChange( anObject ); - } - } - - /** - * Called by subjectChanged() to requalify the controlled - * display group with the selected object and the bound key. - */ - protected void requalify() - { + } + + /** + * Called by subjectChanged() to requalify the controlled display group with the + * selected object and the bound key. + */ + protected void requalify() { EODisplayGroup component = component(); - EODisplayGroup displayGroup = displayGroupForAspect( ParentAspect ); - String key = displayGroupKeyForAspect( ParentAspect ); - - if ( ( displayGroup.selectedObject() != null ) - && ( component.dataSource() != null ) ) - { - component.dataSource().qualifyWithRelationshipKey( - key, displayGroup.selectedObject() ); + EODisplayGroup displayGroup = displayGroupForAspect(ParentAspect); + String key = displayGroupKeyForAspect(ParentAspect); + + if ((displayGroup.selectedObject() != null) && (component.dataSource() != null)) { + component.dataSource().qualifyWithRelationshipKey(key, displayGroup.selectedObject()); component.fetch(); - observableArray.setArray( component.allObjects() ); - } - else // no selection or no data source, clear + observableArray.setArray(component.allObjects()); + } else // no selection or no data source, clear { - component.setObjectArray( null ); - observableArray.removeAllObjects(); + component.setObjectArray(null); + observableArray.removeAllObjects(); } - component.updateDisplayedObjects(); + component.updateDisplayedObjects(); + } + + /** + * This implementation returns ObserverPrioritySecond so that master detail + * assocations are notified before other associations. + */ + public int priority() { + return ObserverPrioritySecond; } - - /** - * This implementation returns ObserverPrioritySecond - * so that master detail assocations are notified before - * other associations. - */ - public int priority () - { - return ObserverPrioritySecond; - } // convenience - private EODisplayGroup component() - { - return (EODisplayGroup) object(); - } - + private EODisplayGroup component() { + return (EODisplayGroup) object(); + } + } /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.14 2004/02/04 20:00:49 mpowers - * Improved change notification for dotted key paths. + * Revision 1.14 2004/02/04 20:00:49 mpowers Improved change notification for + * dotted key paths. * - * Revision 1.13 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.13 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.12 2001/10/26 18:39:05 mpowers - * Now a delayed observer with a higher priority, so that it is processed - * before other associations. + * Revision 1.12 2001/10/26 18:39:05 mpowers Now a delayed observer with a + * higher priority, so that it is processed before other associations. * - * Revision 1.11 2001/06/26 21:39:33 mpowers - * Added check for null component data source before requalifying. + * Revision 1.11 2001/06/26 21:39:33 mpowers Added check for null component data + * source before requalifying. * - * Revision 1.10 2001/05/21 14:04:15 mpowers - * No longer changing a detail group's data source if it's already specified. + * Revision 1.10 2001/05/21 14:04:15 mpowers No longer changing a detail group's + * data source if it's already specified. * - * Revision 1.9 2001/05/18 21:08:46 mpowers - * Now calling updateDisplayedObjects on detail after master changes. + * Revision 1.9 2001/05/18 21:08:46 mpowers Now calling updateDisplayedObjects + * on detail after master changes. * - * Revision 1.8 2001/05/14 15:26:42 mpowers - * Modified logic for controlled groups that have no data source already set. + * Revision 1.8 2001/05/14 15:26:42 mpowers Modified logic for controlled groups + * that have no data source already set. * - * Revision 1.7 2001/05/04 14:42:58 mpowers - * Now getting stored values in KeyValueCoding. - * MasterDetail now marks dirty based on whether it's an attribute - * or relation. - * Implemented editing context marker. + * Revision 1.7 2001/05/04 14:42:58 mpowers Now getting stored values in + * KeyValueCoding. MasterDetail now marks dirty based on whether it's an + * attribute or relation. Implemented editing context marker. * - * Revision 1.6 2001/04/29 02:29:31 mpowers - * Debugging relationship faulting. + * Revision 1.6 2001/04/29 02:29:31 mpowers Debugging relationship faulting. * - * Revision 1.4 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.4 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.3 2001/01/18 16:57:18 mpowers - * Fixed problem with losing connection: the association was getting - * garbage collected because nothing referred to it. All other associations - * make themselves listeners of their controlled object, and that has been - * the only thing keeping them from getting gc'd. This will need to be fixed. + * Revision 1.3 2001/01/18 16:57:18 mpowers Fixed problem with losing + * connection: the association was getting garbage collected because nothing + * referred to it. All other associations make themselves listeners of their + * controlled object, and that has been the only thing keeping them from getting + * gc'd. This will need to be fixed. * - * Revision 1.2 2001/01/17 23:06:09 mpowers - * TreeAssociation now modifies the contents of the children display - * group rather than adding items to the titles display group. + * Revision 1.2 2001/01/17 23:06:09 mpowers TreeAssociation now modifies the + * contents of the children display group rather than adding items to the titles + * display group. * - * Revision 1.1.1.1 2000/12/21 15:48:23 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:48:23 mpowers Contributing wotonomy. * - * Revision 1.5 2000/12/20 16:25:40 michael - * Added log to all files. + * Revision 1.5 2000/12/20 16:25:40 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java index aeac376..b81f9e2 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/MirrorDetailAssociation.java @@ -17,90 +17,76 @@ License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.ui; + import net.wotonomy.foundation.NSArray; /** -* This master detail association synchronizes the contents -* and selection of the master group into the detail group. -*/ -public class MirrorDetailAssociation extends MasterDetailAssociation{ + * This master detail association synchronizes the contents and selection of the + * master group into the detail group. + */ +public class MirrorDetailAssociation extends MasterDetailAssociation { - /** - * Standard constructor specifying the detail display group. - * @param displayGroup the detail display group of this - * Master-Detail Association - */ - public MirrorDetailAssociation(EODisplayGroup displayGroup){ - super(displayGroup); - } + /** + * Standard constructor specifying the detail display group. + * + * @param displayGroup the detail display group of this Master-Detail + * Association + */ + public MirrorDetailAssociation(EODisplayGroup displayGroup) { + super(displayGroup); + } - /** - * Called by subjectChanged() to requalify the controlled - * display group with the indexed object and the bound key. - * This implementation ignores both and sets the object array - * of the detail group to the displayed objects of the master - * and sets the selection to match. - */ - protected void requalify() - { - EODisplayGroup detail = (EODisplayGroup) object(); - EODisplayGroup master = - displayGroupForAspect( ParentAspect ); + /** + * Called by subjectChanged() to requalify the controlled display group with the + * indexed object and the bound key. This implementation ignores both and sets + * the object array of the detail group to the displayed objects of the master + * and sets the selection to match. + */ + protected void requalify() { + EODisplayGroup detail = (EODisplayGroup) object(); + EODisplayGroup master = displayGroupForAspect(ParentAspect); - if ( master != null ) - { - NSArray masterObjects = master.displayedObjects(); - NSArray detailObjects = detail.displayedObjects(); - int size = masterObjects.size(); - boolean different = false; - - // see if lists contain the same object instances - if ( size == detailObjects.size() ) - { - for ( int i = 0; i < size; i++ ) - { - if ( masterObjects.objectAtIndex(i) - != detailObjects.objectAtIndex(i) ) - { - different = true; - break; - } - } - } - else // different sizes - { - different = true; - } - - // if different, sync contents and selection with master - if ( different ) - { - detail.setObjectArray( masterObjects ); - detail.setSelectionIndexes( master.selectionIndexes() ); - } - else // if selection changed, sync selection with master - if ( master.selectionChanged() ) - { - detail.setSelectionIndexes( master.selectionIndexes() ); - } - } - else // no bound display group, clear - { - detail.setObjectArray( null ); - } - } + if (master != null) { + NSArray masterObjects = master.displayedObjects(); + NSArray detailObjects = detail.displayedObjects(); + int size = masterObjects.size(); + boolean different = false; + + // see if lists contain the same object instances + if (size == detailObjects.size()) { + for (int i = 0; i < size; i++) { + if (masterObjects.objectAtIndex(i) != detailObjects.objectAtIndex(i)) { + different = true; + break; + } + } + } else // different sizes + { + different = true; + } + + // if different, sync contents and selection with master + if (different) { + detail.setObjectArray(masterObjects); + detail.setSelectionIndexes(master.selectionIndexes()); + } else // if selection changed, sync selection with master + if (master.selectionChanged()) { + detail.setSelectionIndexes(master.selectionIndexes()); + } + } else // no bound display group, clear + { + detail.setObjectArray(null); + } + } } /* - * $Log$ - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2001/07/05 22:13:28 mpowers - * Now only updating if master has actually changed. + * Revision 1.2 2001/07/05 22:13:28 mpowers Now only updating if master has + * actually changed. * - * Revision 1.1 2001/05/29 19:57:47 mpowers - * Added some neglected files. + * Revision 1.1 2001/05/29 19:57:47 mpowers Added some neglected files. * * */ - diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java index a398e97..e18ed3b 100644 --- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java @@ -28,322 +28,272 @@ import net.wotonomy.foundation.NSMutableArray; import net.wotonomy.foundation.NSRange; /** -* A package class that extends NSMutableArray but makes use -* of the fact that wotonomy's implementation extends ArrayList -* to intercept insertions and deletion and register and -* unregister objects for change notifications as appropriate. -* Since we can't be sure of ArrayList's implementation, we're -* forced to override each and every add and remove method, -* some of which probably call each other. However, -* EOObserverCenter will only register us once per object. -*/ -class ObservableArray extends NSMutableArray -{ - EOObserving observer; - - ObservableArray( EOObserving anObserver ) - { - observer = anObserver; - } - + * A package class that extends NSMutableArray but makes use of the fact that + * wotonomy's implementation extends ArrayList to intercept insertions and + * deletion and register and unregister objects for change notifications as + * appropriate. Since we can't be sure of ArrayList's implementation, we're + * forced to override each and every add and remove method, some of which + * probably call each other. However, EOObserverCenter will only register us + * once per object. + */ +class ObservableArray extends NSMutableArray { + EOObserving observer; + + ObservableArray(EOObserving anObserver) { + observer = anObserver; + } + /** - * Removes the last object from the array. - */ - public void removeLastObject () - { - remove( count() - 1 ); - } + * Removes the last object from the array. + */ + public void removeLastObject() { + remove(count() - 1); + } /** - * Removes the object at the specified index. - */ - public void removeObjectAtIndex (int index) - { - remove( index ); - } + * Removes the object at the specified index. + */ + public void removeObjectAtIndex(int index) { + remove(index); + } /** - * Adds all objects in the specified collection. - */ - public void addObjectsFromArray (Collection aCollection) - { - addAll( aCollection ); - } + * Adds all objects in the specified collection. + */ + public void addObjectsFromArray(Collection aCollection) { + addAll(aCollection); + } /** - * Removes all objects from the array. - */ - public void removeAllObjects () - { - clear(); - } + * Removes all objects from the array. + */ + public void removeAllObjects() { + clear(); + } /** - * Removes all objects equivalent to the specified object - * within the range of specified indices. - */ - public void removeObject (Object anObject, NSRange aRange) - { - if ( ( anObject == null ) || ( aRange == null ) ) return; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject.equals( get( i ) ) ) - { - remove( i ); - i = i - 1; - max = max - 1; - } - } - } + * Removes all objects equivalent to the specified object within the range of + * specified indices. + */ + public void removeObject(Object anObject, NSRange aRange) { + if ((anObject == null) || (aRange == null)) + return; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject.equals(get(i))) { + remove(i); + i = i - 1; + max = max - 1; + } + } + } /** - * Removes all instances of the specified object within the - * range of specified indices, comparing by reference. - */ - public void removeIdenticalObject (Object anObject, NSRange aRange) - { - if ( ( anObject == null ) || ( aRange == null ) ) return; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject == get( i ) ) - { - remove( i ); - i = i - 1; - max = max - 1; - } - } - } + * Removes all instances of the specified object within the range of specified + * indices, comparing by reference. + */ + public void removeIdenticalObject(Object anObject, NSRange aRange) { + if ((anObject == null) || (aRange == null)) + return; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject == get(i)) { + remove(i); + i = i - 1; + max = max - 1; + } + } + } /** - * Removes all objects in the specified collection from the array. - */ - public void removeObjectsInArray (Collection aCollection) - { - removeAll( aCollection ); - } + * Removes all objects in the specified collection from the array. + */ + public void removeObjectsInArray(Collection aCollection) { + removeAll(aCollection); + } /** - * Removes all objects in the indices within the specified range - * from the array. - */ - public void removeObjectsInRange (NSRange aRange) - { - if ( aRange == null ) return; - - for ( int i = 0; i < aRange.length(); i++ ) - { - remove( aRange.location() ); - } - } + * Removes all objects in the indices within the specified range from the array. + */ + public void removeObjectsInRange(NSRange aRange) { + if (aRange == null) + return; + + for (int i = 0; i < aRange.length(); i++) { + remove(aRange.location()); + } + } /** - * Replaces objects in the current range with objects from - * the specified range of the specified array. If currentRange - * is larger than otherRange, the extra objects are removed. - * If otherRange is larger than currentRange, the extra objects - * are added. - */ - public void replaceObjectsInRange (NSRange currentRange, - List otherArray, NSRange otherRange) - { - if ( ( currentRange == null ) || ( otherArray == null ) || - ( otherRange == null ) ) return; - + * Replaces objects in the current range with objects from the specified range + * of the specified array. If currentRange is larger than otherRange, the extra + * objects are removed. If otherRange is larger than currentRange, the extra + * objects are added. + */ + public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) { + if ((currentRange == null) || (otherArray == null) || (otherRange == null)) + return; + // transform otherRange if out of bounds for array - if ( otherRange.maxRange() > otherArray.size() ) - { + if (otherRange.maxRange() > otherArray.size()) { // TODO: Test this logic. - int loc = Math.min( otherRange.location(), otherArray.size() - 1 ); - otherRange = new NSRange( loc, otherArray.size() - loc ); + int loc = Math.min(otherRange.location(), otherArray.size() - 1); + otherRange = new NSRange(loc, otherArray.size() - loc); } - + Object o; - List subList = subList( - currentRange.location(), currentRange.maxRange() ); + List subList = subList(currentRange.location(), currentRange.maxRange()); int otherIndex = otherRange.location(); // TODO: Test this logic. - for ( int i = 0; i < subList.size(); i++ ) - { - if ( otherIndex < otherRange.maxRange() ) - { // set object - subList.set( i, otherArray.get( otherIndex ) ); - } - else - { // remove extra elements from currentRange - subList.remove( i ); - i--; + for (int i = 0; i < subList.size(); i++) { + if (otherIndex < otherRange.maxRange()) { // set object + subList.set(i, otherArray.get(otherIndex)); + } else { // remove extra elements from currentRange + subList.remove(i); + i--; } otherIndex++; } // TODO: Test this logic. - for ( int i = otherIndex; i < otherRange.maxRange(); i++ ) - { - add( otherArray.get( i ) ); + for (int i = otherIndex; i < otherRange.maxRange(); i++) { + add(otherArray.get(i)); } } /** - * Clears the current array and then populates it with the - * contents of the specified collection. - */ - public void setArray (Collection aCollection) - { - clear(); - addAll( aCollection ); - } + * Clears the current array and then populates it with the contents of the + * specified collection. + */ + public void setArray(Collection aCollection) { + clear(); + addAll(aCollection); + } /** - * Removes all objects equivalent to the specified object. - */ - public void removeObject (Object anObject) - { - remove( anObject ); - } + * Removes all objects equivalent to the specified object. + */ + public void removeObject(Object anObject) { + remove(anObject); + } /** - * Removes all occurences of the specified object, - * comparing by reference. - */ - public void removeIdenticalObject (Object anObject) - { - EOObserverCenter.removeObserver( observer, anObject ); - super.removeIdenticalObject( anObject ); - } + * Removes all occurences of the specified object, comparing by reference. + */ + public void removeIdenticalObject(Object anObject) { + EOObserverCenter.removeObserver(observer, anObject); + super.removeIdenticalObject(anObject); + } /** - * Inserts the specified object into this array at the - * specified index. - */ - public void insertObjectAtIndex (Object anObject, int anIndex) - { - add( anIndex, anObject ); - } - + * Inserts the specified object into this array at the specified index. + */ + public void insertObjectAtIndex(Object anObject, int anIndex) { + add(anIndex, anObject); + } + /** - * Replaces the object at the specified index with the - * specified object. - */ - public void replaceObjectAtIndex (int anIndex, Object anObject) - { - set( anIndex, anObject ); - } + * Replaces the object at the specified index with the specified object. + */ + public void replaceObjectAtIndex(int anIndex, Object anObject) { + set(anIndex, anObject); + } /** - * Adds the specified object to the end of this array. - */ - public void addObject (Object anObject) - { - add( anObject ); - } - - // interface List: mutators - - public void add(int index, Object element) - { - EOObserverCenter.addObserver( observer, element ); - super.add( index, element ); - } - - public boolean add(Object o) - { - EOObserverCenter.addObserver( observer, o ); - return super.add(o); - } - - public boolean addAll(Collection coll) - { - Iterator it = coll.iterator(); - while ( it.hasNext() ) - { - EOObserverCenter.addObserver( observer, it.next() ); - } - return super.addAll(coll); - } - - public boolean addAll(int index, Collection c) - { - Iterator it = c.iterator(); - while ( it.hasNext() ) - { - EOObserverCenter.addObserver( observer, it.next() ); - } - return super.addAll( index, c ); - } - - public void clear() - { - Iterator it = iterator(); - while ( it.hasNext() ) - { - EOObserverCenter.removeObserver( observer, it.next() ); - } - super.clear(); - } - - public Object remove(int index) - { - EOObserverCenter.removeObserver( observer, get(index) ); - return super.remove( index ); - } - - public boolean remove(Object o) - { - EOObserverCenter.removeObserver( observer, o ); - return super.remove(o); - } - - public boolean removeAll(Collection coll) - { - Iterator it = coll.iterator(); - while ( it.hasNext() ) - { - EOObserverCenter.removeObserver( observer, it.next() ); - } - return super.removeAll(coll); - } - - public boolean retainAll(Collection coll) - { - throw new UnsupportedOperationException(); - } - - public Object set(int index, Object element) - { - EOObserverCenter.removeObserver( observer, get(index) ); - EOObserverCenter.addObserver( observer, element ); - return super.set( index, element ); - } + * Adds the specified object to the end of this array. + */ + public void addObject(Object anObject) { + add(anObject); + } + + // interface List: mutators + + public void add(int index, Object element) { + EOObserverCenter.addObserver(observer, element); + super.add(index, element); + } + + public boolean add(Object o) { + EOObserverCenter.addObserver(observer, o); + return super.add(o); + } + + public boolean addAll(Collection coll) { + Iterator it = coll.iterator(); + while (it.hasNext()) { + EOObserverCenter.addObserver(observer, it.next()); + } + return super.addAll(coll); + } + + public boolean addAll(int index, Collection c) { + Iterator it = c.iterator(); + while (it.hasNext()) { + EOObserverCenter.addObserver(observer, it.next()); + } + return super.addAll(index, c); + } + + public void clear() { + Iterator it = iterator(); + while (it.hasNext()) { + EOObserverCenter.removeObserver(observer, it.next()); + } + super.clear(); + } + + public Object remove(int index) { + EOObserverCenter.removeObserver(observer, get(index)); + return super.remove(index); + } + + public boolean remove(Object o) { + EOObserverCenter.removeObserver(observer, o); + return super.remove(o); + } + + public boolean removeAll(Collection coll) { + Iterator it = coll.iterator(); + while (it.hasNext()) { + EOObserverCenter.removeObserver(observer, it.next()); + } + return super.removeAll(coll); + } + + public boolean retainAll(Collection coll) { + throw new UnsupportedOperationException(); + } + + public Object set(int index, Object element) { + EOObserverCenter.removeObserver(observer, get(index)); + EOObserverCenter.addObserver(observer, element); + return super.set(index, element); + } } /* - * $Log$ - * Revision 1.2 2006/02/18 23:14:35 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:14:35 cgruber Update imports and maven + * dependencies. * - * 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.3 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.2 2002/10/24 21:15:36 mpowers - * New implementations of NSArray and subclasses. + * Revision 1.2 2002/10/24 21:15:36 mpowers New implementations of NSArray and + * subclasses. * - * Revision 1.1 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.1 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.1 2001/01/24 14:37:24 mpowers - * Contributing a delegate useful for debugging. + * Revision 1.1 2001/01/24 14:37:24 mpowers Contributing a delegate useful for + * debugging. * * */ - |
