|
|
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:
11: #import <appkit/appkit.h>
12: #import <dbkit/dbkit.h>
13: #import <objc/List.h>
14: #import <objc/NXBundle.h>
15: #import <sys/param.h>
16: #import <libc.h>
17:
18: #import "Controller.h"
19: #import "AddressView.h"
20:
21:
22: #define FAILURE NXLocalizedString("Failure:", NULL, "Message given to user when connection to database can't be made")
23: #define CANNOT_CONNECT NXLocalizedString("Couldn't connect to database", NULL, "Message given to user to explain what fails. ")
24: #define CANNOT_ADD NXLocalizedString("Add operation failed", NULL, "Message given to user that add operation has failed")
25: #define CANNOT_UPDATE NXLocalizedString("Update operation failed",NULL,"Message given to user that update operation has failed")
26: #define CANNOT_DELETE NXLocalizedString("Delete operation failed",NULL,"Message given to user that delete operation has failed")
27:
28: @implementation Controller
29:
30: - appDidInit:sender
31: {
32: /* Try to connect to the database specified using the Sybase Adaptor
33: * and the default login sa, NULL password, SYBASE server, and
34: * pubs database.
35: */
36: database = [[DBDatabase alloc]init];
37: [database connectUsingAdaptor:"SybaseAdaptor"
38: andString:"sa@SYBASE/pubs"];
39:
40: if ( ![database isConnected] ) {
41: NXRunAlertPanel(FAILURE, CANNOT_CONNECT, "OK", NULL, NULL);
42: return self;
43: }
44: /* Once successfully connected, build the data to be displayed in the
45: * matrix
46: */
47: [self initRecordList];
48: [addressView loadCellsFrom:self];
49:
50: /* Assign the controller to become the database delegate */
51: [database setDelegate:self];
52:
53: cellMatrix = [addressView cellMatrix];
54:
55: /* Select a cell as a start */
56: [[cellMatrix selectCellAt:0 :0] sendAction];
57: /* Bring the main application window up front */
58: [theWindow makeKeyAndOrderFront:nil];
59:
60: return self;
61: }
62:
63: /* Set up the DBRecordList object. Create a list of properties which contains
64: * all properties needed for display or updating.
65: */
66: - initRecordList
67: {
68: id firstName, lastName, phone;
69: id state, city, address, zipCode, contract;
70: List *keyList;
71:
72: if (recordList)
73: [recordList free];
74: if (propertyList)
75: [propertyList free];
76:
77: /* get the author table from the database */
78: authorEntity = [database entityNamed:"authors"];
79:
80: /* get the properties */
81: lastName = [authorEntity propertyNamed:"au_lname"];
82: firstName = [authorEntity propertyNamed:"au_fname"];
83: authId = [authorEntity propertyNamed:"au_id"];
84:
85: phone = [authorEntity propertyNamed:"phone"];
86: address = [authorEntity propertyNamed:"address"];
87: city = [authorEntity propertyNamed:"city"];
88: state = [authorEntity propertyNamed:"state"];
89: zipCode = [authorEntity propertyNamed:"zip"];
90: contract = [authorEntity propertyNamed:"contract"];
91:
92: /* Set up the property list
93: * Note that certain properties need to be defined in order
94: * for an Insert or Update operation to work. This depends
95: * on how your data dictionary has been defined. Here pubs
96: * is being used as the model.
97: */
98: propertyList = [[List alloc] init];
99: [propertyList addObject:authId];
100: [propertyList addObject:lastName];
101: [propertyList addObject:firstName];
102: [propertyList addObject:phone];
103: [propertyList addObject:address];
104: [propertyList addObject:city];
105: [propertyList addObject:state];
106: [propertyList addObject:zipCode];
107: [propertyList addObject:contract];
108:
109: recordList = [[DBRecordList alloc] init];
110:
111:
112: /* A unique key is needed if you want to update or insert new
113: * data via the record list into the database. If no key is defined,
114: * the data retrieved via the record list is read-only.
115: * This is needed here, since we do not use a dbmodel to define
116: * the key.
117: */
118: keyList = (List *)[[List alloc] init];
119: [keyList addObject:authId];
120: [recordList setKeyProperties:keyList];
121: [keyList free];
122:
123: /* You must set the properties FIRST before setting the retrieve order */
124: [recordList setProperties:propertyList ofSource:authorEntity];
125:
126: [recordList addRetrieveOrder:DB_AscendingOrder for:lastName];
127: [recordList addRetrieveOrder:DB_AscendingOrder for:firstName];
128: [recordList fetchUsingQualifier:nil];
129: recordCount = [recordList count];
130:
131: return self;
132: }
133:
134: /* This method is called when selecting "Insert"
135: */
136: - addRecords:sender
137: {
138:
139: int row;
140:
141: if (recordCount > 0) {
142:
143: if ( ![addressView addRecordFrom:sender at:(recordCount-1)]) {
144: NXRunAlertPanel(NULL, CANNOT_ADD, NULL, NULL, NULL);
145: return self;
146: }
147:
148: [self initRecordList];
149: [addressView loadCellsFrom:self];
150: /* Find the row of the newly inserted record */
151: row = [addressView getNewRow];
152: [cellMatrix scrollCellToVisible:row :0];
153: [[cellMatrix selectCellAt:row:0] sendAction];
154: }
155: else
156: fprintf(stderr, "empty record list - NOP\n");
157: return self;
158: }
159:
160: /* This method gets called when selecting "Update"
161: */
162: - updateRecords:sender
163: {
164: int row;
165:
166: row = [cellMatrix selectedRow];
167: if ( ![addressView updateRecordFrom:sender at:row]) {
168: NXRunAlertPanel(NULL, CANNOT_UPDATE, NULL, NULL, NULL);
169: return self;
170: }
171: /* Redisplay the records */
172: [self initRecordList];
173: [addressView loadCellsFrom:self];
174: /* find the row of the updated record */
175: row = [addressView getNewRow];
176: [cellMatrix scrollCellToVisible:row :0];
177: [[cellMatrix selectCellAt:row:0] sendAction];
178:
179: return self;
180: }
181:
182:
183: - deleteRecords:sender
184: {
185:
186: int row;
187:
188: row = [cellMatrix selectedRow];
189: if (recordCount > 0) {
190:
191: if (![addressView deleteSelectedRecord:sender]) {
192: NXRunAlertPanel(NULL, CANNOT_DELETE, NULL, NULL, NULL);
193: return self;
194: }
195:
196: [self initRecordList];
197: [addressView loadCellsFrom:self];
198: [cellMatrix scrollCellToVisible:row :0];
199: [[cellMatrix selectCellAt:row:0] sendAction];
200: }
201: else
202: fprintf(stderr, "empty record list - NOP\n");
203:
204: return self;
205: }
206: - getRecordList
207: {
208: return recordList;
209: }
210:
211: - getPropertyList
212: {
213: return propertyList;
214: }
215:
216: - (int)getRecordCount
217: {
218: return recordCount;
219: }
220:
221: - showSQLPanel:sender
222: {
223: [SQLPanel makeKeyAndOrderFront:nil];
224: return self;
225: }
226:
227: - showInfoPanel:sender
228: {
229: if (!infoPanel) {
230: infoPanel = [NXApp loadNibSection:"InfoPanel.nib" owner:NXApp
231: withNames:NO];
232: }
233: [infoPanel orderFront:nil];
234: return self;
235: }
236:
237: - appWillTerminate:sender
238: {
239: /* deallocate what has been allocated */
240: if (recordList)
241: [recordList free];
242: if (propertyList)
243: [propertyList free];
244: return self;
245: }
246:
247: /* DBDatabase delegate methods to log error messages and SQL queries */
248:
249: - (BOOL)db:aDb willEvaluateString:(const unsigned char*)aString
250: usingBinder:aBinder
251: {
252: [textObj appendToText:"SQL Query:\n"];
253: [textObj appendToText:aString];
254: [textObj appendToText:"\n"];
255: return YES;
256: }
257:
258: @end
259:
260: @implementation Text(printResults)
261:
262: - appendToText:(const char *)newText
263: {
264: int currentLength = [self textLength];
265:
266: [self setSel:currentLength :currentLength];
267: [self replaceSel:newText];
268: [self scrollSelToVisible];
269: return self;
270: }
271:
272: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.