|
|
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.