home *** CD-ROM | disk | FTP | other *** search
- // EOEditingContext.h
- // Copyright (c) 1995, NeXT Software, Inc. All rights reserved.
- //
- // The EOEditingContext, which represents a single "object space" or
- // document in an application, holds a graph of enterprise objects.
- // All objects fetched from an external store are registered in an
- // EOEditingContext along with a global identifier (EOGlobalID) that's
- // used to uniquely identify each object to the external store.
- // The EOEditingContext is responsible for watching for changes in its
- // objects (using the EOObserving protocol) and recording snapshots for
- // object-based undo.
- //
- // The object graph that an EOEditingContext monitors is created by the
- // EOEditingContext's parent EOObjectStore. The EditingContext is itself
- // an EOObjectStore, which gives it the ability to act as an EOObjectStore
- // for another EOEditingContext. In other words, EOEditingContexts can be
- // nested, thereby allowing a user to make edits to copy of an one object
- // graph in one editing context and then discard or commit those changes to
- // another object graph (which, in turn, may commit them to an external store).
- //
- // A single enterprise object instance exists in one and only one context,
- // but a multiple copies of an object may exist in different editing contexts.
- // Thus object uniquing is scoped to an EOEditingContext.
- //
-
- #import <Foundation/Foundation.h>
- #import <EOControl/EOObjectStore.h>
- #import <EOControl/EOObserver.h>
- #import <EOControl/EODefines.h>
-
- @class EOUndoManager;
-
- @interface EOEditingContext : EOObjectStore <EOObserving>
- {
- EOObjectStore *_objectStore;
- EOUndoManager *_undoManager;
- NSHashTable *_unprocessedChanges;
- NSHashTable *_unprocessedDeletes;
- NSHashTable *_unprocessedInserts;
- NSHashTable *_insertedObjects;
- NSHashTable *_deletedObjects;
- NSHashTable *_changedObjects;
-
- NSHashTable *_infoById;
- NSHashTable *_infoByGID;
- id _delegate;
- NSMutableArray *_editors;
- id _messageHandler;
- unsigned short _undoTransactionID;
- struct {
- unsigned registeredForCallback:1;
- unsigned propagatesDeletesAtEndOfEvent:1;
- unsigned ignoreChangeNotification:1;
- unsigned exhaustiveValidation:1;
- unsigned autoLocking:1;
- unsigned processingChanges:1;
- unsigned skipInvalidateOnDealloc:1;
- unsigned useCommittedSnapshot:1;
- unsigned unused:8;
- } _flags;
- }
-
- // Commonly used methods //////////////////////////////////
-
- - initWithParentObjectStore:(EOObjectStore *)parentObjectStore;
- // Designated initializer.
- // Initializes the receiver with a parent EOObjectStore.
- // Returns self.
-
- - init;
- // equivalent to [[EOEditingContext alloc] initWithParentObjectStore:
- // [EOEditingContext defaultParentObjectStore]]
-
- - (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification;
- // returns an array of objects matching the given query. This fetches from the
- // parentObjectStore.
-
- - (void)insertObject:(id)object;
- // Registers a new object that should be inserted in the parent EOObjectStore
- // when changes are saved. This automatically records the new object with a
- // EOTemporaryGlobalID gid. When the external store commits the object it
- // should rerecord it with the appropriate global ID.
-
- - (void)deleteObject:(id)object;
- // Registers that an existing object should be removed from the parent
- // EOObjectStore when changes are saved. The object will be removed from
- // the uniquing tables when changes are committed.
-
- - (void)lockObject:(id)object;
- // attempts to lock the given object in the external store. Raises an
- // exception if unable to obtain the lock.
-
- // Saving
- - (BOOL)hasChanges;
- // Returns YES if any object has been modified; that is, if any objects
- // have been edited, inserted, or deleted.
-
- - (void)saveChanges;
- // Commits changes made in the EOEditingContext to the parent EOObjectStore.
- // Raises an exception if a validation or database error occurs.
-
- - (void)revert;
- // Removes everything from the undo stack. Throws out all insertions and
- // deletions and restores updated objects to their last committed values.
- // Does not refetch from the database.
- // Note: This does not undo changes in display groups. Display groups that
- // allow insertion and deletion of objects need to be refetched or somehow
- // re-synced whenever their editing context is reverted.
-
- - (id)objectForGlobalID:(EOGlobalID *)globalID;
- - (EOGlobalID *)globalIDForObject:object;
- // All objects fetched from an external store are registered in an
- // EOEditingContext along with a global identifier (EOGlobalID) that's used
- // to uniquely identify each object to the external store. These methods
- // (respectively) return an object given its globalID, or return a globalID
- // given a pointer to its object. If no match is found, these methods return nil.
-
- - (void)setDelegate:(id)delegate;
- - (id)delegate;
- // These methods set/return the delegate of the EOEditingContext
-
- - (EOObjectStore *)parentObjectStore;
- // Returns the receiver's parent EOObjectStore (that is, the persistent
- // store for objects in this EOEditingContext)
-
- - (EOObjectStore *)rootObjectStore;
- // Returns the EOEditingContext's parent EOObjectStore.
- // When EditingContexts are nested, returns the non-EOEditingContext
- // EOObjectStore at the base of the tree (usually an EOObjectStoreCoordinator)
-
-
- // Advanced methods //////////////////////////
-
- - (void)setUndoManager:(EOUndoManager *)undoManager;
- - (EOUndoManager *)undoManager;
- // These methods set/return the object in which the EOEditingContext
- // registers undos
-
- - (void)objectWillChange:(id)object;
- // Implementation of EOObserving protocol.
- // Automatically called by [self willChange] on any registered object.
-
- - (void)recordObject:(id)object globalID:(EOGlobalID *)globalID;
- // Makes the EOEditingContext aware of an object existing in its EOObjectStore.
- // EOObjectStores (such as the EODatabaseContext) usually call this for each
- // object fetched. The EOEditingContext then enters the object in its uniquing
- // table and subscribes to willChange notification on the object.
-
- - (void)forgetObject:(id)object;
- // Removes object from uniquing tables and causes the EOEditingContext
- // to remove itself as a willChange observer. This is called automatically
- // when an object being observed by an EOEditingContext is deallocated.
-
- - (NSArray *)registeredObjects;
- // Returns an array containing all of the EOs managed by this editingContext.
-
- - (NSArray *)updatedObjects;
- - (NSArray *)insertedObjects;
- - (NSArray *)deletedObjects;
- // Returns a list of changes made in the object graph managed by the
- // EOEditingContext.
-
- - (void)processRecentChanges;
- // When objects are changed (inserted, updated, and deleted), processing of
- // the changes is normally deferred until the end of the current event.
- // At that point, objects are moved to the inserted, updated, and deleted
- // lists, delete propagation is performed, undos are registered,
- // and the EOObjectsChangedInStoreNotification is sent (usually causing the
- // UI to update). Calling processRecentChanges forces this all to be done
- // synchronously. The EOEditingContext automatically calls this method on
- // itself before performing certain operations (e.g. saveChanges).
-
- - (BOOL)propagatesDeletesAtEndOfEvent;
- - (void)setPropagatesDeletesAtEndOfEvent:(BOOL)propagatesDeletesAtEndOfEvent;
- // If propagatesDeletesAtEndOfEvent is YES, any explicit deletion of an EO
- // using [editingContext deleteObject:] or an implicit deletion of an EO
- // by removing it from an owning relationship, will trigger delete propagation
- // at the end of the event in which the deletion occured. Delete propagation
- // uses the delete rule information available from EOClassDescription to
- // possibly delete other objects related to the deleted ones.
- // If delete propagation fails (an EO refuses to be deleted -- possibly
- // due to a deny rule) all changes made during the event are rolled back
- // and a validation error is processed via editingContext:presentErrorMessage:.
- // If propagatesDeletesAtEndOfEvent is NO, delete propagation is not performed
- // until saveChanges is called.
-
- - (BOOL)stopsValidationAfterFirstError;
- - (void)setStopsValidationAfterFirstError:(BOOL)yn;
- // Determines whether or not validation (upon save, for instance)
- // stops after the first error is encountered, or continues for all
- // objects. The latter is useful if the delegate implements
- // editingContext:shouldPresentException: to handle aggregate
- // exceptions.
-
- - (BOOL)locksObjectsBeforeFirstModification;
- - (void)setLocksObjectsBeforeFirstModification:(BOOL)yn;
- // If locksObjectsBeforeFirstModification is set, the editingContext
- // will automatically call [self lockObject:obj] to lock an object in its
- // external store the first time the object is modified. This may result in
- // an exception being raised in willChange if the lock cannot be obtained.
- // By default this mode is off.
-
- // Snapshotting
- - (NSDictionary *)committedSnapshotForObject:(id)object;
- // snapshot for this object before it was first modified.
- // This snapshot is updated to the newest object state after a save.
-
- - (NSDictionary *)currentEventSnapshotForObject:(id)object;
- // snapshot for the state of the object at the beginning of the current
- // event. After the end of the current event, this snapshot is recorded with
- // the undo manager to undo changes to this object and the return value
- // method is updated to hold modified state of the object.
-
- - (void)refaultObjects;
- // Refaults all objects that haven't been modified, inserted or deleted.
-
- - (void)setInvalidatesObjectsWhenFreed:(BOOL)yn;
- - (BOOL)invalidatesObjectsWhenFreed;
- // returns whether the editing context invalidates (clears and booby traps)
- // all of the objects registered with it when the context is deallocated.
- // The default is YES.
-
- - (void)addEditor:(id)editor;
- - (void)removeEditor:(id)editor;
- - (NSArray *)editors;
- // Editors are special-purpose delegate objects that may have uncomitted
- // changes that need to be validated and flushed to objects before
- // the EOEditingContext saves changes. EODisplayGroups register themselves
- // as editors with the EOEditingContext of their dataSources.
- // See the EOEditors delegate category below for more information.
-
- - (void)setMessageHandler:(id)handler;
- - (id)messageHandler;
- // The message handler is a special-purpose delegate responsible for
- // presenting errors to the user. Typically an EODisplayGroup will
- // register itself as the message handler for its EOEditingContext.
- // See EOMessageHandlers delegate category below for more information.
- // These methods set/return the message handler of the EOEditingContext.
-
- // EditingContext implementation of EOObjectStore methods.
- // Used when an EOEditingContext acts as an ObjectStore for
- // another EditingContext.
- - (id)faultForGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
- // If a object has already been registered in the given EOEditingContext it
- // is returned. If not, a newly constructed fault is returned.
- // When a parent EOEditingContext receives this on behalf of a child context, and
- // the globalID identifies a newly inserted object in the parent, the parent
- // registers a copy of its object in the child. Otherwise, the EditingContext
- // propagates this message to its parentObjectStore.
-
- - (NSArray *)arrayFaultWithSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
- // When a parent EOEditingContext receives this on behalf of a child context, and
- // the globalID identifies a newly inserted object in the parent, the parent
- // returns a copy of its object's relationship array translated into the child.
- // Otherwise, the EditingContext propagates this message to its parentObjectStore.
-
- - (void)initializeObject:(id)object withGlobalID:(EOGlobalID *)globalID
- editingContext:(EOEditingContext *)context;
- // Build the properties for the object uniqued by globalID.
- // When a parent EOEditingContext receives this on behalf of a child context, and
- // the globalID identifies object instantiated in the parent, the parent returns
- // uses properties extracted from its object and translated into the
- // child's context. This ensures that a nested context "inherits" modified values
- // from its parent context.
- // If the receiving context does not have the given object, the request is fowarded
- // its parentObjectStore.
-
- - (NSArray *)objectsForSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
- // This method is used to fire a to-many fault.
- // When a parent EOEditingContext receives this on behalf of a child context, and
- // the globalID identifies object instantiated in the parent, the parent returns
- // a copy of its relationship array translated into the child's context.
- // This ensures that a nested context "inherits" modified values from its parent context.
- // If the receiving context does not have the given object, or the parents
- // relationship property is still an EOFault, the request is fowarded
- // its parentObjectStore.
-
- - (void)refaultObject:object withGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
- // Turn an Enterprise Object back into a fault. This method should be used with caution.
- // Refaulting an object does not remove the object snapshot from the undo stack. Objects
- // that have been inserted or deleted should be not refaulted.
-
- - (void)saveChangesInEditingContext:(EOEditingContext *)context;
- // Sent by an EditingContext to its ObjectStore to commit changes. This method should
- // not be invoked directly. It is called by a nested EOEditingContext when committing
- // changes to a parent context. The receiving parent EOEditingContext will copy
- // all changes from the nested context into its own copies of the objects, but will
- // not immediately save those changes to the database. When the parent itself is
- // sent saveChanges, it will propagate any changes saved from the child, along with
- // any other changes,its parentObjectStore.
- // Raises an exception if an error occurs.
-
- - (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)context;
- // The base method to get an array of objects. The EOEditingContext simply forwards
- // this message onto it parentObjectStore.
- // Raises an exception if an error occurs.
-
- - (void)lockObjectWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
- // passes lock request to parentObjectStore.
-
- - (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
- // passes lock query to parentObjectStore.
-
- @end
-
- // used with NSRunLoop's performSelector:target:argument:order:modes:
- enum {
- EOEditingContextFlushChangesRunLoopOrdering = 300000
- };
-
- // Notifications
- // EOObjectsChangedInStoreNotification is broadcast by the editing context whenever
- // objectWillChange observer notifications are processed. This is usually as the
- // end of the event in which the changes occured. See EOObjectStore.h for more
- // information on this notification.
- // EODisplayGroups listen for this notification to redisplay their contents.
-
- // EOInvalidatedAllObjectsInStoreNotification is broadcast whenever the
- // editing context is invalidating all its objects. When an EditingContext receives
- // this notification from its parent objectStore it will clear its
- // inserted/updated/deleted lists and reset its undo stack. See EOObjectStore.h
- // for more information on this notification.
- // EODisplayGroups listen for this notification to refetch their contents.
-
- // EOObjectsChangedInEditingContextNotification is broadcast whenever changes are
- // made in an EditingContext. This notification is similar to
- // EOObjectsChangedInStoreNotification, but this notifications contains
- // objects rather than GlobalID's.
- //
- // object = sending EditingContext
- // userInfo = {
- // updated = (array of changed objects);
- // deleted = (array of deleted objects);
- // inserted = (array of inserted objects);
- // invalidated = (array of invalidated objects);
- // }
- // Invalidated objects are those for which the cached view can should no longer
- // be trusted. Invalidated objects should be refaulted so that they are refetched
- // when next examined.
- //
- EOCONTROL_EXTERN NSString *EOObjectsChangedInEditingContextNotification;
-
- // EOEditingContextDidSaveChangesNotification is broadcast after
- // changes are saved to the objectStore used by the editingContext.
- //
- // object = sending EditingContext
- // userInfo = nil
- //
- EOCONTROL_EXTERN NSString *EOEditingContextDidSaveChangesNotification;
-
- @interface NSObject (EOEditingContext)
- - (EOEditingContext *)editingContext;
- // returns the editingContext in which this object lives or
- // nil if this object has not been registered.
- @end
-
- //
- // Delegation methods
- //
- @interface NSObject (EOEditingContextDelegation)
- - (BOOL)editingContext:(EOEditingContext *)editingContext shouldPresentException:(NSException *)exception;
- // if delegate implements this message and returns NO, the
- // exception is ignored. Otherwise it is passed to the message
- // handler with editingContext:presentErrorMessage:
-
- - (BOOL)editingContextShouldValidateChanges:(EOEditingContext *)editingContext;
- // If the delegate returns NO, the validation is bypassed.
-
- - (void)editingContextWillSaveChanges:(EOEditingContext *)editingContext;
- // The delegate could raise to abort the save.
-
- - (BOOL)editingContext:(EOEditingContext *)editingContext shouldInvalidateObject:(id)object globalID:(EOGlobalID *)gid;
- // Permits delegate to selectively override which objects are invalidated.
-
- - (BOOL)editingContextShouldUndoUserActionsAfterFailure:(EOEditingContext *)context;
- // Permits delegate to turn off undoing of user actions after validation has resulted
- // in an error.
-
- - (NSArray *)editingContext:(EOEditingContext *)editingContext willFetchObjectsDescribedByFetchSpecification:(EOFetchSpecification *)fetchSpecification;
- // Called by objectsWithFetchSpecification:editingContext:. If delegate already
- // has appropriate results cached
-
- @end
-
- //
- // EOEditors informal protocol
- //
- @interface NSObject (EOEditors)
- - (BOOL)editorHasChangesForEditingContext:(EOEditingContext *)editingContext;
- // Called by the EOEditingContext to determine if the editor is "dirty"
-
- - (void)editingContextWillSaveChanges:(EOEditingContext *)editingContext;
- // Passed first to the editors, then to the delegate. Editors
- // should validate any unprocessed fields and save changes to the objects.
- // If any editors raise, the save is aborted.
- @end
-
- //
- // EOMessageHandler informal protocol
- //
- @interface NSObject (EOMessageHandlers)
- - (void)editingContext:(EOEditingContext *)editingContext presentErrorMessage:(NSString *)message;
- // The message handler should present error to user
- // (in an alert panel, for instance)
- @end
-
-
- @interface EOEditingContext (EORendezvous)
- + (void)setSubstitutionEditingContext:(EOEditingContext *)ec;
- + (EOEditingContext *)substitutionEditingContext;
- // An editing context that will be swapped in in place of any
- // context read from a nib file. If substitutionEditingContext
- // is set to nil, the EditingContext loaded from the nib is
- // used by default.
-
- + (void)setDefaultParentObjectStore:(EOObjectStore *)store;
- + (EOObjectStore *)defaultParentObjectStore;
- // The default parentObjectStore for editing contexts read from
- // a nib. By default this is the
- // [EOObjectStoreCoordinator defaultCoordinator].
- // This may be set to a different coordinator, or another EditingContext
- // (for a nested editing context configuration) prior to loading a nib.
- @end
-
- @interface EOEditingContext (EOStateArchiving)
- // These are methods EOs invoke to implement encodeWithCoder: and initWithCoder:.
- // These are primarily useful for minimal freeze-drying of state relative to the
- // parent state. Unmodified objects are archived with just their globalIDs (since
- // their state can be fetched from the object store). Modified or inserted objects
- // archive all of their classProperties.
- //
- + (void)setUsesContextRelativeEncoding:(BOOL)yn;
- + (BOOL)usesContextRelativeEncoding;
- + (void)encodeObject:(id)object withCoder:(NSCoder *)coder;
- + (id)initObject:(id)object withCoder:(NSCoder *)coder;
- @end
-
- // Target action methods for InterfaceBuilder
- //
- @interface EOEditingContext (EOTargetAction)
- - (void)saveChanges:(id)sender;
- - (void)refault:(id)sender;
- - (void)revert:(id)sender;
- - (void)refetch:(id)sender;
-
- // Forward messages on to the undoManager of this editing context
- - (void)undo:(id)sender;
- - (void)redo:(id)sender;
- @end
-
-