home *** CD-ROM | disk | FTP | other *** search
/ OpenStep (Enterprise) / OpenStepENTCD.toast / OEDEV / EODEV.Z / EOEditingContext.h < prev    next >
Encoding:
Text File  |  1996-09-11  |  21.0 KB  |  451 lines

  1. // EOEditingContext.h
  2. // Copyright (c) 1995, NeXT Software, Inc. All rights reserved. 
  3. //
  4. // The EOEditingContext, which represents a single "object space" or
  5. // document in an application, holds a graph of enterprise objects.
  6. // All objects fetched from an external store are registered in an
  7. // EOEditingContext along with a global identifier (EOGlobalID) that's
  8. // used to uniquely identify each object to the external store.
  9. // The EOEditingContext is responsible for watching for changes in its
  10. // objects (using the EOObserving protocol) and recording snapshots for
  11. // object-based undo.
  12. //
  13. // The object graph that an EOEditingContext monitors is created by the
  14. // EOEditingContext's parent EOObjectStore. The EditingContext is itself
  15. // an EOObjectStore, which gives it the ability to act as an EOObjectStore
  16. // for another EOEditingContext. In other words, EOEditingContexts can be
  17. // nested, thereby allowing a user to make edits to copy of an one object
  18. // graph in one editing context and then discard or commit those changes to
  19. // another object graph (which, in turn, may commit them to an external store).
  20. //
  21. // A single enterprise object instance exists in one and only one context,
  22. // but a multiple copies of an object may exist in different editing contexts.
  23. // Thus object uniquing is scoped to an EOEditingContext.
  24. //
  25.  
  26. #import <Foundation/Foundation.h>
  27. #import <EOControl/EOObjectStore.h>
  28. #import <EOControl/EOObserver.h>
  29. #import <EOControl/EODefines.h>
  30.  
  31. @class EOUndoManager;
  32.  
  33. @interface EOEditingContext : EOObjectStore <EOObserving>
  34. {
  35.     EOObjectStore *_objectStore;
  36.     EOUndoManager *_undoManager;
  37.     NSHashTable *_unprocessedChanges;
  38.     NSHashTable *_unprocessedDeletes;
  39.     NSHashTable *_unprocessedInserts;
  40.     NSHashTable *_insertedObjects; 
  41.     NSHashTable *_deletedObjects;
  42.     NSHashTable *_changedObjects;
  43.  
  44.     NSHashTable *_infoById;
  45.     NSHashTable *_infoByGID;
  46.     id _delegate;
  47.     NSMutableArray *_editors;
  48.     id _messageHandler;
  49.     unsigned short _undoTransactionID;
  50.     struct {
  51.         unsigned registeredForCallback:1;
  52.         unsigned propagatesDeletesAtEndOfEvent:1;
  53.         unsigned ignoreChangeNotification:1;
  54.         unsigned exhaustiveValidation:1;
  55.         unsigned autoLocking:1;
  56.         unsigned processingChanges:1;
  57.         unsigned skipInvalidateOnDealloc:1;
  58.         unsigned useCommittedSnapshot:1;
  59.         unsigned unused:8;
  60.     } _flags;
  61. }
  62.  
  63. // Commonly used methods //////////////////////////////////
  64.  
  65. - initWithParentObjectStore:(EOObjectStore *)parentObjectStore;
  66.     // Designated initializer.
  67.     // Initializes the receiver with a parent EOObjectStore.
  68.     // Returns self.
  69.  
  70. - init;
  71.     // equivalent to [[EOEditingContext alloc] initWithParentObjectStore:
  72.     //                    [EOEditingContext defaultParentObjectStore]]
  73.  
  74. - (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification;
  75.     // returns an array of objects matching the given query.  This fetches from the
  76.     // parentObjectStore.
  77.  
  78. - (void)insertObject:(id)object;
  79.     // Registers a new object that should be inserted in the parent EOObjectStore
  80.     // when changes are saved.  This automatically records the new object with a
  81.     // EOTemporaryGlobalID gid.  When the external store commits the object it
  82.     // should rerecord it with the appropriate global ID.
  83.  
  84. - (void)deleteObject:(id)object;
  85.     // Registers that an existing object should be removed from the parent
  86.     // EOObjectStore when changes are saved. The object will be removed from
  87.     // the uniquing tables when changes are committed.
  88.  
  89. - (void)lockObject:(id)object;
  90.     // attempts to lock the given object in the external store.  Raises an
  91.     // exception if unable to obtain the lock.
  92.  
  93. // Saving
  94. - (BOOL)hasChanges;
  95.     // Returns YES if any object has been modified; that is, if any objects
  96.     // have been edited, inserted, or deleted.
  97.  
  98. - (void)saveChanges;
  99.     // Commits changes made in the EOEditingContext to the parent EOObjectStore.
  100.     // Raises an exception if a validation or database error occurs.
  101.  
  102. - (void)revert;
  103.     // Removes everything from the undo stack. Throws out all insertions and
  104.     // deletions and restores updated objects to their last committed values.
  105.     // Does not refetch from the database.
  106.     // Note: This does not undo changes in display groups. Display groups that
  107.     // allow insertion and deletion of objects need to be refetched or somehow
  108.     // re-synced whenever their editing context is reverted.
  109.  
  110. - (id)objectForGlobalID:(EOGlobalID *)globalID;
  111. - (EOGlobalID *)globalIDForObject:object;
  112.     // All objects fetched from an external store are registered in an
  113.     // EOEditingContext along with a global identifier (EOGlobalID) that's used
  114.     // to uniquely identify each object to the external store. These methods
  115.     // (respectively) return an object given its globalID, or return a globalID
  116.     // given a pointer to its object. If no match is found, these methods return nil.
  117.  
  118. - (void)setDelegate:(id)delegate;
  119. - (id)delegate;
  120.     // These methods set/return the delegate of the EOEditingContext
  121.  
  122. - (EOObjectStore *)parentObjectStore;
  123.     // Returns the receiver's parent EOObjectStore (that is, the persistent
  124.     // store for objects in this EOEditingContext)
  125.  
  126. - (EOObjectStore *)rootObjectStore;
  127.     // Returns the EOEditingContext's parent EOObjectStore.
  128.     // When EditingContexts are nested, returns the non-EOEditingContext
  129.     // EOObjectStore at the base of the tree (usually an EOObjectStoreCoordinator)
  130.  
  131.  
  132. // Advanced methods //////////////////////////
  133.  
  134. - (void)setUndoManager:(EOUndoManager *)undoManager;
  135. - (EOUndoManager *)undoManager;
  136.     // These methods set/return the object in which the EOEditingContext 
  137.     // registers undos
  138.  
  139. - (void)objectWillChange:(id)object;
  140.     // Implementation of EOObserving protocol.
  141.     // Automatically called by [self willChange] on any registered object.
  142.  
  143. - (void)recordObject:(id)object globalID:(EOGlobalID *)globalID;
  144.     // Makes the EOEditingContext aware of an object existing in its EOObjectStore.
  145.     // EOObjectStores (such as the EODatabaseContext) usually call this for each
  146.     // object fetched. The EOEditingContext then enters the object in its uniquing
  147.     // table and subscribes to willChange notification on the object.
  148.  
  149. - (void)forgetObject:(id)object;
  150.     // Removes object from uniquing tables and causes the EOEditingContext 
  151.     // to remove itself as a willChange observer.  This is called automatically 
  152.     // when an object being observed by an EOEditingContext is deallocated.
  153.  
  154. - (NSArray *)registeredObjects;
  155.     // Returns an array containing all of the EOs managed by this editingContext.
  156.  
  157. - (NSArray *)updatedObjects;
  158. - (NSArray *)insertedObjects;
  159. - (NSArray *)deletedObjects;
  160.     // Returns a list of changes made in the object graph managed by the
  161.     // EOEditingContext.
  162.  
  163. - (void)processRecentChanges;
  164.     // When objects are changed (inserted, updated, and deleted), processing of
  165.     // the changes is normally deferred until the end of the current event.
  166.     // At that point, objects are moved to the inserted, updated, and deleted
  167.     // lists, delete propagation is performed, undos are registered,
  168.     // and the EOObjectsChangedInStoreNotification is sent (usually causing the
  169.     // UI to update).  Calling processRecentChanges forces this all to be done
  170.     // synchronously.  The EOEditingContext automatically calls this method on
  171.     // itself before performing certain operations (e.g. saveChanges).
  172.  
  173. - (BOOL)propagatesDeletesAtEndOfEvent;
  174. - (void)setPropagatesDeletesAtEndOfEvent:(BOOL)propagatesDeletesAtEndOfEvent;
  175.     // If propagatesDeletesAtEndOfEvent is YES, any explicit deletion of an EO
  176.     // using [editingContext deleteObject:] or an implicit deletion of an EO
  177.     // by removing it from an owning relationship, will trigger delete propagation
  178.     // at the end of the event in which the deletion occured.  Delete propagation
  179.     // uses the delete rule information available from EOClassDescription to
  180.     // possibly delete other objects related to the deleted ones.
  181.     // If delete propagation fails (an EO refuses to be deleted -- possibly
  182.     // due to a deny rule) all changes made during the event are rolled back
  183.     // and a validation error is processed via editingContext:presentErrorMessage:.
  184.     // If propagatesDeletesAtEndOfEvent is NO, delete propagation is not performed
  185.     // until saveChanges is called.
  186.  
  187. - (BOOL)stopsValidationAfterFirstError;
  188. - (void)setStopsValidationAfterFirstError:(BOOL)yn;
  189.     // Determines whether or not validation (upon save, for instance)
  190.     // stops after the first error is encountered, or continues for all
  191.     // objects.  The latter is useful if the delegate implements
  192.     // editingContext:shouldPresentException: to handle aggregate
  193.     // exceptions.
  194.  
  195. - (BOOL)locksObjectsBeforeFirstModification;
  196. - (void)setLocksObjectsBeforeFirstModification:(BOOL)yn;
  197.     // If locksObjectsBeforeFirstModification is set, the editingContext
  198.     // will automatically call [self lockObject:obj] to lock an object in its
  199.     // external store the first time the object is modified.  This may result in
  200.     // an exception being raised in willChange if the lock cannot be obtained.
  201.     // By default this mode is off.
  202.  
  203. // Snapshotting
  204. - (NSDictionary *)committedSnapshotForObject:(id)object;
  205.     // snapshot for this object before it was first modified.
  206.     // This snapshot is updated to the newest object state after a save.
  207.  
  208. - (NSDictionary *)currentEventSnapshotForObject:(id)object;
  209.     // snapshot for the state of the object at the beginning of the current
  210.     // event.  After the end of the current event, this snapshot is recorded with
  211.     // the undo manager to undo changes to this object and the return value
  212.     // method is updated to hold modified state of the object.
  213.  
  214. - (void)refaultObjects;
  215.     // Refaults all objects that haven't been modified, inserted or deleted.
  216.  
  217. - (void)setInvalidatesObjectsWhenFreed:(BOOL)yn;
  218. - (BOOL)invalidatesObjectsWhenFreed;
  219.     // returns whether the editing context invalidates (clears and booby traps)
  220.     // all of the objects registered with it when the context is deallocated.
  221.     // The default is YES.
  222.     
  223. - (void)addEditor:(id)editor;
  224. - (void)removeEditor:(id)editor;
  225. - (NSArray *)editors;
  226.     // Editors are special-purpose delegate objects that may have uncomitted
  227.     // changes that need to be validated and flushed to objects before
  228.     // the EOEditingContext saves changes.  EODisplayGroups register themselves
  229.     // as editors with the EOEditingContext of their dataSources.
  230.     // See the EOEditors delegate category below for more information.
  231.  
  232. - (void)setMessageHandler:(id)handler;
  233. - (id)messageHandler;
  234.     // The message handler is a special-purpose delegate responsible for
  235.     // presenting errors to the user.  Typically an EODisplayGroup will
  236.     // register itself as the message handler for its EOEditingContext.
  237.     // See EOMessageHandlers delegate category below for more information.
  238.     // These methods set/return the message handler of the EOEditingContext.
  239.  
  240. // EditingContext implementation of EOObjectStore methods.
  241. // Used when an EOEditingContext acts as an ObjectStore for
  242. // another EditingContext.
  243. - (id)faultForGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
  244.     // If a object has already been registered in the given EOEditingContext it
  245.     // is returned.  If not, a newly constructed fault is returned.
  246.     // When a parent EOEditingContext receives this on behalf of a child context, and
  247.     // the globalID identifies a newly inserted object in the parent, the parent
  248.     // registers a copy of its object in the child.  Otherwise, the EditingContext
  249.     // propagates this message to its parentObjectStore.
  250.  
  251. - (NSArray *)arrayFaultWithSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
  252.     // When a parent EOEditingContext receives this on behalf of a child context, and
  253.     // the globalID identifies a newly inserted object in the parent, the parent
  254.     // returns a copy of its object's relationship array translated into the child.
  255.     // Otherwise, the EditingContext propagates this message to its parentObjectStore.
  256.  
  257. - (void)initializeObject:(id)object withGlobalID:(EOGlobalID *)globalID
  258.           editingContext:(EOEditingContext *)context;
  259.     // Build the properties for the object uniqued by globalID.
  260.     // When a parent EOEditingContext receives this on behalf of a child context, and
  261.     // the globalID identifies object instantiated in the parent, the parent returns
  262.     // uses properties extracted from its object and translated into the
  263.     // child's context.  This ensures that a nested context "inherits" modified values
  264.     // from its parent context.
  265.     // If the receiving context does not have the given object, the request is fowarded
  266.     // its parentObjectStore.
  267.  
  268. - (NSArray *)objectsForSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
  269.     // This method is used to fire a to-many fault.
  270.     // When a parent EOEditingContext receives this on behalf of a child context, and
  271.     // the globalID identifies object instantiated in the parent, the parent returns
  272.     // a copy of its relationship array translated into the child's context.
  273.     // This ensures that a nested context "inherits" modified values from its parent context.
  274.     // If the receiving context does not have the given object, or the parents
  275.     // relationship property is still an EOFault, the request is fowarded
  276.     // its parentObjectStore.
  277.  
  278. - (void)refaultObject:object withGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
  279.     // Turn an Enterprise Object back into a fault. This method should be used with caution.
  280.     // Refaulting an object does not remove the object snapshot from the undo stack. Objects
  281.     // that have been inserted or deleted should be not refaulted.
  282.  
  283. - (void)saveChangesInEditingContext:(EOEditingContext *)context;
  284.     // Sent by an EditingContext to its ObjectStore to commit changes.  This method should
  285.     // not be invoked directly.  It is called by a nested EOEditingContext when committing
  286.     // changes to a parent context.  The receiving parent EOEditingContext will copy
  287.     // all changes from the nested context into its own copies of the objects, but will
  288.     // not immediately save those changes to the database.  When the parent itself is
  289.     // sent saveChanges, it will propagate any changes saved from the child, along with
  290.     // any other changes,its parentObjectStore.
  291.     // Raises an exception if an error occurs.
  292.  
  293. - (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)context;
  294.     // The base method to get an array of objects. The EOEditingContext simply forwards
  295.     // this message onto it parentObjectStore.
  296.     // Raises an exception if an error occurs.
  297.  
  298. - (void)lockObjectWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
  299.     // passes lock request to parentObjectStore.
  300.  
  301. - (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
  302.     // passes lock query to parentObjectStore.
  303.  
  304. @end
  305.  
  306. // used with NSRunLoop's performSelector:target:argument:order:modes:
  307. enum {
  308.     EOEditingContextFlushChangesRunLoopOrdering        = 300000
  309. };
  310.  
  311. // Notifications
  312. //     EOObjectsChangedInStoreNotification is broadcast by the editing context whenever
  313. //     objectWillChange observer notifications are processed.  This is usually as the
  314. //     end of the event in which the changes occured.  See EOObjectStore.h for more
  315. //     information on this notification.
  316. //     EODisplayGroups listen for this notification to redisplay their contents.
  317.  
  318. //     EOInvalidatedAllObjectsInStoreNotification is broadcast whenever the
  319. //     editing context is invalidating all its objects. When an EditingContext receives
  320. //     this notification from its parent objectStore it will clear its
  321. //     inserted/updated/deleted lists and reset its undo stack.   See EOObjectStore.h
  322. //     for more information on this notification.
  323. //     EODisplayGroups listen for this notification to refetch their contents.
  324.  
  325. //     EOObjectsChangedInEditingContextNotification is broadcast whenever changes are
  326. //     made in an EditingContext. This notification is similar to
  327. //     EOObjectsChangedInStoreNotification, but this notifications contains
  328. //     objects rather than GlobalID's.
  329. //
  330. //     object = sending EditingContext
  331. //     userInfo = {
  332. //                    updated = (array of changed objects);
  333. //                    deleted = (array of deleted objects);
  334. //                    inserted = (array of inserted objects);
  335. //                    invalidated = (array of invalidated objects);
  336. //     }
  337. //     Invalidated objects are those for which the cached view can should no longer
  338. //     be trusted.  Invalidated objects should be refaulted so that they are refetched
  339. //     when next examined.
  340. //
  341. EOCONTROL_EXTERN NSString *EOObjectsChangedInEditingContextNotification;
  342.  
  343. //     EOEditingContextDidSaveChangesNotification is broadcast after
  344. //     changes are saved to the objectStore used by the editingContext.
  345. //
  346. //     object = sending EditingContext
  347. //     userInfo = nil
  348. //
  349. EOCONTROL_EXTERN NSString *EOEditingContextDidSaveChangesNotification;
  350.  
  351. @interface NSObject (EOEditingContext)
  352. - (EOEditingContext *)editingContext;
  353.     // returns the editingContext in which this object lives or
  354.     // nil if this object has not been registered.
  355. @end
  356.  
  357. //
  358. // Delegation methods
  359. //
  360. @interface NSObject (EOEditingContextDelegation)
  361. - (BOOL)editingContext:(EOEditingContext *)editingContext shouldPresentException:(NSException *)exception;
  362.     // if delegate implements this message and returns NO, the
  363.     // exception is ignored.  Otherwise it is passed to the message
  364.     // handler with editingContext:presentErrorMessage:
  365.  
  366. - (BOOL)editingContextShouldValidateChanges:(EOEditingContext *)editingContext;
  367.     // If the delegate returns NO, the validation is bypassed.
  368.  
  369. - (void)editingContextWillSaveChanges:(EOEditingContext *)editingContext;
  370.     // The delegate could raise to abort the save.
  371.  
  372. - (BOOL)editingContext:(EOEditingContext *)editingContext shouldInvalidateObject:(id)object globalID:(EOGlobalID *)gid;
  373.     // Permits delegate to selectively override which objects are invalidated.
  374.  
  375. - (BOOL)editingContextShouldUndoUserActionsAfterFailure:(EOEditingContext *)context;
  376.     // Permits delegate to turn off undoing of user actions after validation has resulted
  377.     // in an error.
  378.  
  379. - (NSArray *)editingContext:(EOEditingContext *)editingContext willFetchObjectsDescribedByFetchSpecification:(EOFetchSpecification *)fetchSpecification;
  380.     // Called by objectsWithFetchSpecification:editingContext:.  If delegate already
  381.     // has appropriate results cached
  382.  
  383. @end
  384.  
  385. //
  386. // EOEditors informal protocol
  387. //
  388. @interface NSObject (EOEditors)
  389. - (BOOL)editorHasChangesForEditingContext:(EOEditingContext *)editingContext;
  390.     // Called by the EOEditingContext to determine if the editor is "dirty"
  391.  
  392. - (void)editingContextWillSaveChanges:(EOEditingContext *)editingContext;
  393.     // Passed first to the editors, then to the delegate.  Editors
  394.     // should validate any unprocessed fields and save changes to the objects.
  395.     // If any editors raise, the save is aborted.
  396. @end
  397.  
  398. //
  399. // EOMessageHandler informal protocol
  400. //
  401. @interface NSObject (EOMessageHandlers)
  402. - (void)editingContext:(EOEditingContext *)editingContext presentErrorMessage:(NSString *)message;
  403.     // The message handler should present error to user
  404.     // (in an alert panel, for instance)
  405. @end
  406.  
  407.  
  408. @interface EOEditingContext (EORendezvous)
  409. + (void)setSubstitutionEditingContext:(EOEditingContext *)ec;
  410. + (EOEditingContext *)substitutionEditingContext;
  411.     // An editing context that will be swapped in in place of any
  412.     // context read from a nib file.  If substitutionEditingContext
  413.     // is set to nil, the EditingContext loaded from the nib is
  414.     // used by default.
  415.  
  416. + (void)setDefaultParentObjectStore:(EOObjectStore *)store;
  417. + (EOObjectStore *)defaultParentObjectStore;
  418.     // The default parentObjectStore for editing contexts read from
  419.     // a nib.  By default this is the
  420.     // [EOObjectStoreCoordinator defaultCoordinator].
  421.     // This may be set to a different coordinator, or another EditingContext
  422.     // (for a nested editing context configuration) prior to loading a nib.
  423. @end
  424.  
  425. @interface EOEditingContext (EOStateArchiving)
  426. // These are methods EOs invoke to implement encodeWithCoder: and initWithCoder:.  
  427. // These are primarily useful for minimal freeze-drying of state relative to the 
  428. // parent state.  Unmodified objects are archived with just their globalIDs (since 
  429. // their state can be fetched from the object store).  Modified or inserted objects 
  430. // archive all of their classProperties.
  431. //
  432. + (void)setUsesContextRelativeEncoding:(BOOL)yn;
  433. + (BOOL)usesContextRelativeEncoding;
  434. + (void)encodeObject:(id)object withCoder:(NSCoder *)coder;
  435. + (id)initObject:(id)object withCoder:(NSCoder *)coder;
  436. @end
  437.  
  438. // Target action methods for InterfaceBuilder
  439. //
  440. @interface EOEditingContext (EOTargetAction)
  441. - (void)saveChanges:(id)sender;
  442. - (void)refault:(id)sender;
  443. - (void)revert:(id)sender;
  444. - (void)refetch:(id)sender;
  445.  
  446. // Forward messages on to the undoManager of this editing context
  447. - (void)undo:(id)sender;
  448. - (void)redo:(id)sender;
  449. @end
  450.  
  451.