2002-11-15 22:57:05 +00:00
|
|
|
|
/**
|
|
|
|
|
EOEditingContext.m <title>EOEditingContext Class</title>
|
|
|
|
|
|
|
|
|
|
Copyright (C) 2000-2002 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Date: June 2000
|
|
|
|
|
|
|
|
|
|
$Revision$
|
|
|
|
|
$Date$
|
|
|
|
|
|
|
|
|
|
<abstract></abstract>
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Database Library.
|
|
|
|
|
|
|
|
|
|
<license>
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
|
If not, write to the Free Software Foundation,
|
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
</license>
|
|
|
|
|
**/
|
|
|
|
|
|
2002-12-31 16:25:21 +00:00
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
RCS_ID("$Id$")
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
//TODO EOMultiReaderLocks
|
2003-03-31 00:24:15 +00:00
|
|
|
|
#include <Foundation/Foundation.h>
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
2003-07-11 19:04:05 +00:00
|
|
|
|
#ifndef GNUSTEP
|
2003-08-25 20:01:59 +00:00
|
|
|
|
#include <GNUstepBase/GNUstep.h>
|
2003-07-11 19:04:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2003-03-31 00:24:15 +00:00
|
|
|
|
#include <EOControl/EOEditingContext.h>
|
|
|
|
|
#include <EOControl/EOObjectStoreCoordinator.h>
|
|
|
|
|
#include <EOControl/EOGlobalID.h>
|
|
|
|
|
#include <EOControl/EOClassDescription.h>
|
|
|
|
|
#include <EOControl/EOKeyValueCoding.h>
|
|
|
|
|
#include <EOControl/EOFault.h>
|
|
|
|
|
#include <EOControl/EONull.h>
|
|
|
|
|
#include <EOControl/EONSAddOns.h>
|
|
|
|
|
#include <EOControl/EODebug.h>
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
2003-02-04 15:17:07 +00:00
|
|
|
|
|
|
|
|
|
@class EOEntityClassDescription;
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
2003-05-02 17:00:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* These EOAccess specific declarations are intended to
|
|
|
|
|
* supress long compiler warnings. Non the less we should
|
|
|
|
|
* avoid dependancies on EOAccess.
|
|
|
|
|
*/
|
|
|
|
|
@interface NSObject(EOEntityWarningSupression)
|
|
|
|
|
- (NSString *) name;
|
|
|
|
|
- (EOGlobalID *) globalIDForRow:(NSDictionary *)row;
|
|
|
|
|
@end
|
|
|
|
|
@interface EOEntityClassDescription : EOClassDescription
|
|
|
|
|
- (NSObject *) entity;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface EOEditingContext(EOEditingContextPrivate)
|
|
|
|
|
- (void) _observeUndoManagerNotifications;
|
|
|
|
|
@end
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
@implementation EOEditingContext
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static EOObjectStore *defaultParentStore = nil;
|
|
|
|
|
|
|
|
|
|
//Notifications
|
|
|
|
|
NSString *EOObjectsChangedInEditingContextNotification = @"EOObjectsChangedInEditingContextNotification";
|
|
|
|
|
NSString *EOEditingContextDidSaveChangesNotification = @"EOEditingContextDidSaveChangesNotification";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ (void)initialize
|
|
|
|
|
{
|
2003-03-31 00:24:15 +00:00
|
|
|
|
if (self == [EOEditingContext class] && defaultParentStore == nil)
|
|
|
|
|
{
|
|
|
|
|
defaultParentStore = [EOObjectStoreCoordinator defaultCoordinator];
|
|
|
|
|
}
|
2002-11-15 22:57:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void)setInstancesRetainRegisteredObjects: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL)instancesRetainRegisteredObjects
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _eoNowMultiThreaded: (NSNotification *)notification
|
|
|
|
|
{
|
|
|
|
|
//TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithParentObjectStore: (EOObjectStore *)parentObjectStore
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
if ((self = [super init]))
|
|
|
|
|
{
|
|
|
|
|
_flags.propagatesDeletesAtEndOfEvent = YES; //Default behavior
|
|
|
|
|
ASSIGN(_objectStore, [EOEditingContext defaultParentObjectStore]); //parentObjectStore instead of defaultParentObjectStore ?
|
|
|
|
|
|
|
|
|
|
_unprocessedChanges = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
_unprocessedDeletes = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
_unprocessedInserts = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
_insertedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
_deletedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
_changedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
|
|
|
|
|
_objectsById = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,//NSObjectMapKeyCallBacks, retained by _objectsByGID
|
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
|
32);
|
|
|
|
|
_objectsByGID = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
|
32);
|
|
|
|
|
|
|
|
|
|
_snapshotsByGID = [[NSMutableDictionary alloc] initWithCapacity:16];
|
|
|
|
|
_eventSnapshotsByGID = [[NSMutableDictionary alloc] initWithCapacity:16];
|
|
|
|
|
|
|
|
|
|
_editors = [NSMutableArray new];
|
|
|
|
|
|
|
|
|
|
_lock = [NSRecursiveLock new];
|
|
|
|
|
|
2003-03-31 00:24:15 +00:00
|
|
|
|
//TODO-NOW _undoManager = [NSUndoManager new];
|
2002-11-15 22:57:05 +00:00
|
|
|
|
[_undoManager beginUndoGrouping]; //??
|
|
|
|
|
|
|
|
|
|
[self _observeUndoManagerNotifications];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
[self setStopsValidationAfterFirstError:YES];
|
|
|
|
|
[self setPropagatesDeletesAtEndOfEvent:YES];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_objectsChangedInStore:)
|
|
|
|
|
name: EOObjectsChangedInStoreNotification
|
|
|
|
|
object: _objectStore];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_invalidatedAllObjectsInStore:)
|
|
|
|
|
name: EOInvalidatedAllObjectsInStoreNotification
|
|
|
|
|
object: _objectStore];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_globalIDChanged:)
|
|
|
|
|
name: EOGlobalIDChangedNotification
|
|
|
|
|
object: nil];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_eoNowMultiThreaded:)
|
|
|
|
|
name: NSWillBecomeMultiThreadedNotification
|
|
|
|
|
object: nil];
|
|
|
|
|
/*
|
|
|
|
|
[self setStopsValidationAfterFirstError:NO];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver:self
|
|
|
|
|
selector:@selector(_objectsChangedInSubStore:)
|
|
|
|
|
name:EOObjectsChangedInStoreNotification
|
|
|
|
|
object:nil];
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
return [self initWithParentObjectStore:
|
|
|
|
|
[EOEditingContext defaultParentObjectStore]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
|
{
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
|
|
|
|
|
|
DESTROY(_objectStore);
|
|
|
|
|
DESTROY(_undoManager);
|
|
|
|
|
|
|
|
|
|
NSFreeHashTable(_unprocessedChanges);
|
|
|
|
|
NSFreeHashTable(_unprocessedDeletes);
|
|
|
|
|
NSFreeHashTable(_unprocessedInserts);
|
|
|
|
|
NSFreeHashTable(_insertedObjects);
|
|
|
|
|
NSFreeHashTable(_deletedObjects);
|
|
|
|
|
NSFreeHashTable(_changedObjects);
|
|
|
|
|
|
|
|
|
|
NSFreeMapTable(_objectsById);
|
|
|
|
|
NSFreeMapTable(_objectsByGID);
|
|
|
|
|
|
|
|
|
|
DESTROY(_snapshotsByGID);
|
|
|
|
|
DESTROY(_eventSnapshotsByGID);
|
|
|
|
|
|
|
|
|
|
DESTROY(_editors);
|
|
|
|
|
DESTROY(_lock);
|
|
|
|
|
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) parentPath
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
return [self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)_observeUndoManagerNotifications
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_undoManagerCheckpoint:)
|
|
|
|
|
name: NSUndoManagerCheckpointNotification
|
|
|
|
|
object: _undoManager];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _processObjectStoreChanges: (NSNotification *)notification
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//"Receive EOObjectsChangedInStoreNotification notification"
|
|
|
|
|
//oldname:_handleObjectsChangedInStoreNotification:
|
|
|
|
|
- (void)_objectsChangedInStore: (NSNotification *)notification
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *arrayEnum;
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
NSArray *array = nil;
|
|
|
|
|
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
// userInfo = {deleted = (); inserted = (); updated = ([GID: CustomerCredit, (1)]); }}
|
|
|
|
|
|
|
|
|
|
if ([notification object] != self)
|
|
|
|
|
{
|
|
|
|
|
// Notification is posted from EODatabase
|
|
|
|
|
array = [[notification userInfo] objectForKey: EOInsertedKey];
|
|
|
|
|
|
|
|
|
|
if (array)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array = [[notification userInfo] objectForKey: EODeletedKey];
|
|
|
|
|
if (array)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array = [[notification userInfo] objectForKey: EOUpdatedKey];
|
|
|
|
|
if (array)
|
|
|
|
|
{
|
|
|
|
|
if (_flags.processingChanges == NO)
|
|
|
|
|
{
|
|
|
|
|
arrayEnum = [array objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((gid = [arrayEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
[self refaultObject: [self objectForGlobalID:gid]
|
|
|
|
|
withGlobalID: gid
|
|
|
|
|
editingContext: self];
|
|
|
|
|
|
|
|
|
|
// TODO: verify modified objects
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array = [[notification userInfo] objectForKey: EOInvalidatedKey];
|
|
|
|
|
if (array)
|
|
|
|
|
{
|
|
|
|
|
// these none-EOTemporary-GID EOObjects are retransformed into EOFaults
|
|
|
|
|
// all snapshots accesses to their gid's are invalid and must remove
|
|
|
|
|
|
|
|
|
|
arrayEnum = [array objectEnumerator];
|
|
|
|
|
while ((gid = [arrayEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if ([gid isTemporary] == NO)
|
|
|
|
|
{
|
|
|
|
|
[_snapshotsByGID removeObjectForKey: gid];
|
|
|
|
|
[_eventSnapshotsByGID removeObjectForKey: gid];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//"Receive EOGlobalIDChangedNotification notification"
|
|
|
|
|
- (void)_globalIDChanged: (NSNotification *)notification
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *snapshot = nil;
|
|
|
|
|
NSDictionary *userInfo;
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
EOGlobalID *tempGID;
|
|
|
|
|
EOGlobalID *gid = nil;
|
|
|
|
|
id object = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
userInfo = [notification userInfo];
|
|
|
|
|
enumerator = [userInfo keyEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((tempGID = [enumerator nextObject]))
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"tempGID=%@", tempGID);
|
|
|
|
|
|
|
|
|
|
gid = [userInfo objectForKey: tempGID];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
|
|
|
|
|
if (_objectsByGID)
|
|
|
|
|
{
|
|
|
|
|
object = NSMapGet(_objectsByGID, tempGID);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
|
|
|
|
|
RETAIN(object);
|
|
|
|
|
NSAssert(_objectsById, @"no _objectsById");
|
|
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
NSMapInsert(_objectsById, object, gid);
|
|
|
|
|
NSMapRemove(_objectsByGID, tempGID);
|
|
|
|
|
NSMapInsert(_objectsByGID, gid, object);
|
|
|
|
|
AUTORELEASE(object);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!object)
|
|
|
|
|
{
|
|
|
|
|
// object is from other editingcontext
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContextValues",
|
|
|
|
|
@"nothing done , object with gid '%@' is from other ed",
|
|
|
|
|
tempGID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if (object)
|
|
|
|
|
snapshot = [_snapshotsByGID objectForKey: tempGID];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"_snapshotsByGID snapshot=%@", snapshot);
|
|
|
|
|
|
|
|
|
|
if (snapshot)
|
|
|
|
|
{
|
|
|
|
|
RETAIN(snapshot);
|
|
|
|
|
|
|
|
|
|
[_snapshotsByGID removeObjectForKey: tempGID];
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"After Remove");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
[_snapshotsByGID setObject: snapshot
|
|
|
|
|
forKey: gid];
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"After SetObject");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
AUTORELEASE(snapshot);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// set snapshot with last committed values
|
|
|
|
|
//EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"adding new object = %@", [self objectForGlobalID:gid]);
|
|
|
|
|
//EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"object class = %@", NSStringFromClass([object class]));
|
|
|
|
|
//EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"with snapshot = %@", [[self objectForGlobalID:gid] snapshot]);
|
|
|
|
|
|
|
|
|
|
// ?? [_snapshots setObject:[[self objectForGlobalID:gid] snapshot] forKey:gid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snapshot = [_eventSnapshotsByGID objectForKey: tempGID];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"_eventSnapshotsByGID snapshot=%@", snapshot);
|
|
|
|
|
|
|
|
|
|
if (snapshot)
|
|
|
|
|
{
|
|
|
|
|
RETAIN(snapshot);
|
|
|
|
|
[_eventSnapshotsByGID removeObjectForKey: tempGID];
|
|
|
|
|
[_eventSnapshotsByGID setObject: snapshot
|
|
|
|
|
forKey: gid];
|
|
|
|
|
|
|
|
|
|
AUTORELEASE(snapshot);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _processNotificationQueue
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _sendOrEnqueueNotification: (id)param0
|
|
|
|
|
selector: (SEL)param1
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//"Invalidate All Objects"
|
|
|
|
|
- (void) invalidateAllObjects
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
|
|
|
|
|
[super invalidateAllObjects]; //??
|
|
|
|
|
[self notImplemented: _cmd]; //TODO-NOW
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//"Receive ???? notification"
|
|
|
|
|
- (void) _invalidatedAllObjectsInStore: (NSNotification*)notification
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _forgetObjectWithGlobalID:(EOGlobalID*)gid
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented:_cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _invalidateObject: (id)object
|
|
|
|
|
withGlobalID: (EOGlobalID*)gid
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _invalidateObjectWithGlobalID: (EOGlobalID*)gid
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) invalidateObjectsWithGlobalIDs: (NSArray*)gids
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _resetAllChanges: (NSNotification*)notification //??
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _resetAllChanges
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _enqueueEndOfEventNotification
|
|
|
|
|
{
|
|
|
|
|
[_undoManager groupsByEvent];
|
|
|
|
|
[_undoManager registerUndoWithTarget: self
|
|
|
|
|
selector: @selector(noop:)
|
|
|
|
|
object: nil];
|
|
|
|
|
|
|
|
|
|
_flags.registeredForCallback = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch
|
|
|
|
|
{
|
|
|
|
|
NSArray *objects;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
objects = [self objectsWithFetchSpecification: fetch
|
|
|
|
|
editingContext: self];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return objects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)insertObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
gid = [self globalIDForObject: object];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
|
|
|
|
|
//GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice
|
|
|
|
|
|
|
|
|
|
if (_insertedObjects && NSHashGet(_insertedObjects, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext",@"Already inserted object [_insertedObjects] %p=%@",object,object);
|
|
|
|
|
}
|
|
|
|
|
else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext",@"Already inserted object [_unprocessedInserts] %p=%@",object,object);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!gid)
|
|
|
|
|
{
|
|
|
|
|
gid = [EOTemporaryGlobalID temporaryGlobalID];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"InsertObjectWithGlobalID object: %p=%@",
|
|
|
|
|
object, object);
|
|
|
|
|
|
|
|
|
|
[self insertObject: object
|
|
|
|
|
withGlobalID: gid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)insertObject: (id)object
|
|
|
|
|
withGlobalID: (EOGlobalID *)gid
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
//GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice
|
|
|
|
|
|
|
|
|
|
if (_insertedObjects && NSHashGet(_insertedObjects, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_insertedObjects] %p=%@", object, object);
|
|
|
|
|
}
|
|
|
|
|
else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_unprocessedInserts] %p=%@", object, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self _insertObject: object
|
|
|
|
|
withGlobalID: gid];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Awake object: %p=%@",
|
|
|
|
|
object, object);
|
|
|
|
|
|
|
|
|
|
[object awakeFromInsertionInEditingContext: self];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_insertObject: (id)object
|
|
|
|
|
withGlobalID: (EOGlobalID *)gid
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gidBis = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Object %p=%@", object, object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
NSAssert(object, @"No Object");
|
|
|
|
|
|
|
|
|
|
//GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice
|
|
|
|
|
|
|
|
|
|
if (_insertedObjects && NSHashGet(_insertedObjects, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_insertedObjects] %p=%@", object, object);
|
|
|
|
|
}
|
|
|
|
|
else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object))
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_unprocessedInserts] %p=%@", object, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([gid isTemporary])
|
|
|
|
|
{
|
|
|
|
|
[self _registerClearStateWithUndoManager];
|
|
|
|
|
[_undoManager registerUndoWithTarget: self
|
|
|
|
|
selector: @selector(deleteObject:)
|
|
|
|
|
object: object];
|
|
|
|
|
|
|
|
|
|
gidBis = [self globalIDForObject: object];
|
|
|
|
|
|
|
|
|
|
if (!gidBis)
|
|
|
|
|
{
|
|
|
|
|
NSAssert(gid, @"No gid");
|
|
|
|
|
|
|
|
|
|
[self recordObject: object
|
|
|
|
|
globalID: gid];
|
|
|
|
|
|
|
|
|
|
NSHashInsert(_unprocessedInserts, object);
|
|
|
|
|
[self _enqueueEndOfEventNotification];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _processEndOfEventNotification: (NSNotification*)notification
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
if ([self tryLock])
|
|
|
|
|
{
|
|
|
|
|
[self processRecentChanges];
|
|
|
|
|
[self unlock];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) noop: (id)param0
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//"Receive NSUndoManagerCheckpointNotification Notification
|
|
|
|
|
- (void) _undoManagerCheckpoint: (NSNotification*)notification
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
|
|
|
|
|
[self _processEndOfEventNotification: notification]; //OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) _processRecentChanges
|
|
|
|
|
{
|
|
|
|
|
//Near OK for insert and update
|
|
|
|
|
BOOL result = YES;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
if (!_flags.processingChanges)
|
|
|
|
|
{
|
|
|
|
|
NSArray *unprocessedInsertsArray = nil;
|
|
|
|
|
NSArray *unprocessedInsertsGlobalIDs = nil;
|
|
|
|
|
NSArray *unprocessedDeletesArray = nil;
|
|
|
|
|
NSArray *unprocessedDeletesGlobalIDs = nil;
|
|
|
|
|
NSArray *unprocessedChangesArray = nil;
|
|
|
|
|
NSArray *unprocessedChangesGlobalIDs = nil;
|
|
|
|
|
NSMutableDictionary *objectsArray = [NSMutableDictionary dictionary];
|
|
|
|
|
NSMutableDictionary *objectGIDsArray = [NSMutableDictionary dictionary];
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
_flags.processingChanges = YES;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[self _registerClearStateWithUndoManager];
|
|
|
|
|
|
|
|
|
|
//_undoManager isUndoing //ret NO //TODO
|
|
|
|
|
//_undoManager isRedoing //ret NO //TODO
|
|
|
|
|
[_undoManager beginUndoGrouping];
|
|
|
|
|
|
|
|
|
|
/*in undomanager beginUndoGrouping
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerCheckpointNotification"
|
|
|
|
|
object:_undoManager]; //call _undoManagerCheckpoint:
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerDidOpenUndoGroupNotification"
|
|
|
|
|
object:_undoManager];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
[self _processDeletedObjects];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[_undoManager endUndoGrouping];
|
|
|
|
|
|
|
|
|
|
/*in undomanager endUndoGrouping
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerCheckpointNotification"
|
|
|
|
|
object:_undoManager] //call _undoManagerCheckpoint:
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerWillCloseUndoGroupNotification"
|
|
|
|
|
object:_undoManager];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
//on inserted objects
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"process _unprocessedInserts");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
unprocessedInsertsArray = NSAllHashTableObjects(_unprocessedInserts);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedInsertsArray=%@",
|
|
|
|
|
unprocessedInsertsArray);
|
|
|
|
|
|
|
|
|
|
[objectsArray setObject: unprocessedInsertsArray
|
|
|
|
|
forKey: @"inserted"];
|
|
|
|
|
|
|
|
|
|
unprocessedInsertsGlobalIDs
|
|
|
|
|
= [self resultsOfPerformingSelector: @selector(globalIDForObject:)
|
|
|
|
|
withEachObjectInArray: unprocessedInsertsArray];
|
|
|
|
|
|
|
|
|
|
[objectGIDsArray setObject: unprocessedInsertsGlobalIDs
|
|
|
|
|
forKey: @"inserted"];
|
|
|
|
|
|
|
|
|
|
count = [unprocessedInsertsArray count];
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
NSHashInsertIfAbsent(_insertedObjects,
|
|
|
|
|
[unprocessedInsertsArray objectAtIndex: i]);
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_unprocessedInserts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//on deleted or updated
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"process _unprocessedDeletes");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
unprocessedDeletesArray = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedDeletesArray=%@",
|
|
|
|
|
unprocessedDeletesArray);
|
|
|
|
|
|
|
|
|
|
[objectsArray setObject: unprocessedDeletesArray
|
|
|
|
|
forKey: @"deleted"];
|
|
|
|
|
unprocessedDeletesGlobalIDs = [self resultsOfPerformingSelector:
|
|
|
|
|
@selector(globalIDForObject:)
|
|
|
|
|
withEachObjectInArray:
|
|
|
|
|
unprocessedDeletesArray];
|
|
|
|
|
|
|
|
|
|
[objectGIDsArray setObject: unprocessedDeletesGlobalIDs
|
|
|
|
|
forKey: @"deleted"];
|
|
|
|
|
|
|
|
|
|
count = [unprocessedDeletesArray count];
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
NSHashInsertIfAbsent(_deletedObjects,
|
|
|
|
|
[unprocessedDeletesArray objectAtIndex: i]);
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_unprocessedDeletes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Changes
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"process _unprocessedChanges");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
unprocessedChangesArray = NSAllHashTableObjects(_unprocessedChanges);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedChangesArray=%@",
|
|
|
|
|
unprocessedChangesArray);
|
|
|
|
|
|
|
|
|
|
[objectsArray setObject:unprocessedChangesArray
|
|
|
|
|
forKey:@"updated"];
|
|
|
|
|
|
|
|
|
|
unprocessedChangesGlobalIDs = [self resultsOfPerformingSelector:
|
|
|
|
|
@selector(globalIDForObject:)
|
|
|
|
|
withEachObjectInArray:
|
|
|
|
|
unprocessedChangesArray];
|
|
|
|
|
|
|
|
|
|
[objectGIDsArray setObject: unprocessedChangesGlobalIDs
|
|
|
|
|
forKey: @"updated"];
|
|
|
|
|
|
|
|
|
|
count = [unprocessedChangesArray count];
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
id object = [unprocessedChangesArray objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object);
|
|
|
|
|
|
|
|
|
|
if (!NSHashGet(_insertedObjects, object)) //Don't update inserted objects ??
|
|
|
|
|
NSHashInsertIfAbsent(_changedObjects, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_unprocessedChanges);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[EOObserverCenter notifyObserversObjectWillChange: nil];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName: @"EOObjectsChangedInStoreNotification"
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: objectGIDsArray];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName: @"EOObjectsChangedInEditingContextNotification"
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: objectsArray];
|
|
|
|
|
|
|
|
|
|
count = [unprocessedChangesArray count];
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
id object = [unprocessedChangesArray objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object);
|
|
|
|
|
[self registerUndoForModifiedObject: object];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
_flags.processingChanges = NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
/*
|
|
|
|
|
(count=0)
|
|
|
|
|
NSMutableDictionary *userInfo;
|
|
|
|
|
NSMutableArray *changedObjects, *invalidatedObjects;
|
|
|
|
|
NSMutableArray *objectsToRemove, *objectsToKeep;
|
|
|
|
|
NSEnumerator *objEnum;
|
|
|
|
|
NSException *exp;
|
|
|
|
|
NSArray *deletedObjects;
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
EONull *null = [EONull null];
|
|
|
|
|
BOOL propagatesDeletes = YES, validateChanges = YES;
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes");
|
|
|
|
|
|
|
|
|
|
objectsToKeep = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
objectsToRemove = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process2");
|
|
|
|
|
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *snapshot, *oldSnapshot, *changes;
|
|
|
|
|
NSArray *toRelArray;
|
|
|
|
|
NSEnumerator *toRelEnum;
|
|
|
|
|
NSString *key;
|
|
|
|
|
|
|
|
|
|
gid = [self globalIDForObject:object];
|
|
|
|
|
oldSnapshot = [_eventSnapshotsByGID objectForKey:gid];
|
|
|
|
|
snapshot = [object snapshot];
|
|
|
|
|
changes = [object changesFromSnapshot:oldSnapshot];
|
|
|
|
|
|
|
|
|
|
toRelArray = [object toOneRelationshipKeys];
|
|
|
|
|
toRelEnum = [toRelArray objectEnumerator];
|
|
|
|
|
while((key = [toRelEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
id val = [changes objectForKey:key];
|
|
|
|
|
|
|
|
|
|
if(val == null)
|
|
|
|
|
val = nil;
|
|
|
|
|
|
|
|
|
|
if(val &&
|
|
|
|
|
[object ownsDestinationObjectsForRelationshipKey:key] == YES)
|
|
|
|
|
{
|
|
|
|
|
if(val != null)
|
|
|
|
|
[objectsToKeep addObject:val];
|
|
|
|
|
|
|
|
|
|
val = [oldSnapshot objectForKey:key];
|
|
|
|
|
if(val != null)
|
|
|
|
|
[objectsToRemove addObject:val];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toRelArray = [object toManyRelationshipKeys];
|
|
|
|
|
toRelEnum = [toRelArray objectEnumerator];
|
|
|
|
|
while((key = [toRelEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
NSArray *val = [changes objectForKey:key];
|
|
|
|
|
|
|
|
|
|
if(val == null)
|
|
|
|
|
val = nil;
|
|
|
|
|
|
|
|
|
|
if(val &&
|
|
|
|
|
[object ownsDestinationObjectsForRelationshipKey:key] == YES)
|
|
|
|
|
{
|
|
|
|
|
[objectsToKeep addObjectsFromArray:[val objectAtIndex:0]];
|
|
|
|
|
[objectsToRemove addObjectsFromArray:[val objectAtIndex:0]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[_eventSnapshotsByGID setObject:snapshot
|
|
|
|
|
forKey:gid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[objectsToRemove removeObjectsInArray:objectsToKeep];
|
|
|
|
|
objEnum = [objectsToRemove objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
NSHashInsert(_unprocessedDeletes, object);
|
|
|
|
|
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
objEnum = [deletedObjects objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if(validateChanges)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//in
|
|
|
|
|
validateTable:(NSHashTable*)table
|
|
|
|
|
withSelector:(SEL)sel
|
|
|
|
|
exceptionArray:(id*)param2
|
|
|
|
|
continueAfterFailure:
|
|
|
|
|
exp = [object validateForDelete];
|
|
|
|
|
|
|
|
|
|
if(exp) // TODO
|
|
|
|
|
{
|
|
|
|
|
if(_flags.stopsValidation == NO)
|
|
|
|
|
{
|
|
|
|
|
if(_delegate == nil ||
|
|
|
|
|
_delegateRespondsTo.shouldPresentException == NO ||
|
|
|
|
|
(_delegateRespondsTo.shouldPresentException &&
|
|
|
|
|
|
|
|
|
|
[_delegate editingContext:self
|
|
|
|
|
shouldPresentException:exp] == YES))
|
|
|
|
|
[_messageHandler editingContext:self
|
|
|
|
|
presentErrorMessage:[exp reason]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[exp raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//fin in...
|
|
|
|
|
NSHashInsert(_deletedObjects, object);
|
|
|
|
|
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertDelete:)
|
|
|
|
|
object:object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
//propagatesDeletesUsingTable:(NSHashTable*)deleteTable
|
|
|
|
|
if(_flags.processingChanges == YES &&
|
|
|
|
|
_delegateRespondsTo.shouldValidateChanges)
|
|
|
|
|
validateChanges = [_delegate editingContextShouldValidateChanges:self];
|
|
|
|
|
|
|
|
|
|
if(_flags.processingChanges == NO && [self propagatesDeletesAtEndOfEvent] == NO)
|
|
|
|
|
propagatesDeletes = NO;
|
|
|
|
|
|
|
|
|
|
if(propagatesDeletes == YES)
|
|
|
|
|
{
|
|
|
|
|
if([self propagatesDeletesAtEndOfEvent] == YES)
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_deletedObjects) objectEnumerator];
|
|
|
|
|
else
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedDeletes)
|
|
|
|
|
objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
[object propagatesDeleteWithEditingContext:self];
|
|
|
|
|
|
|
|
|
|
if([self propagatesDeletesAtEndOfEvent] == YES)
|
|
|
|
|
{
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedDeletes)
|
|
|
|
|
objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
NSHashInsert(_deletedObjects, object);
|
|
|
|
|
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_deletedObjects);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
|
|
|
|
|
objEnum = [deletedObjects objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if(validateChanges)
|
|
|
|
|
{
|
|
|
|
|
exp = [object validateForDelete];
|
|
|
|
|
|
|
|
|
|
if(exp) // TODO
|
|
|
|
|
{
|
|
|
|
|
if(_flags.stopsValidation == NO)
|
|
|
|
|
{
|
|
|
|
|
if(_delegate == nil ||
|
|
|
|
|
_delegateRespondsTo.shouldPresentException == NO ||
|
|
|
|
|
(_delegateRespondsTo.shouldPresentException &&
|
|
|
|
|
|
|
|
|
|
[_delegate editingContext:self
|
|
|
|
|
shouldPresentException:exp] == YES))
|
|
|
|
|
[_messageHandler editingContext:self
|
|
|
|
|
presentErrorMessage:[exp reason]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[exp raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(propagatesDeletes == NO || [self propagatesDeletesAtEndOfEvent] == NO)
|
|
|
|
|
NSHashInsert(_deletedObjects, object);
|
|
|
|
|
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertDelete:)
|
|
|
|
|
object:object];
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: prop delete");
|
|
|
|
|
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if(validateChanges)
|
|
|
|
|
{
|
|
|
|
|
exp = [object validateForUpdate];
|
|
|
|
|
|
|
|
|
|
if(exp)
|
|
|
|
|
{
|
|
|
|
|
if(_flags.stopsValidation == NO)
|
|
|
|
|
{
|
|
|
|
|
if(_delegate == nil ||
|
|
|
|
|
_delegateRespondsTo.shouldPresentException == NO ||
|
|
|
|
|
(_delegateRespondsTo.shouldPresentException &&
|
|
|
|
|
|
|
|
|
|
[_delegate editingContext:self
|
|
|
|
|
shouldPresentException:exp] == YES))
|
|
|
|
|
[_messageHandler editingContext:self
|
|
|
|
|
presentErrorMessage:[exp reason]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[exp raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed");
|
|
|
|
|
NSHashInsert(_changedObjects, object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed2");
|
|
|
|
|
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertChanged:) // TODO si pianta
|
|
|
|
|
object:object];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed: undo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: validated changes");
|
|
|
|
|
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedInserts) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if(validateChanges)
|
|
|
|
|
{
|
|
|
|
|
exp = [object validateForInsert];
|
|
|
|
|
|
|
|
|
|
if(exp)
|
|
|
|
|
{
|
|
|
|
|
if(_flags.stopsValidation == NO)
|
|
|
|
|
{
|
|
|
|
|
if(_delegate == nil ||
|
|
|
|
|
_delegateRespondsTo.shouldPresentException == NO ||
|
|
|
|
|
(_delegateRespondsTo.shouldPresentException &&
|
|
|
|
|
|
|
|
|
|
[_delegate editingContext:self
|
|
|
|
|
shouldPresentException:exp] == YES))
|
|
|
|
|
[_messageHandler editingContext:self
|
|
|
|
|
presentErrorMessage:[exp reason]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[exp raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSHashInsert(_insertedObjects, object);
|
|
|
|
|
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertInsert:)
|
|
|
|
|
object:object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: validated inserts");
|
|
|
|
|
|
|
|
|
|
[_undoManager endUndoGrouping];
|
|
|
|
|
[_undoManager beginUndoGrouping];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: end undo");
|
|
|
|
|
|
|
|
|
|
userInfo = [NSMutableDictionary dictionaryWithCapacity:3];
|
|
|
|
|
|
|
|
|
|
changedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedDeletes) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
[changedObjects addObject:[self globalIDForObject:object]];
|
|
|
|
|
|
|
|
|
|
[userInfo setObject:changedObjects
|
|
|
|
|
forKey:EODeletedKey];
|
|
|
|
|
|
|
|
|
|
changedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedInserts) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
[changedObjects addObject:[self globalIDForObject:object]];
|
|
|
|
|
|
|
|
|
|
[userInfo setObject:changedObjects
|
|
|
|
|
forKey:EOInsertedKey];
|
|
|
|
|
|
|
|
|
|
invalidatedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
changedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_changedObjects) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if([EOFault isFault:object] == YES)
|
|
|
|
|
[invalidatedObjects addObject:[self globalIDForObject:object]];
|
|
|
|
|
else
|
|
|
|
|
[changedObjects addObject:[self globalIDForObject:object]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[userInfo setObject:changedObjects
|
|
|
|
|
forKey:EOUpdatedKey];
|
|
|
|
|
[userInfo setObject:invalidatedObjects
|
|
|
|
|
forKey:EOInvalidatedKey];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName:EOObjectsChangedInStoreNotification
|
|
|
|
|
object:self
|
|
|
|
|
userInfo:userInfo];
|
|
|
|
|
|
|
|
|
|
userInfo = [NSMutableDictionary dictionaryWithCapacity:3];
|
|
|
|
|
|
|
|
|
|
[userInfo setObject:NSAllHashTableObjects(_unprocessedDeletes)
|
|
|
|
|
forKey:EODeletedKey];
|
|
|
|
|
[userInfo setObject:NSAllHashTableObjects(_unprocessedInserts)
|
|
|
|
|
forKey:EOInsertedKey];
|
|
|
|
|
|
|
|
|
|
invalidatedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
changedObjects = [NSMutableArray arrayWithCapacity:8];
|
|
|
|
|
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if([EOFault isFault:object] == YES)
|
|
|
|
|
[invalidatedObjects addObject:object];
|
|
|
|
|
else
|
|
|
|
|
[changedObjects addObject:object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[userInfo setObject:changedObjects
|
|
|
|
|
forKey:EOUpdatedKey];
|
|
|
|
|
[userInfo setObject:invalidatedObjects
|
|
|
|
|
forKey:EOInvalidatedKey];
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName:EOObjectsChangedInEditingContextNotification
|
|
|
|
|
object:self
|
|
|
|
|
userInfo:userInfo];
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_unprocessedChanges);
|
|
|
|
|
NSResetHashTable(_unprocessedDeletes);
|
|
|
|
|
NSResetHashTable(_unprocessedInserts);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"** process finished");
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes END");
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _processDeletedObjects
|
|
|
|
|
{
|
|
|
|
|
//OK finished ??
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[self _processOwnedObjectsUsingChangeTable: _unprocessedChanges
|
|
|
|
|
deleteTable: _unprocessedDeletes];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[self propagatesDeletesUsingTable: _unprocessedDeletes];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
[self validateDeletesUsingTable: _unprocessedDeletes];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
//verify
|
|
|
|
|
BOOL propagatesDeletes = YES, validateChanges = YES;
|
|
|
|
|
if(_flags.processingChanges == YES
|
|
|
|
|
&& _delegateRespondsTo.shouldValidateChanges)
|
|
|
|
|
validateChanges = [_delegate editingContextShouldValidateChanges:self];
|
|
|
|
|
|
|
|
|
|
if(_flags.processingChanges == NO && [self propagatesDeletesAtEndOfEvent] == NO)
|
|
|
|
|
propagatesDeletes = NO;
|
|
|
|
|
|
|
|
|
|
if(propagatesDeletes == YES)
|
|
|
|
|
{
|
|
|
|
|
if([self propagatesDeletesAtEndOfEvent] == YES)
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_deletedObjects) objectEnumerator];
|
|
|
|
|
else
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedDeletes)
|
|
|
|
|
objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
[object propagatesDeleteWithEditingContext:self];
|
|
|
|
|
|
|
|
|
|
if([self propagatesDeletesAtEndOfEvent] == YES)
|
|
|
|
|
{
|
|
|
|
|
objEnum = [NSAllHashTableObjects(_unprocessedDeletes)
|
|
|
|
|
objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
NSHashInsert(_deletedObjects, object);
|
|
|
|
|
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_deletedObjects);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
deletedObjects = NSAllHashTableObjects(_unprocessedDeletes);
|
|
|
|
|
|
|
|
|
|
objEnum = [deletedObjects objectEnumerator];
|
|
|
|
|
while((object = [objEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
if(validateChanges)
|
|
|
|
|
{
|
|
|
|
|
exp = [object validateForDelete];
|
|
|
|
|
|
|
|
|
|
if(exp) // TODO
|
|
|
|
|
{
|
|
|
|
|
if(_flags.stopsValidation == NO)
|
|
|
|
|
{
|
|
|
|
|
if(_delegate == nil ||
|
|
|
|
|
_delegateRespondsTo.shouldPresentException == NO ||
|
|
|
|
|
(_delegateRespondsTo.shouldPresentException &&
|
|
|
|
|
|
|
|
|
|
[_delegate editingContext:self
|
|
|
|
|
shouldPresentException:exp] == YES))
|
|
|
|
|
[_messageHandler editingContext:self
|
|
|
|
|
presentErrorMessage:[exp reason]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[exp raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(propagatesDeletes == NO || [self propagatesDeletesAtEndOfEvent] == NO)
|
|
|
|
|
NSHashInsert(_deletedObjects, object);
|
|
|
|
|
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertDelete:)
|
|
|
|
|
object:object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
- (void)validateChangesForSave
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *exceptions = nil;
|
|
|
|
|
BOOL validateForDelete = NO;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
2003-06-26 08:20:30 +00:00
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
|
2002-11-15 22:57:05 +00:00
|
|
|
|
validateForDelete = [self validateTable: _unprocessedDeletes
|
|
|
|
|
withSelector: @selector(validateForDelete)
|
|
|
|
|
exceptionArray: &exceptions
|
|
|
|
|
continueAfterFailure: NO];
|
|
|
|
|
|
|
|
|
|
if (!validateForDelete)
|
|
|
|
|
{
|
|
|
|
|
switch ([exceptions count])
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
[[exceptions objectAtIndex: 0] raise];
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BOOL validateForInsert = [self validateTable: _unprocessedInserts
|
|
|
|
|
withSelector: @selector(validateForInsert)
|
|
|
|
|
exceptionArray: &exceptions
|
|
|
|
|
continueAfterFailure: NO];
|
|
|
|
|
|
|
|
|
|
if (!validateForInsert)
|
|
|
|
|
{
|
|
|
|
|
switch ([exceptions count])
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
[[exceptions objectAtIndex: 0] raise];
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BOOL validateForUpdate
|
|
|
|
|
= [self validateTable: _unprocessedInserts
|
|
|
|
|
withSelector: @selector(validateForUpdate)
|
|
|
|
|
exceptionArray: &exceptions
|
|
|
|
|
continueAfterFailure: NO];
|
|
|
|
|
|
|
|
|
|
if (!validateForUpdate)
|
|
|
|
|
{
|
|
|
|
|
switch ([exceptions count])
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
[[exceptions objectAtIndex: 0] raise];
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) validateDeletesUsingTable: (NSHashTable*)deleteTable
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *exceptionArray = nil;
|
|
|
|
|
|
|
|
|
|
if (![self validateTable: deleteTable
|
|
|
|
|
withSelector: @selector(validateForDelete)
|
|
|
|
|
exceptionArray: &exceptionArray
|
|
|
|
|
continueAfterFailure: NO])
|
|
|
|
|
{
|
|
|
|
|
NSException *exception = [NSException aggregateExceptionWithExceptions:
|
|
|
|
|
exceptionArray];
|
|
|
|
|
[exception raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) validateTable: (NSHashTable*)table
|
|
|
|
|
withSelector: (SEL)sel
|
|
|
|
|
exceptionArray: (NSMutableArray**)exceptionArrayPtr
|
|
|
|
|
continueAfterFailure: (BOOL)continueAfterFailure
|
|
|
|
|
{
|
|
|
|
|
BOOL ok = YES;
|
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
id object = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
2003-06-26 08:20:30 +00:00
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"table: %@",
|
|
|
|
|
NSStringFromHashTable(table));
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"sel: %@",
|
|
|
|
|
NSStringFromSelector(sel));
|
|
|
|
|
|
2002-11-15 22:57:05 +00:00
|
|
|
|
enumerator = NSEnumerateHashTable(table);
|
|
|
|
|
|
|
|
|
|
while ((ok || continueAfterFailure)
|
|
|
|
|
&& (object=(id)NSNextHashEnumeratorItem(&enumerator)))
|
|
|
|
|
{
|
|
|
|
|
NSException *exception = [object performSelector: sel];
|
|
|
|
|
|
|
|
|
|
if (exception)
|
|
|
|
|
{
|
|
|
|
|
ok = NO;
|
|
|
|
|
if (continueAfterFailure)
|
|
|
|
|
{
|
|
|
|
|
if (_delegate == nil
|
|
|
|
|
|| _delegateRespondsTo.shouldPresentException == NO
|
|
|
|
|
|| (_delegateRespondsTo.shouldPresentException
|
|
|
|
|
&& [_delegate editingContext: self
|
|
|
|
|
shouldPresentException: exception] == YES))
|
|
|
|
|
[_messageHandler editingContext: self
|
|
|
|
|
presentErrorMessage: [exception reason]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exceptionArrayPtr)
|
|
|
|
|
{
|
|
|
|
|
if (!*exceptionArrayPtr)
|
|
|
|
|
*exceptionArrayPtr = [NSMutableArray array];
|
|
|
|
|
|
|
|
|
|
[*exceptionArrayPtr addObject: exception];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NSEndHashTableEnumeration(enumerator);
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) handleErrors: (id)p
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) handleError: (NSException*)exception
|
|
|
|
|
{
|
|
|
|
|
[exception raise]; //raise the exception??
|
|
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) propagatesDeletesUsingTable: (NSHashTable*)deleteTable
|
|
|
|
|
{
|
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
id object = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
enumerator = NSEnumerateHashTable(deleteTable);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&enumerator)))
|
|
|
|
|
[object propagateDeleteWithEditingContext: self];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _processOwnedObjectsUsingChangeTable: (NSHashTable*)changeTable
|
|
|
|
|
deleteTable: (NSHashTable*)deleteTable
|
|
|
|
|
{
|
|
|
|
|
NSHashTable *objectsToInsert = NSCreateHashTable(NSObjectHashCallBacks, 32);
|
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
id object = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
enumerator = NSEnumerateHashTable(changeTable);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&enumerator)))
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *objectSnapshot = nil;
|
|
|
|
|
NSArray *toOneRelationshipKeys;
|
|
|
|
|
NSArray *toManyRelationshipKeys = nil;
|
|
|
|
|
int i;
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object:%@", object);
|
|
|
|
|
|
|
|
|
|
toOneRelationshipKeys = [object toOneRelationshipKeys];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"toOneRelationshipKeys:%@",
|
|
|
|
|
toOneRelationshipKeys);
|
|
|
|
|
|
|
|
|
|
count = [toOneRelationshipKeys count];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
NSString *relKey = [toOneRelationshipKeys objectAtIndex: i];
|
|
|
|
|
BOOL ownsDestinationObjects
|
|
|
|
|
= [object ownsDestinationObjectsForRelationshipKey:relKey];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"relKey:%@", relKey);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"ownsDestinationObjects: %s",
|
|
|
|
|
(ownsDestinationObjects ? "YES" : "NO"));
|
|
|
|
|
|
|
|
|
|
if (ownsDestinationObjects)
|
|
|
|
|
{
|
|
|
|
|
id existingObject = nil;
|
|
|
|
|
id value = nil;
|
|
|
|
|
|
|
|
|
|
if (!objectSnapshot)
|
|
|
|
|
objectSnapshot = [self currentEventSnapshotForObject: object];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"objectSnapshot:%@",
|
|
|
|
|
objectSnapshot);
|
|
|
|
|
|
|
|
|
|
existingObject = [objectSnapshot objectForKey: relKey];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"existingObject:%@",
|
|
|
|
|
existingObject);
|
|
|
|
|
|
|
|
|
|
value = [object storedValueForKey: relKey];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"value:%@", value);
|
|
|
|
|
|
|
|
|
|
if (value != existingObject)
|
|
|
|
|
{
|
|
|
|
|
if (isNilOrEONull(value))
|
|
|
|
|
{
|
|
|
|
|
if (!isNilOrEONull(existingObject))//value is new
|
|
|
|
|
{
|
|
|
|
|
//existing object is removed
|
|
|
|
|
//TODO ?? ad it in delete table ??
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented:_cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!isNilOrEONull(existingObject))//value is new
|
|
|
|
|
{
|
|
|
|
|
//existing object is removed
|
|
|
|
|
//TODO ?? ad it in delete table ??
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented:_cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
if (!NSHashGet(changeTable,value))//id not already in change table
|
|
|
|
|
{
|
|
|
|
|
//We will insert it
|
|
|
|
|
NSHashInsertIfAbsent(objectsToInsert,value);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",@"Will insert %@",value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toManyRelationshipKeys = [object toManyRelationshipKeys];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object:%@", object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"toManyRelationshipKeys: %@",
|
|
|
|
|
toManyRelationshipKeys);
|
|
|
|
|
|
|
|
|
|
count = [toManyRelationshipKeys count];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
NSString *relKey = [toManyRelationshipKeys objectAtIndex: i]; //1-1 payments
|
|
|
|
|
BOOL ownsDestinationObjects
|
|
|
|
|
= [object ownsDestinationObjectsForRelationshipKey: relKey];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"relKey: %@", relKey);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"ownsDestinationObjects: %s",
|
|
|
|
|
(ownsDestinationObjects ? "YES" : "NO"));
|
|
|
|
|
|
|
|
|
|
if (ownsDestinationObjects) //1-1 YES
|
|
|
|
|
{
|
|
|
|
|
NSArray *existingObjects = nil;
|
|
|
|
|
NSArray *currentObjects = nil;
|
|
|
|
|
NSArray *newObjects = nil;
|
|
|
|
|
int newObjectsCount = 0;
|
|
|
|
|
int iNewObject = 0;
|
|
|
|
|
|
|
|
|
|
if (!objectSnapshot)
|
|
|
|
|
objectSnapshot = [self currentEventSnapshotForObject: object];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"objectSnapshot:%p: %@",
|
|
|
|
|
objectSnapshot, objectSnapshot);
|
|
|
|
|
|
|
|
|
|
existingObjects = [objectSnapshot objectForKey: relKey];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"key %@ existingObjects: %@",
|
|
|
|
|
relKey, existingObjects);
|
|
|
|
|
|
|
|
|
|
currentObjects = [object storedValueForKey: relKey];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"key %@ currentObjects: %@",
|
|
|
|
|
relKey, currentObjects);
|
|
|
|
|
//TODO YY=[currentObjects shallowCopy];
|
|
|
|
|
|
|
|
|
|
newObjects = [currentObjects arrayExcludingObjectsInArray:
|
|
|
|
|
existingObjects];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"newObjects: %@",
|
|
|
|
|
newObjects);
|
|
|
|
|
|
|
|
|
|
newObjectsCount = [newObjects count];
|
|
|
|
|
|
|
|
|
|
for (iNewObject = 0; iNewObject < newObjectsCount; iNewObject++)
|
|
|
|
|
{
|
|
|
|
|
id newObject = [newObjects objectAtIndex: iNewObject];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"newObject: %@",
|
|
|
|
|
newObject);
|
|
|
|
|
|
|
|
|
|
if (!NSHashGet(changeTable, newObject)) //id not already in change table (or in insertTable ?)
|
|
|
|
|
{
|
|
|
|
|
//We will insert it
|
|
|
|
|
NSHashInsertIfAbsent(objectsToInsert, newObject);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"Will insert %@", newObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO XX=[existingObjects arrayExcludingObjectsInArray:(newObjects or currentObjects)];//nil
|
|
|
|
|
//=========>
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
//TODO [self notImplemented:_cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enumerator = NSEnumerateHashTable(objectsToInsert);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&enumerator)))
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Insert %@", object);
|
|
|
|
|
[self insertObject: object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSFreeHashTable(objectsToInsert);
|
|
|
|
|
|
|
|
|
|
//TODO-NOW: use deleteTable !
|
|
|
|
|
//[self notImplemented:_cmd]; //TODO
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) registerUndoForModifiedObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
NSDictionary *snapshot;
|
|
|
|
|
NSDictionary *undoObject;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
|
|
|
|
|
gid = [self globalIDForObject: object];
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
|
|
|
|
|
snapshot = [self currentEventSnapshotForObject: object];
|
|
|
|
|
undoObject = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
object, @"object",
|
|
|
|
|
snapshot, @"snapshot",
|
|
|
|
|
nil, nil];
|
|
|
|
|
|
|
|
|
|
[_undoManager registerUndoWithTarget: self
|
|
|
|
|
selector: @selector(_undoUpdate:)
|
|
|
|
|
object: undoObject];
|
|
|
|
|
|
|
|
|
|
[_eventSnapshotsByGID removeObjectForKey: gid];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _undoUpdate: (id)param0
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
//TODO
|
|
|
|
|
// receive a dict with object and snapshot ? (cf registerUndoForModifiedObject:)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)incrementUndoTransactionID
|
|
|
|
|
{
|
|
|
|
|
_undoTransactionID++;
|
|
|
|
|
_flags.registeredUndoTransactionID = NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _registerClearStateWithUndoManager
|
|
|
|
|
{
|
|
|
|
|
//pas appell<EFBFBD> dans le cas d'un delete ?
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
object = [NSNumber numberWithUnsignedInt: _undoTransactionID];
|
|
|
|
|
_flags.registeredUndoTransactionID = YES;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"_undoManager=%p", _undoManager);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"_undoManager=%@", _undoManager);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"self=%@", self);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
|
|
|
|
|
[_undoManager registerUndoWithTarget: self
|
|
|
|
|
selector: @selector(_clearChangedThisTransaction:)
|
|
|
|
|
object: object];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)deleteObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
if (!NSHashGet(_unprocessedDeletes, object)
|
|
|
|
|
&& !NSHashGet(_deletedObjects, object))
|
|
|
|
|
{
|
|
|
|
|
NSMethodSignature *undoMethodSignature = nil;
|
2003-03-31 00:24:15 +00:00
|
|
|
|
NSUndoManager *undoManager;
|
2002-11-15 22:57:05 +00:00
|
|
|
|
//EOGlobalID *gid = [self globalIDForObject: object];
|
|
|
|
|
|
|
|
|
|
[self _registerClearStateWithUndoManager];
|
|
|
|
|
|
2003-03-31 00:24:15 +00:00
|
|
|
|
undoManager = (NSUndoManager*)[self undoManager];
|
2002-11-15 22:57:05 +00:00
|
|
|
|
[undoManager prepareWithInvocationTarget: self];
|
|
|
|
|
|
|
|
|
|
undoMethodSignature = [undoManager methodSignatureForSelector:
|
|
|
|
|
@selector(_insertObject:withGlobalID:)];
|
|
|
|
|
/*
|
|
|
|
|
//TODO
|
|
|
|
|
if base class of undoManager ret nil, undomanager call editingcont methodSignatureForSelector: _insertObject:withGlobalID:
|
|
|
|
|
|
|
|
|
|
undoManager forwardInvocation:
|
|
|
|
|
<NSInvocation selector: _insertObject:withGlobalID: signature: NMethodSignature: types=v@:@@ nargs=4 sizeOfParams=16 returnValueLength=0; >
|
|
|
|
|
_NSUndoInvocation avec selector:_insertObject:withGlobalID:
|
|
|
|
|
target self (editing context)
|
|
|
|
|
[undoManager _registerUndoObject:arget: EOEditingContext -- selector:_insertObject:withGlobalID:
|
|
|
|
|
_invocation=NSInvocation * object: Description:<NSInvocation selector: _insertObject:withGlobalID: signature: NSMethodSignature: types=v@:@@ nargs=4 sizeOfParams=16 returnValueLength=0; >
|
|
|
|
|
next=_NSUndoObject * object:0x0 Description:*nil*
|
|
|
|
|
previous=_NSUndoObject * object:0x0 Description:*nil*
|
|
|
|
|
_target=id object: Description:<EOEditingContext>
|
|
|
|
|
[self _prepareEventGrouping];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
NSHashInsert(_unprocessedDeletes, object);
|
|
|
|
|
[self _enqueueEndOfEventNotification];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)lockObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gid = [self globalIDForObject: object];
|
|
|
|
|
|
|
|
|
|
if (gid == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ -- %@ 0x%x: globalID for object 0x%x not found",
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
self,
|
|
|
|
|
object];
|
|
|
|
|
|
|
|
|
|
[self lockObjectWithGlobalID: gid
|
|
|
|
|
editingContext: self];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Saving
|
|
|
|
|
- (BOOL)hasChanges
|
|
|
|
|
{
|
|
|
|
|
if(NSCountHashTable(_insertedObjects)
|
|
|
|
|
|| NSCountHashTable(_deletedObjects)
|
|
|
|
|
|| NSCountHashTable(_changedObjects))
|
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)didSaveChanges
|
|
|
|
|
{
|
|
|
|
|
NSHashTable *hashTables[3]={ _insertedObjects,
|
|
|
|
|
_deletedObjects,//??
|
|
|
|
|
_changedObjects };
|
|
|
|
|
NSMutableArray *objectsForNotification[3]={ [NSMutableArray array],//inserted
|
|
|
|
|
[NSMutableArray array],//deleted
|
|
|
|
|
[NSMutableArray array] };//updated
|
|
|
|
|
NSEnumerator *enumerator = nil;
|
|
|
|
|
id object = nil;
|
|
|
|
|
int which;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"Changes nb: inserted:%d deleted:%d changed:%d",
|
|
|
|
|
NSCountHashTable(_insertedObjects),
|
|
|
|
|
NSCountHashTable(_deletedObjects),
|
|
|
|
|
NSCountHashTable(_changedObjects));
|
|
|
|
|
|
|
|
|
|
_flags.ignoreChangeNotification=NO; //MG??
|
|
|
|
|
|
|
|
|
|
for (which = 0; which < 3; which++)
|
|
|
|
|
{
|
|
|
|
|
NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator)))
|
|
|
|
|
{
|
|
|
|
|
[objectsForNotification[which] addObject: object];
|
|
|
|
|
[self clearOriginalSnapshotForObject: object]; //OK for update
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enumerator = [NSAllHashTableObjects(_deletedObjects) objectEnumerator];
|
|
|
|
|
while ((object = [enumerator nextObject]))
|
|
|
|
|
{
|
|
|
|
|
[self forgetObject: object];
|
|
|
|
|
[object clearProperties];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_insertedObjects);
|
|
|
|
|
NSResetHashTable(_deletedObjects);
|
|
|
|
|
NSResetHashTable(_changedObjects);
|
|
|
|
|
[self incrementUndoTransactionID]; //OK for update
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
|
|
|
|
|
enumerator = [[_snapshotsByGID allKeys] objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((gid = [enumerator nextObject]))
|
|
|
|
|
{
|
|
|
|
|
[_snapshotsByGID setObject: [[self objectForGlobalID:gid] snapshot]
|
|
|
|
|
forKey: gid];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName: @"EOEditingContextDidSaveChangesNotification"
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
objectsForNotification[0], @"inserted",
|
|
|
|
|
objectsForNotification[1], @"deleted",
|
|
|
|
|
objectsForNotification[2], @"updated",
|
|
|
|
|
nil, nil]];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)saveChanges
|
|
|
|
|
{
|
|
|
|
|
id object = nil;
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
//TODOLOCK
|
|
|
|
|
[self lock];
|
|
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
enumerator = [_editors objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((object = [enumerator nextObject]))
|
|
|
|
|
[object editingContextWillSaveChanges: self];
|
|
|
|
|
|
|
|
|
|
if (_delegateRespondsTo.willSaveChanges)
|
|
|
|
|
[_delegate editingContextWillSaveChanges: self];
|
|
|
|
|
|
|
|
|
|
[self _processRecentChanges]; // filled lists _changedObjects, _deletedObjects, _insertedObjects, breaks relations
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
_flags.registeredForCallback = NO;
|
|
|
|
|
|
|
|
|
|
[self validateChangesForSave]; // may raise exception
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
//?? [EOObserverCenter notifyObserversObjectWillChange: nil];
|
|
|
|
|
|
|
|
|
|
_flags.ignoreChangeNotification = YES;
|
|
|
|
|
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"_objectStore saveChangesInEditingContext");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
[_objectStore saveChangesInEditingContext: self];
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"self didSaveChanges");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
[self didSaveChanges];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ (%@)", localException, [localException reason]);
|
|
|
|
|
NSDebugMLog(@"%@ (%@)", localException, [localException reason]);
|
|
|
|
|
|
|
|
|
|
[self unlock];
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
|
|
|
|
|
[self unlock];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSException *) tryToSaveChanges
|
|
|
|
|
{
|
|
|
|
|
NSException *newException = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStartOrCond(@"EOEditingContext");
|
|
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
[self saveChanges];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
if(_messageHandler
|
|
|
|
|
&& [_messageHandler
|
2002-12-31 16:25:21 +00:00
|
|
|
|
respondsToSelector: @selector(editingContext:presentErrorMessage:)] == YES)
|
2002-11-15 22:57:05 +00:00
|
|
|
|
[_messageHandler editingContext: self
|
|
|
|
|
presentErrorMessage: [localException reason]];
|
|
|
|
|
|
|
|
|
|
newException = localException;
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStopOrCond(@"EOEditingContext");
|
|
|
|
|
|
|
|
|
|
return newException;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)revert
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
|
|
|
|
|
enumerator = [_eventSnapshotsByGID keyEnumerator];
|
|
|
|
|
while ((gid = [enumerator nextObject]))
|
|
|
|
|
{
|
|
|
|
|
[[self objectForGlobalID: gid]
|
|
|
|
|
updateFromSnapshot: [_eventSnapshotsByGID objectForKey: gid]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
[_undoManager removeAllActions];
|
|
|
|
|
[_undoManager beginUndoGrouping];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_unprocessedChanges);
|
|
|
|
|
NSResetHashTable(_unprocessedDeletes);
|
|
|
|
|
NSResetHashTable(_unprocessedInserts);
|
|
|
|
|
|
|
|
|
|
NSResetHashTable(_changedObjects);
|
|
|
|
|
NSResetHashTable(_deletedObjects);
|
|
|
|
|
NSResetHashTable(_insertedObjects);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) clearOriginalSnapshotForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
//Consider OK
|
2003-06-26 08:20:30 +00:00
|
|
|
|
EOGlobalID *gid = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
gid = [self globalIDForObject: object];
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
if (gid)
|
|
|
|
|
{
|
|
|
|
|
[_snapshotsByGID removeObjectForKey: gid];
|
|
|
|
|
}
|
2003-06-26 08:20:30 +00:00
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
2002-11-15 22:57:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)objectForGlobalID:(EOGlobalID *)globalID
|
|
|
|
|
{
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", globalID);
|
|
|
|
|
// NSDebugMLLog(@"XXX",@"_objectsByGID=%@",NSAllMapTableKeys(_objectsByGID));
|
|
|
|
|
|
|
|
|
|
object = NSMapGet(_objectsByGID, globalID);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (EOGlobalID *)globalIDForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
//Consider OK
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
[self recordForObject:object]
|
|
|
|
|
[self notImplemented:_cmd]; //TODO
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"ed context=%p _objectsById=%p object=%p",
|
|
|
|
|
self, _objectsById, object);
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext",@"_objectsById Values=%@",NSAllMapTableValues(_objectsById));
|
|
|
|
|
|
|
|
|
|
gid = NSMapGet(_objectsById, object);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return gid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSHashTable*) recordForGID: (EOGlobalID *)globalID
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSHashTable*) recordForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setDelegate: (id)delegate
|
|
|
|
|
{
|
|
|
|
|
_delegate = delegate;
|
|
|
|
|
_delegateRespondsTo.willRunLoginPanel =
|
|
|
|
|
[delegate respondsToSelector: @selector(databaseContext:willRunLoginPanelToOpenDatabaseChannel:)];
|
|
|
|
|
_delegateRespondsTo.shouldFetchObjects =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContext:shouldFetchObjectsDescribedByFetchSpecification:)];
|
|
|
|
|
_delegateRespondsTo.shouldInvalidateObject =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContext:shouldInvalidateObject:globalID:)];
|
|
|
|
|
_delegateRespondsTo.shouldMergeChanges =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContext:shouldMergeChangesForObject:)];
|
|
|
|
|
_delegateRespondsTo.shouldPresentException =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContext:shouldPresentException:)];
|
|
|
|
|
_delegateRespondsTo.shouldUndoUserActions =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContextShouldUndoUserActionsAfterFailure:)];
|
|
|
|
|
_delegateRespondsTo.shouldValidateChanges =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContextShouldValidateChanges:)];
|
|
|
|
|
_delegateRespondsTo.willSaveChanges =
|
|
|
|
|
[delegate respondsToSelector: @selector(editingContextWillSaveChanges:)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)delegate
|
|
|
|
|
{
|
|
|
|
|
return _delegate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (EOObjectStore *)parentObjectStore
|
|
|
|
|
{
|
|
|
|
|
return _objectStore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (EOObjectStore *)rootObjectStore
|
|
|
|
|
{
|
|
|
|
|
EOObjectStore *rootObjectStore;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
if ([_objectStore isKindOfClass: [EOEditingContext class]] == YES)
|
|
|
|
|
rootObjectStore = [(EOEditingContext *)_objectStore rootObjectStore];
|
|
|
|
|
else
|
|
|
|
|
rootObjectStore=_objectStore;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return rootObjectStore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Advanced methods //////////////////////////
|
|
|
|
|
|
|
|
|
|
- (void)setUndoManager: (NSUndoManager *)undoManager
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_undoManager, undoManager);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUndoManager *)undoManager
|
|
|
|
|
{
|
|
|
|
|
return _undoManager;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_revertChange: (NSDictionary *)dict
|
|
|
|
|
{
|
|
|
|
|
[[dict objectForKey: @"object"]
|
|
|
|
|
updateFromSnapshot: [dict objectForKey: @"snapshot"]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)objectWillChange: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
// EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"object=%@ _flags.ignoreChangeNotification=%d",
|
|
|
|
|
object, (int)_flags.ignoreChangeNotification);
|
|
|
|
|
|
|
|
|
|
if (_flags.ignoreChangeNotification == NO)
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *snapshot;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"*** object change %p %@",
|
|
|
|
|
object, [object class]);
|
|
|
|
|
//recordForObject:
|
|
|
|
|
|
|
|
|
|
snapshot = [object snapshot]; // OK
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"snapshot=%@", snapshot);
|
|
|
|
|
//if not in _unprocessedChanges: add in snaps and call _enqueueEndOfEventNotification
|
|
|
|
|
/*
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(noop:)
|
|
|
|
|
object:nil;];
|
|
|
|
|
*/
|
|
|
|
|
////////
|
|
|
|
|
if (NSHashInsertIfAbsent(_unprocessedChanges, object)) //The object is already here
|
|
|
|
|
{
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"_enqueueEndOfEventNotification");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
[self _enqueueEndOfEventNotification];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if(_undoManager)
|
|
|
|
|
[_undoManager registerUndoWithTarget:self
|
|
|
|
|
selector:@selector(_revertChange:)
|
|
|
|
|
object:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
object, @"object",
|
|
|
|
|
[object snapshot], @"snapshot",
|
|
|
|
|
nil]];
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//???????????
|
|
|
|
|
EOGlobalID *gid = [self globalIDForObject: object];
|
|
|
|
|
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext",
|
|
|
|
|
@"insert into xxsnapshotsByGID");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
[_eventSnapshotsByGID setObject: [object snapshot]
|
|
|
|
|
forKey: gid];
|
|
|
|
|
|
|
|
|
|
[_snapshotsByGID setObject: [object snapshot]
|
|
|
|
|
forKey: gid];
|
|
|
|
|
|
|
|
|
|
if (_flags.autoLocking == YES)
|
|
|
|
|
[self lockObject: object];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)recordObject: (id)object
|
|
|
|
|
globalID: (EOGlobalID *)globalID
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"Record %p for %@ in ed context %p _objectsById=%p",
|
|
|
|
|
object, globalID, self, _objectsById);
|
|
|
|
|
|
|
|
|
|
NSAssert(object, @"No Object");
|
|
|
|
|
NSAssert(globalID, @"No GlobalID");
|
|
|
|
|
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"insertInto _objectsById");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
NSMapInsert(_objectsById, object, globalID);
|
|
|
|
|
|
|
|
|
|
//TODO: delete
|
|
|
|
|
{
|
|
|
|
|
id aGID2;
|
|
|
|
|
id aGID = NSMapGet(_objectsById, object);
|
|
|
|
|
|
|
|
|
|
NSAssert1(aGID, @"Object %p recorded but can't retrieve it directly !",
|
|
|
|
|
object);
|
|
|
|
|
|
|
|
|
|
aGID2 = [self globalIDForObject: object];
|
|
|
|
|
|
|
|
|
|
NSAssert1(aGID2, @"Object %p recorded but can't retrieve it with globalIDForObject: !", object);
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"insertInto _objectsByGID");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
NSMapInsert(_objectsByGID, globalID, object);
|
|
|
|
|
|
2002-12-08 10:07:26 +00:00
|
|
|
|
EOFLOGObjectLevel(@"EOEditingContext", @"addObserver");
|
2002-11-15 22:57:05 +00:00
|
|
|
|
|
|
|
|
|
[EOObserverCenter addObserver: self
|
|
|
|
|
forObject: object];
|
|
|
|
|
//call EOAccessFaultHandler targetClass
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)forgetObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
|
|
|
|
|
gid = [self globalIDForObject: object];
|
|
|
|
|
NSMapRemove(_objectsById, object);
|
|
|
|
|
NSMapRemove(_objectsByGID, gid);
|
|
|
|
|
|
|
|
|
|
[EOObserverCenter removeObserver: self
|
|
|
|
|
forObject: object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)registeredObjects
|
|
|
|
|
{
|
|
|
|
|
return NSAllMapTableValues(_objectsByGID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)updatedObjects
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *updatedObjects = [NSMutableArray array];
|
|
|
|
|
NSHashEnumerator changedEnum = NSEnumerateHashTable(_changedObjects);
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&changedEnum)))
|
|
|
|
|
{
|
|
|
|
|
if (!NSHashGet(_deletedObjects, (const void*)object))
|
|
|
|
|
[updatedObjects addObject: object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NSEndHashTableEnumeration(changedEnum);
|
|
|
|
|
|
|
|
|
|
return updatedObjects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)insertedObjects
|
|
|
|
|
{
|
|
|
|
|
return NSAllHashTableObjects(_insertedObjects);
|
|
|
|
|
//TODO: remove inserted objectss which are deleted ???
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)deletedObjects
|
|
|
|
|
{
|
|
|
|
|
return NSAllHashTableObjects(_deletedObjects);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void)_revertInsert: (id)object
|
|
|
|
|
{
|
|
|
|
|
NSHashRemove(_insertedObjects, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_revertUpdate: (id)object
|
|
|
|
|
{
|
|
|
|
|
NSHashRemove(_changedObjects, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_revertDelete: (id)object
|
|
|
|
|
{
|
|
|
|
|
NSHashRemove(_deletedObjects, object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ***************************
|
|
|
|
|
// *
|
|
|
|
|
// * Objects for DELETE
|
|
|
|
|
// *
|
|
|
|
|
// * compares object from _unprocessedChanges
|
|
|
|
|
// * between their state from _eventSnapshots and [object snapshot]
|
|
|
|
|
// *
|
|
|
|
|
// * you can see if any other instead of this EditingContext has changed the object
|
|
|
|
|
// *
|
|
|
|
|
// * decision of keeping or deleting these changed objects (RelationshipObjects)
|
|
|
|
|
// *
|
|
|
|
|
// ****************************
|
|
|
|
|
- (void)processRecentChanges
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@",
|
|
|
|
|
[self unprocessedDescription]);
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@",
|
|
|
|
|
[self objectsDescription]);
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
|
|
|
|
|
// [self notImplemented:_cmd]; //TODO
|
|
|
|
|
[self _processRecentChanges]; //ret YES
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)propagatesDeletesAtEndOfEvent
|
|
|
|
|
{
|
|
|
|
|
return _flags.propagatesDeletesAtEndOfEvent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setPropagatesDeletesAtEndOfEvent: (BOOL)propagatesDeletesAtEndOfEvent
|
|
|
|
|
{
|
|
|
|
|
_flags.propagatesDeletesAtEndOfEvent = propagatesDeletesAtEndOfEvent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)stopsValidationAfterFirstError
|
|
|
|
|
{
|
|
|
|
|
return !_flags.exhaustiveValidation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setStopsValidationAfterFirstError:(BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_flags.exhaustiveValidation = !flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)locksObjectsBeforeFirstModification
|
|
|
|
|
{
|
|
|
|
|
return _flags.autoLocking;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setLocksObjectsBeforeFirstModification: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_flags.autoLocking = flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Snapshotting
|
|
|
|
|
|
|
|
|
|
/** Returns a dictionary containing a snapshot of object that
|
|
|
|
|
reflects its committed values (last values putted in the
|
|
|
|
|
database; i.e. values before changes were made on the object).
|
|
|
|
|
It is updated after commiting new values.
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)committedSnapshotForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
return [_snapshotsByGID objectForKey: [self globalIDForObject: object]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns a dictionary containing a snapshot of object with
|
|
|
|
|
its state as it was at the beginning of the current event loop.
|
|
|
|
|
After the end of the current event, upon invocation of
|
|
|
|
|
processRecentChanges, the snapshot is updated to hold the
|
|
|
|
|
modified state of the object.**/
|
|
|
|
|
- (NSDictionary *)currentEventSnapshotForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
return [_eventSnapshotsByGID objectForKey: [self globalIDForObject: object]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDictionary *)uncommittedChangesForObject: (id)object
|
|
|
|
|
{
|
|
|
|
|
return [object changesFromSnapshot:
|
|
|
|
|
[self currentEventSnapshotForObject: object]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)refaultObjects
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray *objs = [[NSMutableArray new] autorelease];
|
|
|
|
|
NSEnumerator *objsEnum;
|
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
|
|
[self processRecentChanges];
|
|
|
|
|
|
|
|
|
|
[objs addObjectsFromArray: NSAllMapTableKeys(_objectsById)];
|
|
|
|
|
|
|
|
|
|
[objs removeObjectsInArray: [self insertedObjects]];
|
|
|
|
|
[objs removeObjectsInArray: [self deletedObjects]];
|
|
|
|
|
[objs removeObjectsInArray: [self updatedObjects]];
|
|
|
|
|
|
|
|
|
|
objsEnum = [objs objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((obj = [objsEnum nextObject]))
|
|
|
|
|
[self refaultObject: obj
|
|
|
|
|
withGlobalID: [self globalIDForObject: obj]
|
|
|
|
|
editingContext: self];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Refaults all objects that haven't been modified, inserted or deleted.
|
|
|
|
|
|
|
|
|
|
- (void)setInvalidatesObjectsWhenFreed: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_flags.skipInvalidateOnDealloc = flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)invalidatesObjectsWhenFreed
|
|
|
|
|
{
|
|
|
|
|
return _flags.skipInvalidateOnDealloc; // TODO contrario ??
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)addEditor: (id)editor
|
|
|
|
|
{
|
|
|
|
|
[_editors addObject: editor];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)removeEditor: (id)editor
|
|
|
|
|
{
|
|
|
|
|
[_editors removeObject: editor];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)editors
|
|
|
|
|
{
|
|
|
|
|
return _editors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setMessageHandler: (id)handler
|
|
|
|
|
{
|
|
|
|
|
_messageHandler = handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)messageHandler
|
|
|
|
|
{
|
|
|
|
|
return _messageHandler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)faultForGlobalID: (EOGlobalID *)globalID
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
id object = [self objectForGlobalID: globalID];
|
|
|
|
|
|
|
|
|
|
if (!object)
|
|
|
|
|
{
|
|
|
|
|
BOOL isTemporary = [globalID isTemporary];
|
|
|
|
|
|
|
|
|
|
if (isTemporary)
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
object = [_objectStore faultForGlobalID: globalID
|
|
|
|
|
editingContext: self];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)faultForRawRow: (NSDictionary *)row
|
|
|
|
|
entityNamed: (NSString *)entityName
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
EOEntityClassDescription *classDesc;
|
|
|
|
|
EOGlobalID *globalID;
|
|
|
|
|
id object;
|
|
|
|
|
id objectCopy;
|
|
|
|
|
|
|
|
|
|
classDesc = (id)[EOClassDescription classDescriptionForEntityName:
|
|
|
|
|
entityName];
|
2003-02-04 15:17:07 +00:00
|
|
|
|
#warning (stephane@sente.ch) ERROR: trying to use EOEntity/EOEntityDescription which are defined in EOAccess
|
2002-11-15 22:57:05 +00:00
|
|
|
|
globalID = [[classDesc entity] globalIDForRow: row];
|
|
|
|
|
object = [self objectForGlobalID: globalID];
|
|
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
if (context == self)
|
|
|
|
|
return object;
|
|
|
|
|
|
|
|
|
|
objectCopy = [classDesc createInstanceWithEditingContext: context
|
|
|
|
|
globalID: globalID
|
|
|
|
|
zone: NULL];
|
|
|
|
|
|
|
|
|
|
NSAssert1(objectCopy, @"No Object. classDesc=%@", classDesc);
|
|
|
|
|
[objectCopy updateFromSnapshot: [object snapshot]];
|
|
|
|
|
|
|
|
|
|
[context recordObject: objectCopy
|
|
|
|
|
globalID: globalID];
|
|
|
|
|
|
|
|
|
|
return objectCopy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object = [_objectStore faultForRawRow: row
|
|
|
|
|
entityNamed: entityName
|
|
|
|
|
editingContext: self];
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)faultForRawRow: (id)row entityNamed: (NSString *)entityName
|
|
|
|
|
{
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStartOrCond(@"EOEditingContext");
|
|
|
|
|
|
|
|
|
|
object = [self faultForRawRow: row
|
|
|
|
|
entityNamed: entityName
|
|
|
|
|
editingContext: self];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStopOrCond(@"EOEditingContext");
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID
|
|
|
|
|
relationshipName: (NSString *)name
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
NSArray *fault;
|
|
|
|
|
id object = [self objectForGlobalID: globalID];
|
|
|
|
|
id objectCopy;
|
|
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
if (context == self)
|
|
|
|
|
{
|
|
|
|
|
fault = [object valueForKey:name];
|
|
|
|
|
if (fault)
|
|
|
|
|
return fault;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
objectCopy = [[EOClassDescription classDescriptionForEntityName:
|
|
|
|
|
[globalID entityName]]
|
|
|
|
|
createInstanceWithEditingContext: context
|
|
|
|
|
globalID: globalID
|
|
|
|
|
zone: NULL];
|
|
|
|
|
|
|
|
|
|
NSAssert1(objectCopy, @"No Object. globalID=%@", globalID);
|
|
|
|
|
[objectCopy updateFromSnapshot: [object snapshot]];
|
|
|
|
|
|
|
|
|
|
[context recordObject: objectCopy
|
|
|
|
|
globalID: globalID];
|
|
|
|
|
|
|
|
|
|
return [objectCopy valueForKey: name];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [_objectStore arrayFaultWithSourceGlobalID: globalID
|
|
|
|
|
relationshipName: name
|
|
|
|
|
editingContext: self];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)initializeObject: (id)object
|
|
|
|
|
withGlobalID: (EOGlobalID *)globalID
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
//near OK
|
|
|
|
|
EOObjectStore *objectStore = nil;
|
|
|
|
|
|
|
|
|
|
_flags.ignoreChangeNotification = YES;
|
|
|
|
|
|
|
|
|
|
if (self == context)
|
|
|
|
|
{
|
|
|
|
|
objectStore = [(EOObjectStoreCoordinator*)_objectStore objectStoreForGlobalID: globalID];
|
|
|
|
|
[objectStore initializeObject: object
|
|
|
|
|
withGlobalID: globalID
|
|
|
|
|
editingContext: context];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd];//TODO
|
|
|
|
|
}
|
|
|
|
|
// [EOObserverCenter notifyObserversObjectWillChange: nil];
|
|
|
|
|
_flags.ignoreChangeNotification = NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID
|
|
|
|
|
relationshipName: (NSString *)name
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
NSArray *objects = nil;
|
|
|
|
|
|
|
|
|
|
if (self == context)
|
|
|
|
|
{
|
|
|
|
|
//TODOLOCK
|
|
|
|
|
[self lock];
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
objects = [_objectStore objectsForSourceGlobalID: globalID
|
|
|
|
|
relationshipName: name
|
|
|
|
|
editingContext: context];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ (%@)", localException, [localException reason]);
|
|
|
|
|
NSDebugMLog(@"%@ (%@)", localException, [localException reason]);
|
|
|
|
|
[self unlock];
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
|
|
|
|
|
[self unlock];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd];//TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return objects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)refaultObject: object
|
|
|
|
|
withGlobalID: (EOGlobalID *)globalID
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
//Near OK
|
|
|
|
|
if (object)
|
|
|
|
|
{
|
|
|
|
|
//call globalID isTemporary //ret NO
|
|
|
|
|
if (self == context)//??
|
|
|
|
|
{
|
|
|
|
|
//NO: in EODatabaseConetxt [object clearProperties];
|
|
|
|
|
|
|
|
|
|
//OK
|
|
|
|
|
[_objectStore refaultObject: object
|
|
|
|
|
withGlobalID: globalID
|
|
|
|
|
editingContext: context];
|
|
|
|
|
//OK
|
|
|
|
|
[self clearOriginalSnapshotForObject: object];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)saveChangesInEditingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
if (context != self)
|
|
|
|
|
{
|
|
|
|
|
NSArray *objects;
|
|
|
|
|
NSEnumerator *objsEnum;
|
|
|
|
|
EOGlobalID *gid;
|
|
|
|
|
id object, localObject;
|
|
|
|
|
|
|
|
|
|
objects = [context insertedObjects];
|
|
|
|
|
|
|
|
|
|
objsEnum = [objects objectEnumerator];
|
|
|
|
|
while ((object = [objsEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
gid = [context globalIDForObject: object];
|
|
|
|
|
|
|
|
|
|
localObject = [[EOClassDescription classDescriptionForEntityName:
|
|
|
|
|
[gid entityName]]
|
|
|
|
|
createInstanceWithEditingContext: context
|
|
|
|
|
globalID: gid
|
|
|
|
|
zone: NULL];
|
|
|
|
|
|
|
|
|
|
NSAssert1(localObject, @"No Object. gid=%@", gid);
|
|
|
|
|
|
|
|
|
|
[localObject updateFromSnapshot: [object snapshot]];
|
|
|
|
|
|
|
|
|
|
[self recordObject: localObject
|
|
|
|
|
globalID: gid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objects = [context updatedObjects];
|
|
|
|
|
|
|
|
|
|
objsEnum = [objects objectEnumerator];
|
|
|
|
|
while ((object = [objsEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
gid = [context globalIDForObject: object];
|
|
|
|
|
localObject = [self objectForGlobalID: gid];
|
|
|
|
|
|
|
|
|
|
[localObject updateFromSnapshot:[object snapshot]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
objects = [context deletedObjects];
|
|
|
|
|
|
|
|
|
|
objsEnum = [objects objectEnumerator];
|
|
|
|
|
while ((object = [objsEnum nextObject]))
|
|
|
|
|
{
|
|
|
|
|
gid = [context globalIDForObject: object];
|
|
|
|
|
localObject = [self objectForGlobalID: gid];
|
|
|
|
|
|
|
|
|
|
[self deleteObject: localObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
//OK
|
|
|
|
|
NSArray *objects = nil;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
|
|
|
|
@"_objectStore=%@ fetch=%@ context=%@",
|
|
|
|
|
_objectStore, fetch, context);
|
|
|
|
|
|
|
|
|
|
[self lock]; //TODOLOCK
|
|
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
objects = [_objectStore objectsWithFetchSpecification: fetch
|
|
|
|
|
editingContext: context];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectLevelArgs(@"EOEditingContext", @"EXCEPTION: %@",
|
|
|
|
|
localException);
|
|
|
|
|
|
|
|
|
|
[self unlock]; //TODOLOCK
|
|
|
|
|
|
|
|
|
|
if ([self handleError: localException])
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSEmitTODO();
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
|
|
|
|
|
[self unlock]; //TODOLOCK
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return objects;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)lockObjectWithGlobalID: (EOGlobalID *)gid
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
[_objectStore lockObjectWithGlobalID: gid
|
|
|
|
|
editingContext: context];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid
|
|
|
|
|
editingContext: (EOEditingContext *)context
|
|
|
|
|
{
|
|
|
|
|
return [_objectStore isObjectLockedWithGlobalID: gid
|
|
|
|
|
editingContext: context];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (EOEditingContext)
|
|
|
|
|
|
|
|
|
|
- (EOEditingContext *)editingContext
|
|
|
|
|
{
|
|
|
|
|
return [EOObserverCenter observerForObject: self
|
|
|
|
|
ofClass: [EOEditingContext class]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (EOEditors)
|
|
|
|
|
|
|
|
|
|
/** Called by the EOEditingContext to determine if the editor is "dirty" **/
|
|
|
|
|
- (BOOL)editorHasChangesForEditingContext: (EOEditingContext *)editingContext
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// EOMessageHandler informal protocol
|
|
|
|
|
//
|
|
|
|
|
@implementation NSObject (EOMessageHandlers)
|
|
|
|
|
|
|
|
|
|
- (void)editingContext: (EOEditingContext *)editingContext
|
|
|
|
|
presentErrorMessage: (NSString *)message
|
|
|
|
|
{
|
|
|
|
|
NSDebugMLog(@"error=%@", message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)editingContext: (EOEditingContext *)editingContext
|
|
|
|
|
shouldContinueFetchingWithCurrentObjectCount: (unsigned)count
|
|
|
|
|
originalLimit: (unsigned)limit
|
|
|
|
|
objectStore: (EOObjectStore *)objectStore
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation EOEditingContext (EORendezvous)
|
|
|
|
|
|
|
|
|
|
+ (void)setSubstitutionEditingContext: (EOEditingContext *)ec
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (EOEditingContext *)substitutionEditingContext
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void)setDefaultParentObjectStore: (EOObjectStore *)store
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(defaultParentStore, store);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (EOObjectStore *)defaultParentObjectStore
|
|
|
|
|
{
|
|
|
|
|
return defaultParentStore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation EOEditingContext (EOStateArchiving)
|
|
|
|
|
|
|
|
|
|
+ (void)setUsesContextRelativeEncoding: (BOOL)yn
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL)usesContextRelativeEncoding
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void)encodeObject: (id)object
|
|
|
|
|
withCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id)initObject: (id)object
|
|
|
|
|
withCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
return [self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Target action methods for InterfaceBuilder
|
|
|
|
|
//
|
|
|
|
|
@implementation EOEditingContext (EOTargetAction)
|
|
|
|
|
|
|
|
|
|
- (void)saveChanges: (id)sender // TODO
|
|
|
|
|
{
|
|
|
|
|
NS_DURING
|
|
|
|
|
[self saveChanges];
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
if(_messageHandler
|
|
|
|
|
&& [_messageHandler
|
2002-12-31 16:25:21 +00:00
|
|
|
|
respondsToSelector: @selector(editingContext:presentErrorMessage:)] == YES)
|
2002-11-15 22:57:05 +00:00
|
|
|
|
[_messageHandler editingContext: self
|
|
|
|
|
presentErrorMessage: [localException reason]];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)refault: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[self refaultObjects];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)revert: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[self revert];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)refetch: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[self invalidateAllObjects];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)undo: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[_undoManager undo];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)redo: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[_undoManager redo];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*)unprocessedDescription
|
|
|
|
|
{
|
|
|
|
|
NSString *desc;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
desc = [NSString stringWithFormat: @"<%p:\nunprocessedChanges [nb:%d]=%p %@\n\nunprocessedDeletes [nb:%d]=%p %@\n\nunprocessedInserts[nb:%d]=%p %@>\n",
|
|
|
|
|
self,
|
|
|
|
|
NSCountHashTable(_unprocessedChanges),
|
|
|
|
|
_unprocessedChanges,
|
|
|
|
|
NSStringFromHashTable(_unprocessedChanges),
|
|
|
|
|
NSCountHashTable(_unprocessedDeletes),
|
|
|
|
|
_unprocessedDeletes,
|
|
|
|
|
NSStringFromHashTable(_unprocessedDeletes),
|
|
|
|
|
NSCountHashTable(_unprocessedInserts),
|
|
|
|
|
_unprocessedInserts,
|
|
|
|
|
NSStringFromHashTable(_unprocessedInserts)];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*)objectsDescription
|
|
|
|
|
{
|
|
|
|
|
NSString *desc;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
desc = [NSString stringWithFormat: @"<%p:\nchangedObjects [nb:%d]=%p %@\n\ndeletedObjects [nb:%d]=%p %@\n\ninsertedObjects [nb:%d]=%p %@>\n",
|
|
|
|
|
self,
|
|
|
|
|
NSCountHashTable(_changedObjects),
|
|
|
|
|
_changedObjects,
|
|
|
|
|
NSStringFromHashTable(_changedObjects),
|
|
|
|
|
NSCountHashTable(_deletedObjects),
|
|
|
|
|
_deletedObjects,
|
|
|
|
|
NSStringFromHashTable(_deletedObjects),
|
|
|
|
|
NSCountHashTable(_insertedObjects),
|
|
|
|
|
_insertedObjects,
|
|
|
|
|
NSStringFromHashTable(_insertedObjects)];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// To support multithreaded operation
|
|
|
|
|
@implementation EOEditingContext(EOMultiThreaded)
|
|
|
|
|
|
|
|
|
|
+ (void)setEOFMultiThreadedEnabled: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)tryLock
|
|
|
|
|
{
|
|
|
|
|
BOOL tryLock = NO;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
tryLock = [_lock tryLock];
|
|
|
|
|
|
|
|
|
|
if (tryLock)
|
|
|
|
|
_lockCount++;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return tryLock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)lock
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
[_lock lock];
|
|
|
|
|
_lockCount++;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)unlock
|
|
|
|
|
{
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
_lockCount--;
|
|
|
|
|
[_lock unlock];
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _assertSafeMultiThreadedAccess: (SEL)param0
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd]; //TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
// Informations
|
|
|
|
|
@implementation EOEditingContext(EOEditingContextInfo)
|
|
|
|
|
|
|
|
|
|
- (NSDictionary*)unprocessedInfo
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *infoDict = nil;
|
|
|
|
|
NSHashTable *hashTables[3] = { _unprocessedChanges,
|
|
|
|
|
_unprocessedDeletes,
|
|
|
|
|
_unprocessedInserts };
|
|
|
|
|
NSMutableArray *objectsForInfo[3] = { [NSMutableArray array], //inserted
|
|
|
|
|
[NSMutableArray array], //deleted
|
|
|
|
|
[NSMutableArray array] }; //updated
|
|
|
|
|
id object;
|
|
|
|
|
int which;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
for (which = 0; which < 3; which++)
|
|
|
|
|
{
|
|
|
|
|
NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator)))
|
|
|
|
|
{
|
|
|
|
|
NSString *info = [NSString stringWithFormat: @"%@ (%p)",
|
|
|
|
|
[[object entity] name],
|
|
|
|
|
object];
|
|
|
|
|
|
|
|
|
|
[objectsForInfo[which] addObject: info];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
infoDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
2003-03-21 20:41:07 +00:00
|
|
|
|
objectsForInfo[0], @"update",
|
2002-11-15 22:57:05 +00:00
|
|
|
|
objectsForInfo[1], @"delete",
|
2003-03-21 20:41:07 +00:00
|
|
|
|
objectsForInfo[2], @"insert",
|
2002-11-15 22:57:05 +00:00
|
|
|
|
nil, nil];
|
|
|
|
|
|
|
|
|
|
NSDebugMLog(@"infoDict=%@", infoDict);
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return infoDict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDictionary*)pendingInfo
|
|
|
|
|
{
|
|
|
|
|
NSDictionary *infoDict = nil;
|
|
|
|
|
NSHashTable *hashTables[3] = { _insertedObjects,
|
|
|
|
|
_deletedObjects,
|
|
|
|
|
_changedObjects };
|
|
|
|
|
NSMutableArray *objectsForInfo[3] = { [NSMutableArray array], //inserted
|
|
|
|
|
[NSMutableArray array], //deleted
|
|
|
|
|
[NSMutableArray array] }; //updated
|
|
|
|
|
id object;
|
|
|
|
|
int which;
|
|
|
|
|
|
|
|
|
|
EOFLOGObjectFnStart();
|
|
|
|
|
|
|
|
|
|
for (which = 0; which < 3; which++)
|
|
|
|
|
{
|
|
|
|
|
NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]);
|
|
|
|
|
|
|
|
|
|
while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator)))
|
|
|
|
|
{
|
|
|
|
|
NSString *info = [NSString stringWithFormat: @"%@ (%p)",
|
|
|
|
|
[[object entity] name],
|
|
|
|
|
object];
|
|
|
|
|
|
|
|
|
|
[objectsForInfo[which] addObject: info];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
infoDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
objectsForInfo[0], @"inserted",
|
|
|
|
|
objectsForInfo[1], @"deleted",
|
|
|
|
|
objectsForInfo[2], @"updated",
|
|
|
|
|
nil, nil];
|
|
|
|
|
|
|
|
|
|
NSDebugMLog(@"infoDict=%@", infoDict);
|
|
|
|
|
EOFLOGObjectFnStop();
|
|
|
|
|
|
|
|
|
|
return infoDict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|