|
|
Sample Programs from NeXSTEP 3.3
/*
* Controller for the Ledger Document.
*
* Author: Kris Younger, NeXT Systems Engineering
* You may freely copy, distribute and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied, as to
* its fitness for any particular use.
*/
#import "LedgerController.h"
#import "Transaction.h"
#import <dbkit/dbkit.h>
#import "JFTableVectorConfiguration.h"
#import "JFTableViewLoader.h"
#import "KAYEditableFormatter.h"
#define XOFFSET 30.0 // Offset of subsequent windows
#define YOFFSET -30.0
@implementation LedgerController
- append:sender
{
id newXaction;
int handle;
newXaction = [[Transaction alloc] init];
[accountStore startTransaction];
handle = [account addRecord:newXaction];
[accountStore commitTransaction];
if (sender != myFormatter) [self ping:sender];
return self;
}
- appendThis:anObj
{
int handle;
[accountStore startTransaction];
handle = [account addRecord:anObj];
[accountStore commitTransaction];
return self;
}
- commit:sender
{
int r;
id o;
r = [tableView selectedRowAfter:DB_NoIndex];
if (r != DB_NoIndex) {
o = (Transaction *)[postingList objectAt:r];
[accountStore startTransaction];
[account replaceRecord:[o handle] with:o];
[accountStore commitTransaction];
if (r == ([postingList count] - 1)) {
[self doBalance];
if (sender != myFormatter) [self ping:self];
} else
[self doFullerBalance:self];
};
return self;
}
- copy:sender
{
return self;
}
- cut:sender
{
return self;
}
- paste:sender
{
return self;
}
- selectAll:sender
{
return self;
}
- initWith:aRecordManager named:(const char *)aName
{
char path[MAXPATHLEN + 1];
int i;
if ([[NXBundle mainBundle] getPath:path forResource:"LedgerController" ofType:"nib"]) {
window = [NXApp loadNibFile:path owner:self];
/*
* Put the window offset from the previous document window... If no
* previous window exists, or the main window is undetermined, then
*/
if ([[[NXApp mainWindow] delegate] respondsTo:@selector(isLedger)] == YES) {
NXRect winFrame, winLoc;
[[NXApp mainWindow] getFrame:&winFrame];
[[window class] getContentRect:&winLoc
forFrameRect:&winFrame style:[window style]];
[window moveTo:NX_X(&winLoc) + XOFFSET:NX_Y(&winLoc) + YOFFSET];
}
/* 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. */
tvLoader = [[JFTableViewLoader alloc] init];
account = aRecordManager;
accountName = aName;
[account getBlock:&i andStore:&accountStore];
[tvLoader setTableView:tableView];
[[tableView setGridVisible:YES] setDelegate:self];
[[tableView window] setTitle:accountName];
#ifdef NEVEREVER
/* useful in making window positions sticky on the
* desktop. */
[[tableView window] setFrameAutosaveName:accountName];
[[tableView window] setFrameUsingName:accountName];
#endif
myFormatter = [[KAYEditableFormatter alloc] init];
[myFormatter setController:self];
[[tableView window] disableFlushWindow];
[self buildConfigurationList];
/* 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. */
[tvLoader setConfigurationList:configList];
[myFormatter setColumnLimit:[configList count] - 1];
[[tableView window] reenableFlushWindow];
[[tableView window] flushWindowIfNeeded];
for (i = 0; i < [configList count]; i++) {
[[tableView columnAt:i] setFormatter:myFormatter];
};
doFullBalance = NO;
} else {
NXRunAlertPanel("Oops!", "No LedgerController nib file", "OK", NULL, NULL);
return nil;
}
return self;
}
- findPostings
{
int handle;
id config;
IXPostingCursor *cursor;
BOOL isValid;
/* 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 */
config = [[tableView columnAt:0] identifier];
cursor = [account cursorForAttributeNamed:
[[configList objectAt:(int)config] ivarName]];
if (cursor == nil)
cursor = [account cursorForAttributeNamed:"tSerial"];
postingList = [postingList free];
postingList = [[IXPostingList alloc] initWithSource:account];
for (isValid = [cursor setFirst]; isValid; isValid = [cursor setNext])
for (handle = [cursor setFirstHandle]; handle; handle = [cursor setNextHandle])
[postingList addHandle:handle withWeight:0];
[cursor free];
return postingList;
}
- makeKey:sender
{
[self doBalance];
[self ping:self];
return self;
}
- (const char *)accountName
{
return accountName;
}
- doBalance
{
double cBalance = 0.0;
char buf[256];
int i, k, h, m;
id obj;
postingList = [self findPostings];
k = [postingList count];
[accountStore startTransaction];
if (((k - 2) <= 0) || (doFullBalance == YES)) {
m = 0;
cBalance = 0.0;
} else {
m = (k - 2);
h = [postingList handleOfObjectAt:(m - 1)];
obj = [account readRecord:h fromZone:[self zone]];
strcpy(buf,[obj tBalance]);
cBalance += atof(buf);
};
for (i = m; i < k; i++) {
h = [postingList handleOfObjectAt:i];
obj = [account readRecord:h fromZone:[self zone]];
cBalance += [obj tAmount];
sprintf(buf, "%.2f", cBalance);
[obj setTBalance:buf];
[account replaceRecord:[obj handle] with:obj];
[obj free];
}
[accountStore commitTransaction];
sprintf(buf, "%.2f", cBalance);
[balanceTF setStringValue:buf];
return self;
}
- doFullerBalance:sender
{
doFullBalance = YES;
[self doBalance];
[self ping:self];
doFullBalance = NO;
return self;
}
- ping:sender
{
[window makeKeyAndOrderFront:self];
[[tableView window] disableFlushWindow]; /* DBTV ignores autodisplay */
postingList = [self findPostings];
[tvLoader setDataList:postingList];
[tableView scrollRowToVisible:[tableView rowCount] - 1];
[tableView editFieldAt:[tableView rowCount] - 1:0];
[[tableView window] reenableFlushWindow];
[[tableView window] flushWindowIfNeeded];
return self;
}
- void:sender
{
int r, h;
id o, p;
r = [tableView selectedRowAfter:DB_NoIndex];
if (r != DB_NoIndex) {
o = (Transaction *)[postingList objectAt:r];
p = [[Transaction alloc] init];
[accountStore startTransaction];
h = [account addRecord:p];
[p becomeVoided:o];
[account replaceRecord:[o handle] with:o];
[account replaceRecord:[p handle] with:p];
[accountStore commitTransaction];
[self doBalance];
[self ping:self];
};
return self;
}
- closeAccount:sender
{
[window performClose:self];
return self;
}
- windowWillClose:sender
{
return self;
}
- tableView:sender movedColumnFrom:(unsigned int)old to:(unsigned int)new
{
if (new == 0) [self ping:self];
return self;
}
- buildConfigurationList
{
configList = [[List alloc] init];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"Date"
ivarName:"tDate"]];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"REF"
ivarName:"tNumber"]];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"Description"
ivarName:"tMemo"]];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"Debit"
ivarName:"tDebit"]];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"Credit"
ivarName:"tCredit"]];
[configList addObject:[[JFTableVectorConfiguration alloc]
initDataClassName:"Transaction"
titleName:"Balance"
ivarName:"tBalance"]];
return self;
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.