|
|
1.1 root 1: /*
2: * Controller for the Ledger Document.
3: *
4: * Author: Kris Younger, NeXT Systems Engineering
5: * You may freely copy, distribute and reuse the code in this example.
6: * NeXT disclaims any warranty of any kind, expressed or implied, as to
7: * its fitness for any particular use.
8: */
9:
10: #import "LedgerController.h"
11: #import "Transaction.h"
12: #import <dbkit/dbkit.h>
13: #import "JFTableVectorConfiguration.h"
14: #import "JFTableViewLoader.h"
15: #import "KAYEditableFormatter.h"
16: #define XOFFSET 30.0 // Offset of subsequent windows
17: #define YOFFSET -30.0
18:
19: @implementation LedgerController
20:
21: - append:sender
22: {
23: id newXaction;
24: int handle;
25:
26: newXaction = [[Transaction alloc] init];
27: [accountStore startTransaction];
28: handle = [account addRecord:newXaction];
29: [accountStore commitTransaction];
30: if (sender != myFormatter) [self ping:sender];
31: return self;
32: }
33:
34: - appendThis:anObj
35: {
36: int handle;
37:
38: [accountStore startTransaction];
39: handle = [account addRecord:anObj];
40: [accountStore commitTransaction];
41: return self;
42: }
43:
44: - commit:sender
45: {
46: int r;
47: id o;
48:
49: r = [tableView selectedRowAfter:DB_NoIndex];
50: if (r != DB_NoIndex) {
51: o = (Transaction *)[postingList objectAt:r];
52: [accountStore startTransaction];
53: [account replaceRecord:[o handle] with:o];
54: [accountStore commitTransaction];
55: if (r == ([postingList count] - 1)) {
56: [self doBalance];
57: if (sender != myFormatter) [self ping:self];
58: } else
59: [self doFullerBalance:self];
60: };
61: return self;
62: }
63:
64: - copy:sender
65: {
66: return self;
67: }
68:
69: - cut:sender
70: {
71: return self;
72: }
73:
74: - paste:sender
75: {
76: return self;
77: }
78:
79: - selectAll:sender
80: {
81: return self;
82: }
83:
84: - initWith:aRecordManager named:(const char *)aName
85: {
86: char path[MAXPATHLEN + 1];
87: int i;
88:
89: if ([[NXBundle mainBundle] getPath:path forResource:"LedgerController" ofType:"nib"]) {
90: window = [NXApp loadNibFile:path owner:self];
91: /*
92: * Put the window offset from the previous document window... If no
93: * previous window exists, or the main window is undetermined, then
94: */
95: if ([[[NXApp mainWindow] delegate] respondsTo:@selector(isLedger)] == YES) {
96: NXRect winFrame, winLoc;
97:
98: [[NXApp mainWindow] getFrame:&winFrame];
99: [[window class] getContentRect:&winLoc
100: forFrameRect:&winFrame style:[window style]];
101: [window moveTo:NX_X(&winLoc) + XOFFSET:NX_Y(&winLoc) + YOFFSET];
102: }
103: /* the tvLoader is an object which takes a list of objects and a list of configuration objects (see below) which work to load the tableview when it requests it. */
104: tvLoader = [[JFTableViewLoader alloc] init];
105: account = aRecordManager;
106: accountName = aName;
107: [account getBlock:&i andStore:&accountStore];
108: [tvLoader setTableView:tableView];
109: [[tableView setGridVisible:YES] setDelegate:self];
110: [[tableView window] setTitle:accountName];
111: #ifdef NEVEREVER
112: /* useful in making window positions sticky on the
113: * desktop. */
114: [[tableView window] setFrameAutosaveName:accountName];
115: [[tableView window] setFrameUsingName:accountName];
116: #endif
117: myFormatter = [[KAYEditableFormatter alloc] init];
118: [myFormatter setController:self];
119: [[tableView window] disableFlushWindow];
120: [self buildConfigurationList];
121: /* go check out the method, it loads a list full of "bindings" binding a tableview column to an ivar inside of the Transaction object. essentially, letting us use a list of objects instead of a recordlist. */
122: [tvLoader setConfigurationList:configList];
123: [myFormatter setColumnLimit:[configList count] - 1];
124: [[tableView window] reenableFlushWindow];
125: [[tableView window] flushWindowIfNeeded];
126: for (i = 0; i < [configList count]; i++) {
127: [[tableView columnAt:i] setFormatter:myFormatter];
128: };
129: doFullBalance = NO;
130: } else {
131: NXRunAlertPanel("Oops!", "No LedgerController nib file", "OK", NULL, NULL);
132: return nil;
133: }
134: return self;
135: }
136:
137: - findPostings
138: {
139: int handle;
140: id config;
141: IXPostingCursor *cursor;
142: BOOL isValid;
143:
144: /* since the Transaction objects are serialized by creation (handled in the main delegate), this method uses the attribute "tSerial" to get a sorted-ascending ordering. The postingList is what we use load the tableview */
145:
146: config = [[tableView columnAt:0] identifier];
147: cursor = [account cursorForAttributeNamed:
148: [[configList objectAt:(int)config] ivarName]];
149: if (cursor == nil)
150: cursor = [account cursorForAttributeNamed:"tSerial"];
151:
152: postingList = [postingList free];
153: postingList = [[IXPostingList alloc] initWithSource:account];
154: for (isValid = [cursor setFirst]; isValid; isValid = [cursor setNext])
155: for (handle = [cursor setFirstHandle]; handle; handle = [cursor setNextHandle])
156: [postingList addHandle:handle withWeight:0];
157:
158: [cursor free];
159: return postingList;
160: }
161:
162: - makeKey:sender
163: {
164: [self doBalance];
165: [self ping:self];
166: return self;
167: }
168:
169: - (const char *)accountName
170: {
171: return accountName;
172: }
173:
174: - doBalance
175: {
176: double cBalance = 0.0;
177: char buf[256];
178: int i, k, h, m;
179: id obj;
180:
181: postingList = [self findPostings];
182: k = [postingList count];
183: [accountStore startTransaction];
184: if (((k - 2) <= 0) || (doFullBalance == YES)) {
185: m = 0;
186: cBalance = 0.0;
187: } else {
188: m = (k - 2);
189: h = [postingList handleOfObjectAt:(m - 1)];
190: obj = [account readRecord:h fromZone:[self zone]];
191: strcpy(buf,[obj tBalance]);
192: cBalance += atof(buf);
193: };
194: for (i = m; i < k; i++) {
195: h = [postingList handleOfObjectAt:i];
196: obj = [account readRecord:h fromZone:[self zone]];
197: cBalance += [obj tAmount];
198: sprintf(buf, "%.2f", cBalance);
199: [obj setTBalance:buf];
200: [account replaceRecord:[obj handle] with:obj];
201: [obj free];
202: }
203: [accountStore commitTransaction];
204: sprintf(buf, "%.2f", cBalance);
205: [balanceTF setStringValue:buf];
206: return self;
207: }
208:
209: - doFullerBalance:sender
210: {
211: doFullBalance = YES;
212: [self doBalance];
213: [self ping:self];
214: doFullBalance = NO;
215:
216: return self;
217: }
218:
219: - ping:sender
220: {
221:
222: [window makeKeyAndOrderFront:self];
223: [[tableView window] disableFlushWindow]; /* DBTV ignores autodisplay */
224: postingList = [self findPostings];
225: [tvLoader setDataList:postingList];
226: [tableView scrollRowToVisible:[tableView rowCount] - 1];
227: [tableView editFieldAt:[tableView rowCount] - 1:0];
228: [[tableView window] reenableFlushWindow];
229: [[tableView window] flushWindowIfNeeded];
230: return self;
231: }
232:
233: - void:sender
234: {
235: int r, h;
236: id o, p;
237:
238: r = [tableView selectedRowAfter:DB_NoIndex];
239: if (r != DB_NoIndex) {
240: o = (Transaction *)[postingList objectAt:r];
241: p = [[Transaction alloc] init];
242: [accountStore startTransaction];
243: h = [account addRecord:p];
244: [p becomeVoided:o];
245: [account replaceRecord:[o handle] with:o];
246: [account replaceRecord:[p handle] with:p];
247: [accountStore commitTransaction];
248: [self doBalance];
249: [self ping:self];
250: };
251: return self;
252: }
253:
254: - closeAccount:sender
255: {
256: [window performClose:self];
257: return self;
258: }
259:
260: - windowWillClose:sender
261: {
262: return self;
263: }
264:
265: - tableView:sender movedColumnFrom:(unsigned int)old to:(unsigned int)new
266: {
267: if (new == 0) [self ping:self];
268: return self;
269: }
270:
271: - buildConfigurationList
272: {
273: configList = [[List alloc] init];
274: [configList addObject:[[JFTableVectorConfiguration alloc]
275: initDataClassName:"Transaction"
276: titleName:"Date"
277: ivarName:"tDate"]];
278: [configList addObject:[[JFTableVectorConfiguration alloc]
279: initDataClassName:"Transaction"
280: titleName:"REF"
281: ivarName:"tNumber"]];
282: [configList addObject:[[JFTableVectorConfiguration alloc]
283: initDataClassName:"Transaction"
284: titleName:"Description"
285: ivarName:"tMemo"]];
286: [configList addObject:[[JFTableVectorConfiguration alloc]
287: initDataClassName:"Transaction"
288: titleName:"Debit"
289: ivarName:"tDebit"]];
290: [configList addObject:[[JFTableVectorConfiguration alloc]
291: initDataClassName:"Transaction"
292: titleName:"Credit"
293: ivarName:"tCredit"]];
294: [configList addObject:[[JFTableVectorConfiguration alloc]
295: initDataClassName:"Transaction"
296: titleName:"Balance"
297: ivarName:"tBalance"]];
298: return self;
299: }
300:
301: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.