|
|
Sample Programs from NeXSTEP 3.3
/*
AppManager.m created by enoyau on Fri 13-Jan-1995
You may freely copy, distribute, and reuse the code in this example.
NeXT disclaims any warranty of any kind, expressed or implied, as to its
fitness for any particular use.
*/
#import "AppManager.h"
#import "Employee.h"
// A property added to the EMPLOYEE table in the PEOPLE demo database.
// This property is needed to avoid concurrent update to the same record.
#define lockProperty @"lock"
@interface AppManager(private)
- (void)_updateDisplay;
@end
@implementation AppManager(private)
// Responsible for keeping the lock button states up-to-date and to
// allow/disallow editing in the tableview.
- (void)_updateDisplay
{
id currentSelection = [[eoController selectedObjects] objectAtIndex:0];
BOOL isEditable = [currentSelection isEditable];
BOOL isLocked = [currentSelection isLocked];
[lockButton setTitle:isLocked ? "Unlock" : "Lock"];
[lockButton setEnabled:(!isLocked) || isEditable];
[tableView setTarget:isLocked ? nil : lockButton];
if([tableView isEditable] != isEditable) {
[tableView setEditable:isEditable];
if(!isEditable) {
[tableView perform:@selector(display)
with:nil
afterDelay:0
cancelPrevious:NO];
}
}
return;
}
@end
@implementation AppManager
// This notification is sent to AppManager by the DEONotificationCenter.
- (void)databaseChange:(DEONotification *)notification
{
id eoObject = [notification notificationObject];
if( !([EOFault isFault:eoObject] || [notification isLocal]) ) {
EODatabaseDataSource *eoDatabasedataSource;
EODatabaseChannel *eoDatabaseChannel;
EODatabaseContext *eoDatabaseContext;
BOOL autoTransaction = NO;
eoDatabasedataSource =(EODatabaseDataSource*)[eoController dataSource];
eoDatabaseChannel = [eoDatabasedataSource databaseChannel];
eoDatabaseContext = [eoDatabaseChannel databaseContext];
// refetch the EO from the database server to preserve data integrity.
if (![eoDatabaseContext transactionNestingLevel]) {
[eoDatabaseContext beginTransaction];
autoTransaction = YES;
}
[eoDatabaseChannel refetchObject:eoObject];
if (autoTransaction) [eoDatabaseContext commitTransaction];
// redisplay the data. If editing is not ended, wait until it is done
// (by changing the selection or the state of the lock)
if([tableView isEditable]) {
needRedisplay = YES;
} else {
[eoController redisplay];
[self _updateDisplay];
}
}
return;
}
// Update the lock value in the database when lock button is pressed.
- toggleLockOnSelection:sender
{
if([lockButton isEnabled]) {
id currentSelection;
NSArray *keys;
NSMutableDictionary *objectValue;
currentSelection = [[eoController selectedObjects] objectAtIndex:0];
keys = [NSArray arrayWithObject:lockProperty];
objectValue = [[[currentSelection valuesForKeys:keys] mutableCopy] autorelease];
if([[objectValue objectForKey:lockProperty] isEqual:[EONull null]]) {
[objectValue setObject:lockString forKey:lockProperty];
} else {
[objectValue setObject:[EONull null] forKey:lockProperty];
}
[eoController setValues:objectValue forObject:currentSelection];
[self _updateDisplay];
}
return self;
}
@end
@implementation AppManager(EOControllerDelegate)
- (void)controllerDidChangeSelection:(EOController *)controller
{
if(needRedisplay) {
[eoController redisplay];
needRedisplay = NO;
}
[self _updateDisplay];
}
@end
@implementation AppManager(EOApplicationDelegate)
- appDidInit:sender
{
EODatabaseDataSource *eoDatabaseDataSource;
EODatabaseChannel *eoDatabaseChannel;
EOAdaptorContext *eoAdaptorContext;
eoDatabaseDataSource = [eoController dataSource];
eoDatabaseChannel = [eoDatabaseDataSource databaseChannel];
eoAdaptorContext = [[eoDatabaseChannel adaptorChannel] adaptorContext];
// Set up as the delegate of EOController, EODatabaseChannel,
// and EOAdaptorContext
[(EOController*)eoController setDelegate:self];
[eoDatabaseChannel setDelegate:self]; // EO updates, inserts and deletes.
[eoAdaptorContext setDelegate:self]; // Transactions begin, commit or rollback.
// Put an ImageFormatter in column 0
[[tableView columnAt:0] setFormatter:[[NXImageFormatter alloc] init]];
// A double click will lock the current selection to start the
// editing mode
[tableView setTarget:lockButton];
[tableView setDoubleAction:@selector(performClick:)];
// Set up the Distributed Entreprise Object notification center
deoNotificationCenter =
[[DEONotificationCenter alloc]
initWithDatabaseChannel:eoDatabaseChannel
entity:[eoDatabaseDataSource entity]];
// Register for notification whenever objects of this entity are updated
[deoNotificationCenter addObserver:self
selector:@selector(databaseChange:)
notificationName:DEOUpdate
object:nil];
// Update instance variables
transactions = [NSMutableArray new];
needRedisplay = NO;
lockString = [[NSString alloc] initWithFormat:@"%s-%@-%d",
NXUserName(),
[DEONotificationCenter localHostname],
NXProcessID];
[Employee setLocalLockString:lockString];
// Force the first fetch
[eoController fetch:self];
[self _updateDisplay];
return self;
}
- appWillTerminate:sender
{
[transactions release];
[lockString release];
[deoNotificationCenter removeObserver:self];
[deoNotificationCenter release];
return self;
}
@end
// We keep a list of all objects updated in the current transaction
// and post notification of the changes when the transaction commits.
// A more complete implementation could also keep track of insertions
// and deletions.
@implementation AppManager(EOAdaptorContextDelegate)
- (void)adaptorContextDidBegin:context
{
[transactions addObject:[NSMutableArray array]];
}
- (void)adaptorContextDidCommit:context
{
NSMutableDictionary *commitedTransaction = [transactions lastObject];
id enumerator, current;
[transactions removeLastObject];
if([transactions count]) {
[[transactions lastObject] addObjectsFromArray:commitedTransaction];
} else {
enumerator = [commitedTransaction objectEnumerator];
while(current = [enumerator nextObject]) {
[deoNotificationCenter postNotificationName:DEOUpdate object:current];
}
}
}
// If the transaction rolls back, there is no notification.
- (void)adaptorContextDidRollback:context
{
[transactions removeLastObject];
}
@end
@implementation AppManager(EODatabaseChannelDelegate)
- (void)databaseChannel:channel didUpdateObject:anEO
{
[(NSMutableArray *)[transactions lastObject] addObject:anEO];
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.