|
|
1.1 root 1: /* Controller.m:
2: * You may freely copy, distribute, and reuse the code in this example.
3: * NeXT disclaims any warranty of any kind, expressed or implied, as to its
4: * fitness for any particular use.
5: *
6: * Written by Mai Nguyen, NeXT Developer Support
7: *
8: */
9:
10: #import <appkit/appkit.h>
11: #import <dbkit/dbkit.h>
12: #import <libc.h>
13: #import "Controller.h"
14:
15: /* Define localized strings */
16: #define INSTALL_MODEL NXLocalizedString("Please install SybaseDemo.dbmodela into your project directory and restart.", NULL, "Notify user that SybaseDemo.dbmodela must be installed in his project directory.")
17: #define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.")
18: #define INSERT_FAILED NXLocalizedString("Insert operation failed", NULL, "Notify user that insert operation has failed.")
19:
20: static char newAuthorID[100];
21:
22: @implementation Controller
23:
24: /* Extract the actual database and recordlist from the DBModule UI Object
25: */
26: -appDidInit:sender
27: {
28: /* Notify the user if the database can't be found */
29: if (![DBDatabase findDatabaseNamed:"SybaseDemo" connect:YES]) {
30: NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
31: return self;
32: }
33: dbDatabase = [dbModule database];
34: dbFetchGroup = [dbModule rootFetchGroup];
35: dbRecordList = [dbFetchGroup recordList];
36: recordOrder = DB_AscendingOrder;
37: dbQualifier = nil;
38:
39: /* Initialize the retrieval order to be ascending order
40: */
41: sortProp = [[dbModule entity] propertyNamed:"lastName"];
42:
43: [dbRecordList addRetrieveOrder:recordOrder for:sortProp];
44:
45: /* Assign the controller object to be the delegate of dbFetchGroup.
46: * See also the method fetchGroup:didInsertRecordAt:
47: */
48: [dbFetchGroup setDelegate:self];
49:
50: /* Assign the record list of the root fetchgroup to be the delegate
51: * of DBBinder. This is a convenient way to make sure that the proper
52: * qualifier will be used at fetch time.
53: * See also the method binderWillSelect:
54: */
55: [[dbFetchGroup recordList] setBinderDelegate:self];
56:
57: /* Create a DBValue instance to be used later for accessing data
58: * inside a record list.
59: */
60: aValue = [[DBValue alloc] init];
61:
62: [theWindow makeKeyAndOrderFront:nil];
63: return self;
64: }
65:
66: /* Change the retrieval order for the record list. To be set before pressing
67: * SELECT.
68: */
69: -changeRetrieveOrder:sender
70: {
71: recordOrder = [sender selectedTag];
72: return self;
73: }
74:
75: /* Build the DBQualifier before a SELECT operation. Note that you should give
76: * the external names as defined in dbModel for properties.
77: */
78: - buildSelectQualifier:sender
79: {
80: const char * state;
81: id stateProperty;
82:
83: state = [qualifierField stringValue];
84: if (!strcmp(state,"")) {
85: dbQualifier = nil;
86: return nil;
87: }
88: else {
89: stateProperty = [[dbModule entity] propertyNamed:"state"];
90: dbQualifier = [[DBQualifier allocFromZone:[self zone] ]
91: initForEntity:[dbModule entity]
92: fromDescription:"%@ LIKE %s", stateProperty, state];
93: }
94: return self;
95: }
96:
97: /* This method is called when the SELECT button is pressed.
98: * NOTE: If the qualifier form has a NULL string, the source is set to nil,
99: * which means that ALL records will be fetched.
100: */
101: - select:sender
102: {
103: id source;
104:
105: [self buildSelectQualifier:nil];
106: if (!dbQualifier)
107: source = nil;
108: else
109: source = [dbModule entity];
110:
111: [dbFetchGroup fetchContentsOf:source usingQualifier:dbQualifier];
112:
113: /* Update the display */
114: [self display];
115: return self;
116: }
117:
118: /* This method is called when the INSERT button is pressed. Check for blank
119: * record fields before the actual INSERT.
120: */
121: - insert:sender
122: {
123: if ([self checkInputRecord:sender]==nil)
124: NXRunAlertPanel(NULL,INSERT_FAILED, "OK", NULL, NULL);
125: else
126: [dbModule insertNewRecord:sender];
127: [self display];
128: return self;
129: }
130:
131: /* Try to highlight the newly added row based on the token "newAuthorID".
132: * This method is called everytime the SELECT button is pressed.
133: * If there is no match, the first row is highlighted by default.
134: */
135: - display
136: {
137: int rowCount, i, row;
138: id socSecProperty;
139: const char *keyValue;
140:
141: row = 0;
142: /* Search for a match only if the ID has meaningful data */
143: if ( strlen(newAuthorID) > 0 ) {
144: rowCount = [dbTableView rowCount];
145: socSecProperty = [[dbModule entity] propertyNamed:"authorID"];
146: for (i= 0; i < rowCount; i++) {
147: [dbRecordList getValue:aValue forProperty:socSecProperty at:i];
148: keyValue = (const char *)[aValue stringValue];
149: if (!strcmp(keyValue, newAuthorID)) {
150: row = i;
151: break; }
152: }
153: }
154: [dbFetchGroup setCurrentRecord:row];
155: [dbTableView display];
156: return self;
157: }
158:
159:
160:
161: /* DBFetchGroup delegate methods */
162:
163: /*
164: * This method is called at each SELECT operation.
165: */
166: - fetchGroupWillFetch:fetchGroup
167: {
168: [dbRecordList addRetrieveOrder:recordOrder for:sortProp];
169: return self;
170: }
171:
172: /*
173: * This method is called at each INSERT operation.
174: */
175:
176: - fetchGroup:fetchGroup didInsertRecordAt:(int)index
177: {
178: /* Fill in the record fields before inserting the new record */
179: [self fillNewRecordAt:index];
180: return self;
181: }
182:
183:
184: /*
185: * This delegate method is called at each SAVE operation.
186: */
187: - fetchGroupDidSave:fetchGroup
188: {
189: [self clearData];
190: return self;
191: }
192:
193: /*
194: * This binder delegate method is called at each SELECT operation so that
195: * the proper qualifier is used.
196: */
197:
198: - (BOOL)binderWillSelect:aBinder
199: {
200: [aBinder setQualifier:dbQualifier];
201: return YES;
202: }
203:
204: /* checkInputRecord
205: * Check if any input field is empty.
206: */
207: - checkInputRecord:sender
208: {
209: int i;
210: const char *inputStr;
211:
212: for ( i = 0; i < 9; i++ ) {
213: inputStr = (const char *)[formMatrix stringValueAt:i];
214: /* If the string is empty, abort the operation */
215: if ( inputStr == NULL){
216: NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
217: return nil;
218: }
219: }
220: return self;
221: }
222:
223: /* fillNewRecordAt:(int) index
224: * Method used for INSERT operation
225: * Get the user input from the form cells.
226: */
227: - fillNewRecordAt:(int)index
228: {
229: const char *inputString;
230: int contractNum;
231:
232: /* set last name */
233: inputString = (const char *)[formMatrix stringValueAt:0];
234: [aValue setStringValue:inputString];
235: [dbRecordList setValue:aValue
236: forProperty:[[dbModule entity] propertyNamed:"lastName"]
237: at:index];
238:
239: /* set first name */
240: inputString = (const char *)[formMatrix stringValueAt:1];
241: [aValue setStringValue:(const char *)inputString];
242: [dbRecordList setValue: aValue
243: forProperty: [[dbModule entity] propertyNamed:"firstName"]
244: at:index];
245:
246: /* get the ssn or author id */
247: inputString = (const char *)[formMatrix stringValueAt:2];
248: [aValue setStringValue:inputString];
249: [dbRecordList setValue:aValue
250: forProperty:[[dbModule entity] propertyNamed:"authorID"]
251: at:index];
252: strcpy( newAuthorID, inputString);
253:
254: /* set address */
255: inputString = (const char *)[formMatrix stringValueAt:3];
256: [aValue setStringValue: inputString];
257: [dbRecordList setValue: aValue
258: forProperty:[[dbModule entity] propertyNamed:"address"]
259: at:index];
260:
261: /* set city name */
262: inputString = (const char *)[formMatrix stringValueAt:4];
263: [aValue setStringValue: inputString];
264: [dbRecordList setValue: aValue
265: forProperty:[[dbModule entity] propertyNamed:"city"]
266: at:index];
267:
268: /* set state */
269: inputString = (const char *)[formMatrix stringValueAt:5];
270: [aValue setStringValue: inputString];
271: [dbRecordList setValue: aValue
272: forProperty:[[dbModule entity] propertyNamed:"state"]
273: at:index];
274:
275: /* set zip code */
276: inputString = (const char *)[formMatrix stringValueAt:6];
277: [aValue setStringValue: inputString];
278: [dbRecordList setValue: aValue
279: forProperty:[[dbModule entity] propertyNamed:"zipCode"]
280: at:index ];
281:
282: /* set phone number */
283: inputString = (const char *)[formMatrix stringValueAt:7];
284: [aValue setStringValue: inputString];
285: [dbRecordList setValue:aValue
286: forProperty:[[dbModule entity] propertyNamed:"phone"]
287: at:index];
288:
289: /* set contract number */
290: contractNum = [formMatrix intValueAt:8];
291: [aValue setIntValue:contractNum];
292: [dbRecordList setValue: aValue
293: forProperty:[[dbModule entity] propertyNamed:"contract"]
294: at:index];
295:
296: return self;
297: }
298:
299:
300: /* Clear the form cells after each SAVE operation to avoid creating
301: * duplicate records.
302: */
303: - clearData
304: {
305: int i;
306:
307: for (i = 0; i < 9; i++)
308: [formMatrix setStringValue:""at:i];
309: return self;
310: }
311:
312: @end
313:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.