|
|
1.1 root 1: #import "UniqueKey.h"
2: #import "Projects.h"
3:
4:
5: static BOOL _Debug = YES;
6:
7: @implementation Projects
8:
9: /******************************************************************************
10: * Create two instances of the UniqueKey object to grab blocks of <count> keys for
11: * our use during inserts. The count is set low so you can see the SQL reserve
12: * blocks of keys. Up the count to something larger for it to be of use.
13: *
14: * The login information (connection dictionary) in the model has been blanked out,
15: * since you may elect to have the tables in some database other than PEOPLE, so we
16: * elect to run a login panel. Once the login is complete we can get the
17: * connection dictionary from the adaptor and use that information to allow
18: * UniqueKey to login and create its separate connection for key reservation.
19: *
20: * Note the content views of the employee and project boxes and paste in the
21: * default content.
22: ******************************************************************************/
23: - appDidInit:sender
24: {
25: EOAdaptor *eoAdaptor;
26:
27: dbChannel = [[(id)[employeeController dataSource] databaseChannel] retain];
28: dbContext = [[dbChannel databaseContext] retain];
29:
30: if(_Debug) [[dbChannel adaptorChannel] setDelegate:self];
31:
32: projectEntity = [[(id)[projectController dataSource] entity] retain];
33: employeeEntity = [[(id)[employeeController dataSource] entity] retain];
34: empProjectEntity = [[(id)[projectEntity relationshipNamed:@"toEmpProjects"] destinationEntity] retain];
35: empProjectDDS = [[EODatabaseDataSource alloc] initWithDatabaseChannel: dbChannel
36: entityNamed: [empProjectEntity name]];
37: eoAdaptor = [[[dbChannel adaptorChannel] adaptorContext] adaptor];
38: if(![eoAdaptor runLoginPanelAndValidateConnectionDictionary]) [NXApp terminate:self];
39: [UniqueKey setConnectionDictionary:[eoAdaptor connectionDictionary]];
40:
41: projectUniqueKey = [[[UniqueKey alloc] initWithEntity:projectEntity count:5] retain];
42: employeeUniqueKey = [[[UniqueKey alloc] initWithEntity:employeeEntity count:5] retain];
43: if(!projectUniqueKey || !employeeUniqueKey) [NXApp terminate:self];
44:
45: [self setFetchOrderFor:projectController with:@"ProjectName" order:EOAscendingOrder];
46: [self setFetchOrderFor:addProjectsForEmployeeController with:@"ProjectName" order:EOAscendingOrder];
47: [self setFetchOrderFor:employeeController with:@"LastName" order:EOAscendingOrder];
48: [self setFetchOrderFor:addEmployeesOnProjectController with:@"LastName" order:EOAscendingOrder];
49:
50: [addProjectsForEmployeeController setSelectsFirstObjectAfterFetch:NO];
51: [addEmployeesOnProjectController setSelectsFirstObjectAfterFetch:NO];
52:
53: inspectorWindow=[swapBox window];
54: [self projectInspector:nil]; // swap in the project content view
55: [[inspectorWindow center] makeKeyAndOrderFront:nil];
56: return self;
57: }
58:
59:
60: /******************************************************************************
61: * Set a controller's data source to fetch sorted by a given attribute name
62: * and order.
63: ******************************************************************************/
64: - setFetchOrderFor:(EOController*)controller with:(NSString*)attributeName order:(EOOrdering)order
65: {
66: id dataSource = [controller dataSource];
67: id attribute = [[dataSource entity] attributeNamed:attributeName];
68: NSArray *orderArray;
69:
70: orderArray = [NSArray arrayWithObject:
71: [EOAttributeOrdering attributeOrderingWithAttribute:attribute ordering:order]];
72: [dataSource setFetchOrder:orderArray];
73: return self;
74: }
75:
76:
77: /******************************************************************************
78: * Accept the users selection for either the Employee or Project inspector. Swap
79: * in the appropriate content view.
80: ******************************************************************************/
81: - employeeInspector:sender
82: {
83: [inspectorWindow disableFlushWindow];
84: [swapBox setContentView:[employeeBox contentView]];
85: [employeeController fetch];
86: [swapBox display];
87: [[inspectorWindow reenableFlushWindow] flushWindowIfNeeded];
88: return self;
89: }
90:
91: - projectInspector:sender
92: {
93: [inspectorWindow disableFlushWindow];
94: [swapBox setContentView:[projectBox contentView]];
95: [projectController fetch];
96: [swapBox display];
97: [[inspectorWindow reenableFlushWindow] flushWindowIfNeeded];
98: return self;
99: }
100:
101:
102: /******************************************************************************
103: * Utility to create an intermediate table empProject EOGenericRecord.
104: ******************************************************************************/
105: - createEmpProject:(NSNumber*)empId:(NSNumber*)projectId
106: {
107: EOGenericRecord *empProject = [empProjectDDS createObject];
108:
109: [empProject setObject:projectId forKey:@"ProjectId"];
110: [empProject setObject:empId forKey:@"EmpId"];
111: return empProject;
112: }
113:
114:
115: /******************************************************************************
116: * Bring up the add employee selection panel and start a modal session. Construct
117: * and 'otherEmployees' qualifier to select employees that do not already appear
118: * in the EmployeesOnProject detail view.
119: ******************************************************************************/
120: - addEmployeesOnProject:sender
121: {
122: EOGenericRecord *project = [(id)[employeesOnProjectController dataSource] masterObject];
123: NSNumber *projectId = [project objectForKey:@"ProjectId"];
124: EOQualifier *otherEmployees;
125: NSString *qualifierString;
126:
127: qualifierString = [NSString stringWithFormat:
128: @"EmpId not in (SELECT z1.EMP_ID FROM EMPLOYEE z1, EMP_PROJECT z2 "
129: @"WHERE z1.EMP_ID = z2.EMP_ID AND z2.PROJECT_ID = %@)",projectId];
130:
131: otherEmployees = [[[EOQualifier alloc]
132: initWithEntity:employeeEntity qualifierFormat:qualifierString] autorelease];
133:
134: [(id)[addEmployeesOnProjectController dataSource] setQualifier:otherEmployees];
135: [addEmployeesOnProjectController clearSelection];
136: [addEmployeesOnProjectController fetch];
137: [[addEmployeesPanel center] makeKeyAndOrderFront:nil];
138: [NXApp runModalFor:addEmployeesPanel];
139: [addEmployeesPanel orderOut:self];
140: [projectController fetch];
141: return self;
142: }
143:
144: - addEmployeesOnProjectOK:sender
145: {
146: NSArray *eArray;
147: NSEnumerator *eEnumerator;
148: EOGenericRecord *project;
149: NSNumber *projectId;
150: EOGenericRecord *employee;
151: EOGenericRecord *empProject;
152:
153: eArray = [addEmployeesOnProjectController selectedObjects];
154: eEnumerator = [eArray objectEnumerator];
155: project = [(id)[employeesOnProjectController dataSource] masterObject];
156: projectId = [project objectForKey:@"ProjectId"];
157: [dbContext beginTransaction];
158: while((employee = [eEnumerator nextObject]) != nil) {
159: empProject = [self createEmpProject:[employee objectForKey:@"EmpId"]:projectId];
160: [dbChannel insertObject:empProject];
161: }
162: [dbContext commitTransaction];
163: [NXApp stopModal];
164: return self;
165: }
166:
167:
168: /******************************************************************************
169: * Bring up the add project selection panel and start a modal session. Construct
170: * and 'otherProjects' qualifier to select project that do not already appear
171: * in the ProjectsForEmployee detail view. We use an imbedded select here with
172: * '.' chars in the qualifier string. These names will not be converted, since they
173: * contain '.' chars, so we have the ability to write qualifiers that
174: * reference external names it we like.
175: ******************************************************************************/
176: - addProjectsForEmployee:sender
177: {
178: EOGenericRecord *employee = [(id)[projectsForEmployeeController dataSource] masterObject];
179: NSNumber *empId = [employee objectForKey:@"EmpId"];
180: EOQualifier *otherProjects;
181: NSString *qualifierString;
182:
183: qualifierString = [NSString stringWithFormat:
184: @"ProjectId not in (SELECT z1.PROJECT_ID FROM PROJECT z1, EMP_PROJECT z2 "
185: @"WHERE z1.PROJECT_ID = z2.PROJECT_ID AND z2.EMP_ID = %@)",empId];
186:
187: otherProjects = [[[EOQualifier alloc]
188: initWithEntity:projectEntity qualifierFormat:qualifierString] autorelease];
189:
190: [(id)[addProjectsForEmployeeController dataSource] setQualifier:otherProjects];
191: [addProjectsForEmployeeController clearSelection];
192: [addProjectsForEmployeeController fetch];
193: [[addProjectsPanel center] makeKeyAndOrderFront:nil];
194: [NXApp runModalFor:addProjectsPanel];
195: [addProjectsPanel orderOut:self];
196: [employeeController fetch];
197: return self;
198: }
199:
200: - addProjectsForEmployeeOK:sender
201: {
202: NSArray *pArray;
203: NSEnumerator *pEnumerator;
204: EOGenericRecord *employee;
205: NSNumber *empId;
206: EOGenericRecord *project;
207: EOGenericRecord *empProject;
208:
209: pArray = [addProjectsForEmployeeController selectedObjects];
210: pEnumerator = [pArray objectEnumerator];
211: employee = [(id)[projectsForEmployeeController dataSource] masterObject];
212: empId = [employee objectForKey:@"EmpId"];
213:
214: [dbContext beginTransaction];
215: while((project = [pEnumerator nextObject]) != nil) {
216: empProject = [self createEmpProject:empId:[project objectForKey:@"ProjectId"]];
217: [dbChannel insertObject:empProject];
218: }
219: [dbContext commitTransaction];
220: [NXApp stopModal];
221: return self;
222: }
223:
224:
225: /******************************************************************************
226: * Delete the intermediate table entries for the selected employee. To do this we
227: * get the selected master object and ask it for the enumerator of empProject
228: * objects. Since each empProject object can be asked objectForKey:@"Employee", we
229: * see if that empProject object has a corresponding employee in the selected employee
230: * array (eArray). We choose to use the method indexOfObjectIdenticalTo: to do the
231: * check since it uses pointer equality. This works because object uniquing is
232: * enabled by default.
233: ******************************************************************************/
234: - removeSelectedEmployeesOnProject:sender
235: {
236: NSArray *eArray;
237: EOGenericRecord *project;
238: NSEnumerator *epEnumerator;
239: EOGenericRecord *empProject;
240:
241: eArray = [employeesOnProjectController selectedObjects];
242: project = [(id)[employeesOnProjectController dataSource] masterObject];
243: epEnumerator = [[project objectForKey:@"toEmpProjects"] objectEnumerator];
244:
245: [dbContext beginTransaction];
246: while((empProject=[epEnumerator nextObject]) != nil)
247: if([eArray indexOfObjectIdenticalTo:[empProject objectForKey:@"toEmployee"]]!=NSNotFound)
248: [dbChannel deleteObject:empProject];
249: [dbContext commitTransaction];
250: [projectController fetch];
251: return self;
252: }
253:
254:
255: /******************************************************************************
256: * Delete the intermediate table entries for the selected project. To do this we
257: * get the selected master object and ask it for the enumerator of empProject
258: * objects. Since each empProject object can be asked objectForKey:@"Project", we
259: * see if that empProject object has a corresponding project in the selected project
260: * array (pArray). We choose to use the method indexOfObjectIdenticalTo: to do the
261: * check since it uses pointer equality. This works because object uniquing is
262: * enabled by default.
263: ******************************************************************************/
264: - removeSelectedProjectsForEmployee:sender
265: {
266: NSArray *pArray;
267: EOGenericRecord *employee;
268: NSEnumerator *epEnumerator;
269: EOGenericRecord *empProject;
270:
271: pArray = [projectsForEmployeeController selectedObjects];
272: employee = [(id)[projectsForEmployeeController dataSource] masterObject];
273: epEnumerator = [[employee objectForKey:@"toEmpProjects"] objectEnumerator];
274:
275: [dbContext beginTransaction];
276: while((empProject=[epEnumerator nextObject]) != nil)
277: if([pArray indexOfObjectIdenticalTo:[empProject objectForKey:@"toProject"]]!=NSNotFound)
278: [dbChannel deleteObject:empProject];
279: [dbContext commitTransaction];
280: [employeeController fetch];
281: return self;
282: }
283:
284:
285: /******************************************************************************
286: * Generate unique keys for the new object. Use the instance of UniqueKey
287: * to dole out a key from its internal buffer. The UniqueKey object has its
288: * own channel to the DB which it uses to allocate blocks of keys.
289: ******************************************************************************/
290: - (BOOL)controller:(EOController *)controller willInsertObject:object atIndex: (unsigned)newIndex
291: {
292: if(controller==employeeController) {
293: NSArray *emptyArray1 = [[[NSArray alloc] init] autorelease];
294: NSArray *emptyArray2 = [[[NSArray alloc] init] autorelease];
295: NSNumber *empId = [NSNumber numberWithInt:[employeeUniqueKey nextKey]];
296:
297: [object setObject:empId forKey:@"EmpId"];
298: [object setObject:@"<FirstName>" forKey:@"FirstName"];
299: [object setObject:@"<LastName>" forKey:@"LastName"];
300: [object setObject:@"<Phone>" forKey:@"Phone"];
301: [object setObject:emptyArray1 forKey:@"toEmpProjects"];
302: [object setObject:emptyArray2 forKey:@"toProjects"];
303: return YES;
304: }
305: if(controller==projectController) {
306: NSArray *emptyArray1 = [[[NSArray alloc] init] autorelease];
307: NSArray *emptyArray2 = [[[NSArray alloc] init] autorelease];
308: NSNumber *projectId = [NSNumber numberWithInt:[projectUniqueKey nextKey]];
309:
310: [object setObject:projectId forKey:@"ProjectId"];
311: [object setObject:@"<ProjectName>" forKey:@"ProjectName"];
312: [object setObject:emptyArray1 forKey:@"toEmpProjects"];
313: [object setObject:emptyArray2 forKey:@"toEmployees"];
314: return YES;
315: }
316: return NO;
317: }
318:
319:
320: /******************************************************************************
321: * When a project or employee is deleted, make sure we delete the entry in the
322: * empProject intermediate table. Both the project and employee entities have
323: * a toEmpProjects relationship which we can use to delete the intermediate
324: * table records.
325: ******************************************************************************/
326: - (BOOL)controller:controller willDeleteObject:object
327: {
328: NSArray *epArray;
329: NSEnumerator *epEnumerator;
330: EOGenericRecord *empProject;
331:
332: // The employee and project entities have a toEmpProjects
333: // relationship to the intermediate table
334: if(controller==projectController ||
335: controller==employeeController) {
336: [dbContext beginTransaction];
337: epArray=[object objectForKey:@"toEmpProjects"];
338: epEnumerator=[epArray objectEnumerator];
339: while((empProject = [epEnumerator nextObject]) != nil)
340: [dbChannel deleteObject:empProject];
341: [dbContext commitTransaction];
342: }
343: return YES;
344: }
345:
346:
347: /******************************************************************************
348: * Echo SQL when debug is enabled.
349: ******************************************************************************/
350: - (EODelegateResponse)adaptorChannel:channel willEvaluateExpression:(NSMutableString *)expression
351: {
352: NSLog(expression);
353: return EODelegateApproves;
354: }
355:
356: - (void)dealloc
357: {
358: [dbContext release];
359: [dbChannel release];
360: [projectEntity release];
361: [employeeEntity release];
362: [empProjectEntity release];
363: [projectUniqueKey release];
364: [employeeUniqueKey release];
365: [super dealloc];
366:
367: }
368:
369: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.