|
|
1.1 root 1: /*
2: AppManager.m created by enoyau on Fri 13-Jan-1995
3:
4: You may freely copy, distribute, and reuse the code in this example.
5: NeXT disclaims any warranty of any kind, expressed or implied, as to its
6: fitness for any particular use.
7: */
8:
9: #import "AppManager.h"
10: #import "Employee.h"
11:
12: // A property added to the EMPLOYEE table in the PEOPLE demo database.
13: // This property is needed to avoid concurrent update to the same record.
14: #define lockProperty @"lock"
15:
16: @interface AppManager(private)
17: - (void)_updateDisplay;
18: @end
19:
20: @implementation AppManager(private)
21:
22: // Responsible for keeping the lock button states up-to-date and to
23: // allow/disallow editing in the tableview.
24: - (void)_updateDisplay
25: {
26: id currentSelection = [[eoController selectedObjects] objectAtIndex:0];
27:
28: BOOL isEditable = [currentSelection isEditable];
29: BOOL isLocked = [currentSelection isLocked];
30:
31: [lockButton setTitle:isLocked ? "Unlock" : "Lock"];
32: [lockButton setEnabled:(!isLocked) || isEditable];
33:
34: [tableView setTarget:isLocked ? nil : lockButton];
35: if([tableView isEditable] != isEditable) {
36: [tableView setEditable:isEditable];
37: if(!isEditable) {
38: [tableView perform:@selector(display)
39: with:nil
40: afterDelay:0
41: cancelPrevious:NO];
42: }
43: }
44: return;
45: }
46:
47: @end
48:
49: @implementation AppManager
50:
51: // This notification is sent to AppManager by the DEONotificationCenter.
52: - (void)databaseChange:(DEONotification *)notification
53: {
54: id eoObject = [notification notificationObject];
55:
56: if( !([EOFault isFault:eoObject] || [notification isLocal]) ) {
57: EODatabaseDataSource *eoDatabasedataSource;
58: EODatabaseChannel *eoDatabaseChannel;
59: EODatabaseContext *eoDatabaseContext;
60: BOOL autoTransaction = NO;
61:
62: eoDatabasedataSource =(EODatabaseDataSource*)[eoController dataSource];
63: eoDatabaseChannel = [eoDatabasedataSource databaseChannel];
64: eoDatabaseContext = [eoDatabaseChannel databaseContext];
65:
66: // refetch the EO from the database server to preserve data integrity.
67: if (![eoDatabaseContext transactionNestingLevel]) {
68: [eoDatabaseContext beginTransaction];
69: autoTransaction = YES;
70: }
71:
72: [eoDatabaseChannel refetchObject:eoObject];
73:
74: if (autoTransaction) [eoDatabaseContext commitTransaction];
75:
76: // redisplay the data. If editing is not ended, wait until it is done
77: // (by changing the selection or the state of the lock)
78: if([tableView isEditable]) {
79: needRedisplay = YES;
80: } else {
81: [eoController redisplay];
82: [self _updateDisplay];
83: }
84: }
85: return;
86: }
87:
88: // Update the lock value in the database when lock button is pressed.
89: - toggleLockOnSelection:sender
90: {
91: if([lockButton isEnabled]) {
92: id currentSelection;
93: NSArray *keys;
94: NSMutableDictionary *objectValue;
95:
96: currentSelection = [[eoController selectedObjects] objectAtIndex:0];
97: keys = [NSArray arrayWithObject:lockProperty];
98: objectValue = [[[currentSelection valuesForKeys:keys] mutableCopy] autorelease];
99:
100: if([[objectValue objectForKey:lockProperty] isEqual:[EONull null]]) {
101: [objectValue setObject:lockString forKey:lockProperty];
102: } else {
103: [objectValue setObject:[EONull null] forKey:lockProperty];
104: }
105:
106: [eoController setValues:objectValue forObject:currentSelection];
107:
108: [self _updateDisplay];
109: }
110: return self;
111: }
112: @end
113:
114: @implementation AppManager(EOControllerDelegate)
115: - (void)controllerDidChangeSelection:(EOController *)controller
116: {
117: if(needRedisplay) {
118: [eoController redisplay];
119: needRedisplay = NO;
120: }
121: [self _updateDisplay];
122: }
123: @end
124:
125: @implementation AppManager(EOApplicationDelegate)
126: - appDidInit:sender
127: {
128: EODatabaseDataSource *eoDatabaseDataSource;
129: EODatabaseChannel *eoDatabaseChannel;
130: EOAdaptorContext *eoAdaptorContext;
131:
132: eoDatabaseDataSource = [eoController dataSource];
133: eoDatabaseChannel = [eoDatabaseDataSource databaseChannel];
134: eoAdaptorContext = [[eoDatabaseChannel adaptorChannel] adaptorContext];
135:
136: // Set up as the delegate of EOController, EODatabaseChannel,
137: // and EOAdaptorContext
138: [(EOController*)eoController setDelegate:self];
139: [eoDatabaseChannel setDelegate:self]; // EO updates, inserts and deletes.
140: [eoAdaptorContext setDelegate:self]; // Transactions begin, commit or rollback.
141:
142: // Put an ImageFormatter in column 0
143: [[tableView columnAt:0] setFormatter:[[NXImageFormatter alloc] init]];
144:
145: // A double click will lock the current selection to start the
146: // editing mode
147: [tableView setTarget:lockButton];
148: [tableView setDoubleAction:@selector(performClick:)];
149:
150: // Set up the Distributed Entreprise Object notification center
151: deoNotificationCenter =
152: [[DEONotificationCenter alloc]
153: initWithDatabaseChannel:eoDatabaseChannel
154: entity:[eoDatabaseDataSource entity]];
155:
156: // Register for notification whenever objects of this entity are updated
157: [deoNotificationCenter addObserver:self
158: selector:@selector(databaseChange:)
159: notificationName:DEOUpdate
160: object:nil];
161:
162: // Update instance variables
163: transactions = [NSMutableArray new];
164: needRedisplay = NO;
165: lockString = [[NSString alloc] initWithFormat:@"%s-%@-%d",
166: NXUserName(),
167: [DEONotificationCenter localHostname],
168: NXProcessID];
169:
170: [Employee setLocalLockString:lockString];
171:
172: // Force the first fetch
173: [eoController fetch:self];
174:
175: [self _updateDisplay];
176: return self;
177: }
178:
179: - appWillTerminate:sender
180: {
181: [transactions release];
182: [lockString release];
183: [deoNotificationCenter removeObserver:self];
184: [deoNotificationCenter release];
185: return self;
186: }
187: @end
188:
189: // We keep a list of all objects updated in the current transaction
190: // and post notification of the changes when the transaction commits.
191: // A more complete implementation could also keep track of insertions
192: // and deletions.
193: @implementation AppManager(EOAdaptorContextDelegate)
194: - (void)adaptorContextDidBegin:context
195: {
196: [transactions addObject:[NSMutableArray array]];
197: }
198:
199: - (void)adaptorContextDidCommit:context
200: {
201: NSMutableDictionary *commitedTransaction = [transactions lastObject];
202: id enumerator, current;
203:
204: [transactions removeLastObject];
205: if([transactions count]) {
206: [[transactions lastObject] addObjectsFromArray:commitedTransaction];
207: } else {
208: enumerator = [commitedTransaction objectEnumerator];
209: while(current = [enumerator nextObject]) {
210: [deoNotificationCenter postNotificationName:DEOUpdate object:current];
211: }
212: }
213: }
214:
215: // If the transaction rolls back, there is no notification.
216: - (void)adaptorContextDidRollback:context
217: {
218: [transactions removeLastObject];
219: }
220:
221: @end
222:
223: @implementation AppManager(EODatabaseChannelDelegate)
224: - (void)databaseChannel:channel didUpdateObject:anEO
225: {
226: [(NSMutableArray *)[transactions lastObject] addObject:anEO];
227: }
228: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.