|
|
Sample Programs from NeXSTEP 3.3
/* MainController.m
* 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.
*
* Written by Mai Nguyen, NeXT Developer Support
*
*/
#import "MainController.h"
#import "Department.h"
#import "strings.h"
@implementation MainController
- init
{
[super init];
return self;
}
- appDidInit:sender
{
dbDataSource = [masterController dataSource];
dbChannel = [dbDataSource databaseChannel];
adaptorChannel = [dbChannel adaptorChannel];
eoAdaptor = [[adaptorChannel adaptorContext] adaptor];
// Bring up a login panel and get the valid connection dictionary
if(![eoAdaptor runLoginPanelAndValidateConnectionDictionary])
[NXApp terminate:self];
[eoAdaptor setConnectionDictionary: [eoAdaptor connectionDictionary]];
rootEntity = [dbDataSource entity];
[self setDelegates];
// set up the controller to not alter the selection after a fetch
[masterController setSelectsFirstObjectAfterFetch:NO];
[self fetch:sender];
return self;
}
// Perform a fetch based on the latest options specified by user.
- fetch:sender
{
if (optionsPanel)
[optionsPanel orderOut:sender];
[self setUpFetch:sender];
[masterController fetch];
return self;
}
- newRecord:sender
{
int i;
// Clear all the current values in the form cells to prepare
// for the insertion of a new record.
for (i = 0; i < 5; i++)
[formMatrix setStringValue:"" at:i];
return self;
}
- insert:sender
{
// Disable the INSERT Button if the input is not valid
if ([self validateRecord] == NO) {
[insertButton setState:0];
NXRunAlertPanel(NULL, ERR_INSERT_FAIL, NULL, NULL, NULL);
}
else {
[insertButton setState:1];
[masterController insert:sender];
}
return self;
}
// Set up the fetch order and specify a qualifier
// for the master table "Department"
- setUpFetch:sender
{
const char *inputString;
const char *attrName = NULL;
EOQualifier *aQualifier;
id fetchOrder;
id sortAttribute;
int orderType;
// build the qualifier.
// If the input string is empty, fetch all records.
inputString = [(TextField *)textField stringValue];
if (inputString == NULL)
[dbDataSource setQualifier: [rootEntity qualifier]];
else {
aQualifier = [[[EOQualifier alloc] initWithEntity:rootEntity
qualifierFormat:@"%A >= %d", @"DeptId",
[textField intValue]] autorelease];
[dbDataSource setQualifier:aQualifier];
}
// build the fetch order based on the first column of the master
// tableview
orderType = [sortMatrix selectedTag];
attrName = [[masterTableview columnAt:0] title];
sortAttribute = [rootEntity attributeNamed:[ [[NSString alloc]
initWithCString:attrName] autorelease]];
fetchOrder = [NSArray arrayWithObject:[[[EOAttributeOrdering alloc]
initWithAttribute:sortAttribute ordering: orderType] autorelease]];
[dbDataSource setFetchOrder:fetchOrder];
return self;
}
- (BOOL) validateRecord
{
int newId, newLocation;
BOOL result = YES;
newId = [formMatrix intValueAt:0];
newLocation = [formMatrix intValueAt:2];
// Do validation here
if ( newId < 100 || newId > 999) {
NXRunAlertPanel(NULL, ERR_INVALID_ID, NULL, NULL, NULL);
result = NO;
}
if ( newLocation != 1101 && newLocation != 1103
&& newLocation != 1104 && newLocation != 1106
&& newLocation != 1207) {
NXRunAlertPanel(NULL, ERR_INVALID_LOCATION, NULL, NULL, NULL);
result = NO;
}
return result;
}
- setDelegates
{
#ifdef DEBUG
[adaptorChannel setDebugEnabled:YES];
#endif
[adaptorChannel setDelegate:self];
[(EOController *) masterController setDelegate:self];
return self;
}
@end
@implementation MainController (EOAdaptorDelegation)
//This method is useful to trace SQL queries
- (void)adaptorChannel:channel
didEvaluateExpression:(NSString *)expression
{
if (sqlPanel) {
[text appendToText:"SQL Query:\n"];
[text appendToText:[expression cString]];
[text appendToText:"\n"];
}
}
@end
@implementation MainController (EOControllerDelegation)
// This method is called before each update. Since the controller has
// buffer edits turned ON, this method is called when the user explicitly
// presses the UPDATE button.
- (NSDictionary *)controller:(EOController *)controller
willSaveEdits: (NSDictionary *)edits
toObject:object
{
if ([self validateRecord] == YES)
return edits;
else {
NXRunAlertPanel(NULL, ERR_UPDATE_FAIL, NULL, NULL, NULL);
return nil;
}
}
// Take the input from the formcells and create a new record.
// This delegate method can be used to set up the default values of a newly
// created EO. By default, we use the current user input in the formcells
// to create a new record.
- (BOOL)controller:(EOController *)controller willInsertObject:object atIndex: (unsigned)newIndex
{
[object setDeptId: (int)[formMatrix intValueAt:0]];
[object setDepartmentName:[[[NSString alloc] initWithCString:
[formMatrix stringValueAt:1]] autorelease]];
[object setLocationId:(int)[formMatrix intValueAt:2]];
// The to-many relationship points to an empty autoreleased array
[object setToEmployee:[NSArray array]];
return YES;
}
// After insertion, refetch object so that the derived attributes are
// properly redisplayed.
- (void)controller:(EOController *)controller didInsertObject:object
inDataSource:dataSource
{
[dbChannel refetchObject:object];
}
// After an update, refetch object so that the derived attributes are
// properly redisplayed.
- (void)controller:(EOController *)controller didUpdateObject:object
inDataSource:dataSource
{
[dbChannel refetchObject:object];
}
// When the insert operation failed, remove the wrong record and rollback
// the data source. A failure usually happens when trying to insert a duplicate
// key. Since an insert operation adds a new record after the current
// selection, the index has to be computed accordingly.
- (EODataSourceFailureResponse)controller:(EOController *)controller
failedToInsertObject:object
inDataSource:dataSource;
{
NXRunAlertPanel(NULL, ERR_INSERT_FAIL, NULL, NULL, NULL);
[controller deleteObjectAtIndex:([masterTableview selectedRow] + 1)];
return EORollbackDataSourceFailureResponse;
}
- (EODataSourceFailureResponse) controller:(EOController *)controller
failedToUpdateObject:object
inDataSource:dataSource
{
NXRunAlertPanel(NULL, ERR_UPDATE_FAIL, NULL, NULL, NULL);
// Restore object to its previous state
[dbChannel refetchObject:object];
return EORollbackDataSourceFailureResponse;
}
// When deleting a department, we need to null all the references
// to that department. Therefore, the "toEmployee" relationship is
// used to find the employee records attached to a given department.
// All department ids will then be nulled out.
- (BOOL)controller:controller willDeleteObject:object
{
NSArray *employeeArray = [object toEmployee];
NSEnumerator *enumerator = [employeeArray objectEnumerator];
EOGenericRecord *employee;
while((employee = [enumerator nextObject]) != nil) {
[employee setObject:[EONull null] forKey:@"DeptId"];
[(id)[controller dataSource] updateObject:employee];
}
return YES;
}
// Implementing this delegate method allows the controller to discard
// pending edits. In this example, pending edits are edits rejected by
// the validation mechanism, hence they can be discarded.
- (BOOL) controllerWillDiscardEdits:(EOController *)controller
{
return YES;
}
@end
@implementation Text(printResults)
- appendToText:(const char *)newText
{
int currentLength = [self textLength];
[self setSel:currentLength :currentLength];
[self replaceSel:newText];
[self scrollSelToVisible];
return self;
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.