|
|
1.1 root 1: /*--------------------------------------------------------------------------
2: *
3: * You may freely copy, distribute, and reuse the code in this example.
4: * SHL Systemhouse disclaims any warranty of any kind, expressed or
5: * implied, as to its fitness for any particular use.
6: *
7: *
8: * QueryController
9: *
10: * Inherits From: NSObject
11: *
12: * Conforms To: None.
13: *
14: * Declared In: QueryController.h
15: *
16: *
17: *------------------------------------------------------------------------*/
18: #import "QueryController.h"
19: #import "EOQualifierContentsCategory.h"
20:
21:
22:
23:
24: @implementation QueryController
25:
26:
27: /*--------------------------------------------------------------------------
28: * Model file reading and preparation for query building
29: *------------------------------------------------------------------------*/
30: - _setUpForModelFile: (NSString *)aFilepath
31: {
32: id model = [[EOModel allocWithZone: NULL]
33: initWithContentsOfFile: aFilepath];
34:
35: /*----------------------------------------------------------------------
36: * create adaptor with specifics contained in the model (server, etc.)
37: *--------------------------------------------------------------------*/
38: if (adaptor) [adaptor autorelease];
39: adaptor = [[EOAdaptor adaptorWithModel: model] retain];
40: [model autorelease];
41:
42: /*----------------------------------------------------------------------
43: * set up database pieces to allow transactions, qualifiers, etc.
44: *--------------------------------------------------------------------*/
45: if (database) [database autorelease];
46: database = [[EODatabase allocWithZone: [self zone]]
47: initWithAdaptor: adaptor];
48:
49: if (dbContext) [dbContext autorelease];
50: dbContext = [[EODatabaseContext alloc] initWithDatabase: database];
51:
52: if (dbChannel) [dbChannel autorelease];
53: dbChannel = [[EODatabaseChannel alloc] initWithDatabaseContext: dbContext];
54:
55: /*----------------------------------------------------------------------
56: * open the channel and turn on debug to see SQL in console
57: *--------------------------------------------------------------------*/
58: if (! [dbChannel openChannel]) {
59: NSLog(@"database channel could not be opened.");
60: }
61: [[dbChannel adaptorChannel] setDebugEnabled:YES];
62:
63: entity = nil;
64:
65: [self clearQualifier:nil];
66: [[qualifierBrowser matrixInColumn:0] renewRows:0 cols:0];
67: [[qualifierBrowser matrixInColumn:0] sizeToCells];
68: [qualifierBrowser display];
69: return self;
70: }
71:
72:
73: /*--------------------------------------------------------------------------
74: * IconWell delegate method
75: *------------------------------------------------------------------------*/
76: - dragSource:dragSource didDropOnIconWell:sender
77: {
78: [modelPath setStringValue: (const char *)[sender path]];
79: [self _setUpForModelFile: [NSString stringWithCString:
80: (char *)[sender path]]];
81:
82: [[browser loadColumnZero] display];
83: [window makeKeyAndOrderFront: self];
84:
85: return self;
86: }
87:
88:
89: /*--------------------------------------------------------------------------
90: * Application delegation
91: *------------------------------------------------------------------------*/
92: - appDidInit: sender
93: {
94: qualifier = nil;
95: dataSource = nil;
96: controller = nil;
97: dbContext = nil;
98: dbChannel = nil;
99:
100: [qualifierOperation setEmptySelectionEnabled:YES];
101: [qualifierOperation selectCellAt:-1:-1];
102: [window makeKeyAndOrderFront: self];
103: return self;
104: }
105:
106:
107: /*--------------------------------------------------------------------------
108: * Query Actions
109: *------------------------------------------------------------------------*/
110: - performQuery:sender
111: {
112: id selection = [[NSMutableArray allocWithZone:NULL] init];
113: id selectedCells = [[List alloc] init];
114: int countSelected, iterator;
115: const char *cString;
116:
117: /*----------------------------------------------------------------------
118: * get attribute names to be selected and browsed
119: *--------------------------------------------------------------------*/
120: [[browser matrixInColumn:1] getSelectedCells:selectedCells];
121: countSelected = [selectedCells count];
122:
123: if (countSelected == 0) {
124: [selectedCells free];
125: selectedCells = [[browser matrixInColumn:1] cellList];
126: countSelected = [selectedCells count];
127: }
128:
129: /*----------------------------------------------------------------------
130: * transfer info from a NS3.2 list to a NS3.3NSArray
131: *--------------------------------------------------------------------*/
132: for (iterator = 0; iterator < countSelected; iterator++) {
133: cString = [(Cell *)[selectedCells objectAt: iterator] stringValue];
134: [(NSMutableArray *)selection addObject:
135: [NSString stringWithCString: cString]];
136: }
137:
138: /*----------------------------------------------------------------------
139: * assure current entity
140: *--------------------------------------------------------------------*/
141: cString = [(Cell *)[[browser matrixInColumn:0] selectedCell] stringValue];
142: entity = [[adaptor model] entityNamed:
143: [NSString stringWithCString: cString]];
144:
145: /*----------------------------------------------------------------------
146: * if qualifier is not defined, create an unqualified fetch.
147: *--------------------------------------------------------------------*/
148: if (qualifier == nil)
149: qualifier = [entity qualifier];
150:
151: /*----------------------------------------------------------------------
152: * call method to handle fetch and reporting thru NXTableView
153: *--------------------------------------------------------------------*/
154: [self fetchAndDisplay:selection inEntity:entity
155: withQualifier:qualifier];
156:
157: return self;
158: }
159:
160:
161: - (void) fetchAndDisplay:(NSArray *)attributes inEntity:(EOEntity *)anEntity
162: withQualifier:(EOQualifier *)aQualifier
163: {
164: unsigned int count, iterator;
165:
166: [resultWindow disableDisplay];
167:
168: /*----------------------------------------------------------------------
169: * if not the first query, we need to change dataSources. The entity
170: * may be different from the previous query.
171: *--------------------------------------------------------------------*/
172: if (dataSource) [dataSource autorelease];
173:
174: dataSource = [[EODatabaseDataSource allocWithZone:[self zone]]
175: initWithDatabaseChannel:dbChannel
176: entityNamed:[anEntity name]];
177: /*----------------------------------------------------------------------
178: * get a new controller with the new dataSource
179: *--------------------------------------------------------------------*/
180: controller = [[EOController allocWithZone: [self zone]]
181: initWithDataSource: dataSource];
182:
183: /*----------------------------------------------------------------------
184: * delete all current columns in the table view
185: *--------------------------------------------------------------------*/
186: count = [resultTable columnCount];
187: for (iterator = count; iterator > 0; iterator--)
188: [resultTable removeColumnAt: iterator-1];
189: [(NXTableView *)resultTable setDataSource:nil];
190:
191: /*----------------------------------------------------------------------
192: * iterate through the desired select attributes and build columns for
193: * each in the tableView.
194: *--------------------------------------------------------------------*/
195: count = [attributes count];
196: for (iterator = 0; iterator < count; iterator ++) {
197: id association;
198: id attribute = [anEntity attributeNamed:
199: [attributes objectAtIndex:iterator]];
200:
201: [resultTable addColumn:attribute withTitle:
202: [[(EOAttribute *)attribute name] cString]];
203:
204: /*----------------------------------------------------------------------
205: * create a new association for each of these attribute/column pairs
206: *--------------------------------------------------------------------*/
207: association = [[EOColumnAssociation allocWithZone: [self zone]]
208: initWithController:controller key: [(EOAttribute *)attribute name]
209: destination:[resultTable columnAt:iterator]];
210:
211: [association setTableView:resultTable];
212: [controller addAssociation: association];
213: [association autorelease];
214: }
215:
216: /*----------------------------------------------------------------------
217: * set the qualifier for the fetch.
218: *--------------------------------------------------------------------*/
219: [dataSource setQualifier: aQualifier];
220:
221: /*----------------------------------------------------------------------
222: * Start a transaction, do the fetch, rollback the transaction (a fetch
223: * doesn't need to commit anything) have the values filled to the
224: * tableView via the columnAssociations.
225: *--------------------------------------------------------------------*/
226: [dbContext beginTransaction];
227:
228: if (! [controller fetch])
229: NSLog(@"controller fetch failed.");
230:
231: [dbContext rollbackTransaction];
232:
233: /*----------------------------------------------------------------------
234: * Redisplay everything...
235: *--------------------------------------------------------------------*/
236: [resultWindow reenableDisplay];
237: [controller redisplay];
238: [resultWindow makeKeyAndOrderFront:self];
239: return;
240: }
241:
242:
243: - (int) browser:aBrowser fillMatrix:aMatrix inColumn:(int)aColumn
244: {
245: int iterator = 0, entryCount = 0;
246: id contents = nil;
247: id enumerator, current;
248:
249: /*----------------------------------------------------------------------
250: * Fill qualifier browser with the attributes of the selected entity;
251: * this is the same list as in the second column of the first browser.
252: *--------------------------------------------------------------------*/
253: if (aBrowser == qualifierBrowser) {
254: id selectedEntity;
255:
256: iterator = 0;
257: if ([browser selectedColumn] < 0)
258: return 0;
259:
260: selectedEntity = [NSString stringWithCString:
261: [(Cell *)[[browser matrixInColumn:0] selectedCell]
262: stringValue]];
263: contents = [[[adaptor model] entityNamed: selectedEntity] attributes];
264: entity = nil;
265:
266: entryCount = [contents count];
267: [aMatrix renewRows: entryCount cols: 1];
268:
269: enumerator = [contents objectEnumerator];
270: while ((current = [enumerator nextObject]) != nil) {
271:
272: [[[aMatrix cellAt: iterator++ : 0]
273: setStringValue: [[(EOAttribute *)current name] cString]]
274: setLeaf: YES];
275: }
276: return entryCount;
277: }
278:
279: /*----------------------------------------------------------------------
280: * The main entity attribute browser with two columns. One selects the
281: * entity for the query the other the attributes to be selected. Note
282: * that since we're using the EODatabaseAdaptor (instead of the
283: * EOChannelAdaptor, we actually select the entire object, but only these
284: * fields will be associated with the tableView.
285: *
286: * Reset query qualifiers for new entity
287: *--------------------------------------------------------------------*/
288: [qualifier autorelease];
289: [qualifierText setStringValue: ""];
290: [queryText setStringValue: ""];
291:
292: if (aColumn == 0)
293: contents = [[adaptor model] entities];
294:
295: else if (aColumn == 1) {
296: id selectedEntity;
297:
298: selectedEntity = [NSString stringWithCString:
299: [(Cell *)[[aBrowser matrixInColumn:0] selectedCell] stringValue]];
300: contents = [[[adaptor model] entityNamed: selectedEntity] attributes];
301: entity = nil;
302: }
303:
304: entryCount = [contents count];
305: [aMatrix renewRows: entryCount cols: 1];
306:
307: enumerator = [contents objectEnumerator];
308: while ((current = [enumerator nextObject]) != nil) {
309:
310: [[[aMatrix cellAt: iterator : 0]
311: setStringValue: [[(EOEntity *)current name] cString]]
312: setLeaf: aColumn == 1 ];
313: iterator++;
314: }
315:
316: if (aColumn == 1)
317: [[qualifierBrowser loadColumnZero] display];
318:
319: return entryCount;
320: }
321:
322:
323: - selectOperation:sender
324: {
325: int selectedOp;
326: id opString = nil;
327: int selection;
328:
329: selectedOp = [[qualifierOperation selectedCell] tag];
330:
331: if (selectedOp == 0) opString = @"<";
332: else if (selectedOp == 1) opString = @"<=";
333: else if (selectedOp == 2) opString = @">";
334: else if (selectedOp == 3) opString = @">=";
335: else if (selectedOp == 4) opString = @"=";
336: else if (selectedOp == 5) opString = @"<>";
337:
338:
339: [qualifierText setStringValue:
340: [[NSString stringWithFormat:@"%s%s ",
341: [(TextField *)qualifierText stringValue],
342: [opString cString]] cString]];
343:
344: selection = strlen([(TextField *)qualifierText stringValue]);
345: [qualifierText selectText:nil];
346:
347:
348: return self;
349: }
350:
351:
352: - selectAttribute:sender
353: {
354: id selectedCell;
355: EOAttribute *newAttribute;
356:
357: if (entity == nil) {
358: const char *entityName;
359:
360: entityName = [(Cell *)[[browser matrixInColumn: 0]
361: selectedCell] stringValue];
362: entity = [[adaptor model] entityNamed:
363: [NSString stringWithCString: entityName]];
364: }
365:
366: if ((selectedCell = [qualifierBrowser selectedCell])) {
367: id newString;
368:
369: newAttribute = [entity attributeNamed:
370: [NSString stringWithCString:[(Cell *)selectedCell stringValue]]];
371:
372: /*----------------------------------------------------------------------
373: * Get the name internal to the database; if it is a column, get the
374: * column name, otherwise, it is a complex value (a flattened attribute)
375: * so get the description.
376: *--------------------------------------------------------------------*/
377: newString = [NSString stringWithFormat: @"%s%s ",
378: [(TextField *)qualifierText stringValue],
379: [newAttribute columnName] ?
380: [(NSString *)[newAttribute columnName] cString] :
381: [(NSString *)[newAttribute definition] cString]];
382:
383: [qualifierText setStringValue: [newString cString]];
384: [qualifierText selectText: nil];
385:
386: }
387:
388: return self;
389: }
390:
391:
392: - replaceQualifier: sender
393: {
394: if (qualifier) [qualifier autorelease];
395:
396: if (entity == nil) {
397: const char *entityName;
398:
399: entityName = [(Cell *)[[browser matrixInColumn: 0]
400: selectedCell] stringValue];
401: if (! entityName) {
402: NXRunAlertPanel("Query Builder",
403: "A model file must be present before a query is possible.",
404: NULL, NULL, NULL);
405: return nil;
406: }
407:
408: entity = [[adaptor model] entityNamed:
409: [NSString stringWithCString: entityName]];
410: }
411:
412: qualifier = [[EOQualifier allocWithZone:[self zone]]
413: initWithEntity:entity
414: qualifierFormat: [NSString stringWithCString:
415: [(TextField *)qualifierText stringValue]]];
416:
417: if ([negator state]) [qualifier negate];
418:
419: [negator setState: 0];
420: [queryText setStringValue:[[qualifier contents] cString]];
421: [qualifierText setStringValue:""];
422: [qualifierText selectText: nil];
423: [qualifierOperation selectCellAt:-1:-1];
424:
425:
426: return self;
427: }
428:
429:
430: - appendAND: sender
431: {
432: id newQualifier;
433:
434: if (entity == nil) {
435: const char *entityName;
436:
437: entityName = [(Cell *)[[browser matrixInColumn: 0]
438: selectedCell] stringValue];
439: if (! entityName) {
440: NXRunAlertPanel("Query Builder",
441: "A model file must be present before a query is possible.",
442: NULL, NULL, NULL);
443: return nil;
444: }
445:
446: entity = [[adaptor model] entityNamed:
447: [NSString stringWithCString: entityName]];
448: }
449:
450:
451: newQualifier = [[EOQualifier allocWithZone:[self zone]]
452: initWithEntity:entity
453: qualifierFormat: [NSString stringWithCString:
454: [(TextField *)qualifierText stringValue]]];
455:
456: /*----------------------------------------------------------------------
457: * If the qualifier is to be negated...
458: *--------------------------------------------------------------------*/
459: if ([negator state]) [newQualifier negate];
460:
461: /*----------------------------------------------------------------------
462: * AND the new qualifier with the previous one
463: *--------------------------------------------------------------------*/
464: [qualifier conjoinWithQualifier: newQualifier];
465:
466: [newQualifier autorelease];
467:
468: [negator setState: 0];
469: [queryText setStringValue:[[qualifier contents] cString]];
470: [qualifierText setStringValue:""];
471: [qualifierText selectText: nil];
472: [qualifierOperation selectCellAt:-1:-1];
473:
474:
475: return self;
476: }
477:
478:
479: - appendOR: sender
480: {
481: id newQualifier;
482:
483: if (entity == nil) {
484: const char *entityName;
485:
486: entityName = [(Cell *)[[browser matrixInColumn: 0]
487: selectedCell] stringValue];
488: if (! entityName) {
489: NXRunAlertPanel("Query Builder",
490: "A model file must be present before a query is possible.",
491: NULL, NULL, NULL);
492: return nil;
493: }
494:
495: entity = [[adaptor model] entityNamed:
496: [NSString stringWithCString: entityName]];
497: }
498:
499:
500: newQualifier = [[EOQualifier allocWithZone:[self zone]]
501: initWithEntity:entity
502: qualifierFormat: [NSString stringWithCString:
503: [(TextField *)qualifierText stringValue]]];
504:
505: /*----------------------------------------------------------------------
506: * If the qualifier is to be negated...
507: *--------------------------------------------------------------------*/
508: if ([negator state]) [newQualifier negate];
509:
510: /*----------------------------------------------------------------------
511: * OR the new qualifier with the previous one.
512: *--------------------------------------------------------------------*/
513: [qualifier disjoinWithQualifier: newQualifier];
514:
515: [newQualifier autorelease];
516:
517: [negator setState: 0];
518: [queryText setStringValue:[[qualifier contents] cString]];
519: [qualifierText setStringValue:""];
520: [qualifierText selectText: nil];
521: [qualifierOperation selectCellAt:-1:-1];
522:
523:
524: return self;
525: }
526:
527:
528: - clearQualifier: sender
529: {
530: [qualifier autorelease];
531: qualifier = nil;
532: [negator setState: 0];
533: [queryText setStringValue:""];
534: [qualifierText setStringValue:""];
535: [qualifierText selectText:nil];
536: [qualifierOperation selectCellAt:-1:-1];
537:
538: return self;
539: }
540:
541:
542: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.