|
|
Sample Programs from NeXSTEP 3.3
#import "UniqueKey.h"
#import "Projects.h"
static BOOL _Debug = YES;
@implementation Projects
/******************************************************************************
* Create two instances of the UniqueKey object to grab blocks of <count> keys for
* our use during inserts. The count is set low so you can see the SQL reserve
* blocks of keys. Up the count to something larger for it to be of use.
*
* The login information (connection dictionary) in the model has been blanked out,
* since you may elect to have the tables in some database other than PEOPLE, so we
* elect to run a login panel. Once the login is complete we can get the
* connection dictionary from the adaptor and use that information to allow
* UniqueKey to login and create its separate connection for key reservation.
*
* Note the content views of the employee and project boxes and paste in the
* default content.
******************************************************************************/
- appDidInit:sender
{
EOAdaptor *eoAdaptor;
dbChannel = [[(id)[employeeController dataSource] databaseChannel] retain];
dbContext = [[dbChannel databaseContext] retain];
if(_Debug) [[dbChannel adaptorChannel] setDelegate:self];
projectEntity = [[(id)[projectController dataSource] entity] retain];
employeeEntity = [[(id)[employeeController dataSource] entity] retain];
empProjectEntity = [[(id)[projectEntity relationshipNamed:@"toEmpProjects"] destinationEntity] retain];
empProjectDDS = [[EODatabaseDataSource alloc] initWithDatabaseChannel: dbChannel
entityNamed: [empProjectEntity name]];
eoAdaptor = [[[dbChannel adaptorChannel] adaptorContext] adaptor];
if(![eoAdaptor runLoginPanelAndValidateConnectionDictionary]) [NXApp terminate:self];
[UniqueKey setConnectionDictionary:[eoAdaptor connectionDictionary]];
projectUniqueKey = [[[UniqueKey alloc] initWithEntity:projectEntity count:5] retain];
employeeUniqueKey = [[[UniqueKey alloc] initWithEntity:employeeEntity count:5] retain];
if(!projectUniqueKey || !employeeUniqueKey) [NXApp terminate:self];
[self setFetchOrderFor:projectController with:@"ProjectName" order:EOAscendingOrder];
[self setFetchOrderFor:addProjectsForEmployeeController with:@"ProjectName" order:EOAscendingOrder];
[self setFetchOrderFor:employeeController with:@"LastName" order:EOAscendingOrder];
[self setFetchOrderFor:addEmployeesOnProjectController with:@"LastName" order:EOAscendingOrder];
[addProjectsForEmployeeController setSelectsFirstObjectAfterFetch:NO];
[addEmployeesOnProjectController setSelectsFirstObjectAfterFetch:NO];
inspectorWindow=[swapBox window];
[self projectInspector:nil]; // swap in the project content view
[[inspectorWindow center] makeKeyAndOrderFront:nil];
return self;
}
/******************************************************************************
* Set a controller's data source to fetch sorted by a given attribute name
* and order.
******************************************************************************/
- setFetchOrderFor:(EOController*)controller with:(NSString*)attributeName order:(EOOrdering)order
{
id dataSource = [controller dataSource];
id attribute = [[dataSource entity] attributeNamed:attributeName];
NSArray *orderArray;
orderArray = [NSArray arrayWithObject:
[EOAttributeOrdering attributeOrderingWithAttribute:attribute ordering:order]];
[dataSource setFetchOrder:orderArray];
return self;
}
/******************************************************************************
* Accept the users selection for either the Employee or Project inspector. Swap
* in the appropriate content view.
******************************************************************************/
- employeeInspector:sender
{
[inspectorWindow disableFlushWindow];
[swapBox setContentView:[employeeBox contentView]];
[employeeController fetch];
[swapBox display];
[[inspectorWindow reenableFlushWindow] flushWindowIfNeeded];
return self;
}
- projectInspector:sender
{
[inspectorWindow disableFlushWindow];
[swapBox setContentView:[projectBox contentView]];
[projectController fetch];
[swapBox display];
[[inspectorWindow reenableFlushWindow] flushWindowIfNeeded];
return self;
}
/******************************************************************************
* Utility to create an intermediate table empProject EOGenericRecord.
******************************************************************************/
- createEmpProject:(NSNumber*)empId:(NSNumber*)projectId
{
EOGenericRecord *empProject = [empProjectDDS createObject];
[empProject setObject:projectId forKey:@"ProjectId"];
[empProject setObject:empId forKey:@"EmpId"];
return empProject;
}
/******************************************************************************
* Bring up the add employee selection panel and start a modal session. Construct
* and 'otherEmployees' qualifier to select employees that do not already appear
* in the EmployeesOnProject detail view.
******************************************************************************/
- addEmployeesOnProject:sender
{
EOGenericRecord *project = [(id)[employeesOnProjectController dataSource] masterObject];
NSNumber *projectId = [project objectForKey:@"ProjectId"];
EOQualifier *otherEmployees;
NSString *qualifierString;
qualifierString = [NSString stringWithFormat:
@"EmpId not in (SELECT z1.EMP_ID FROM EMPLOYEE z1, EMP_PROJECT z2 "
@"WHERE z1.EMP_ID = z2.EMP_ID AND z2.PROJECT_ID = %@)",projectId];
otherEmployees = [[[EOQualifier alloc]
initWithEntity:employeeEntity qualifierFormat:qualifierString] autorelease];
[(id)[addEmployeesOnProjectController dataSource] setQualifier:otherEmployees];
[addEmployeesOnProjectController clearSelection];
[addEmployeesOnProjectController fetch];
[[addEmployeesPanel center] makeKeyAndOrderFront:nil];
[NXApp runModalFor:addEmployeesPanel];
[addEmployeesPanel orderOut:self];
[projectController fetch];
return self;
}
- addEmployeesOnProjectOK:sender
{
NSArray *eArray;
NSEnumerator *eEnumerator;
EOGenericRecord *project;
NSNumber *projectId;
EOGenericRecord *employee;
EOGenericRecord *empProject;
eArray = [addEmployeesOnProjectController selectedObjects];
eEnumerator = [eArray objectEnumerator];
project = [(id)[employeesOnProjectController dataSource] masterObject];
projectId = [project objectForKey:@"ProjectId"];
[dbContext beginTransaction];
while((employee = [eEnumerator nextObject]) != nil) {
empProject = [self createEmpProject:[employee objectForKey:@"EmpId"]:projectId];
[dbChannel insertObject:empProject];
}
[dbContext commitTransaction];
[NXApp stopModal];
return self;
}
/******************************************************************************
* Bring up the add project selection panel and start a modal session. Construct
* and 'otherProjects' qualifier to select project that do not already appear
* in the ProjectsForEmployee detail view. We use an imbedded select here with
* '.' chars in the qualifier string. These names will not be converted, since they
* contain '.' chars, so we have the ability to write qualifiers that
* reference external names it we like.
******************************************************************************/
- addProjectsForEmployee:sender
{
EOGenericRecord *employee = [(id)[projectsForEmployeeController dataSource] masterObject];
NSNumber *empId = [employee objectForKey:@"EmpId"];
EOQualifier *otherProjects;
NSString *qualifierString;
qualifierString = [NSString stringWithFormat:
@"ProjectId not in (SELECT z1.PROJECT_ID FROM PROJECT z1, EMP_PROJECT z2 "
@"WHERE z1.PROJECT_ID = z2.PROJECT_ID AND z2.EMP_ID = %@)",empId];
otherProjects = [[[EOQualifier alloc]
initWithEntity:projectEntity qualifierFormat:qualifierString] autorelease];
[(id)[addProjectsForEmployeeController dataSource] setQualifier:otherProjects];
[addProjectsForEmployeeController clearSelection];
[addProjectsForEmployeeController fetch];
[[addProjectsPanel center] makeKeyAndOrderFront:nil];
[NXApp runModalFor:addProjectsPanel];
[addProjectsPanel orderOut:self];
[employeeController fetch];
return self;
}
- addProjectsForEmployeeOK:sender
{
NSArray *pArray;
NSEnumerator *pEnumerator;
EOGenericRecord *employee;
NSNumber *empId;
EOGenericRecord *project;
EOGenericRecord *empProject;
pArray = [addProjectsForEmployeeController selectedObjects];
pEnumerator = [pArray objectEnumerator];
employee = [(id)[projectsForEmployeeController dataSource] masterObject];
empId = [employee objectForKey:@"EmpId"];
[dbContext beginTransaction];
while((project = [pEnumerator nextObject]) != nil) {
empProject = [self createEmpProject:empId:[project objectForKey:@"ProjectId"]];
[dbChannel insertObject:empProject];
}
[dbContext commitTransaction];
[NXApp stopModal];
return self;
}
/******************************************************************************
* Delete the intermediate table entries for the selected employee. To do this we
* get the selected master object and ask it for the enumerator of empProject
* objects. Since each empProject object can be asked objectForKey:@"Employee", we
* see if that empProject object has a corresponding employee in the selected employee
* array (eArray). We choose to use the method indexOfObjectIdenticalTo: to do the
* check since it uses pointer equality. This works because object uniquing is
* enabled by default.
******************************************************************************/
- removeSelectedEmployeesOnProject:sender
{
NSArray *eArray;
EOGenericRecord *project;
NSEnumerator *epEnumerator;
EOGenericRecord *empProject;
eArray = [employeesOnProjectController selectedObjects];
project = [(id)[employeesOnProjectController dataSource] masterObject];
epEnumerator = [[project objectForKey:@"toEmpProjects"] objectEnumerator];
[dbContext beginTransaction];
while((empProject=[epEnumerator nextObject]) != nil)
if([eArray indexOfObjectIdenticalTo:[empProject objectForKey:@"toEmployee"]]!=NSNotFound)
[dbChannel deleteObject:empProject];
[dbContext commitTransaction];
[projectController fetch];
return self;
}
/******************************************************************************
* Delete the intermediate table entries for the selected project. To do this we
* get the selected master object and ask it for the enumerator of empProject
* objects. Since each empProject object can be asked objectForKey:@"Project", we
* see if that empProject object has a corresponding project in the selected project
* array (pArray). We choose to use the method indexOfObjectIdenticalTo: to do the
* check since it uses pointer equality. This works because object uniquing is
* enabled by default.
******************************************************************************/
- removeSelectedProjectsForEmployee:sender
{
NSArray *pArray;
EOGenericRecord *employee;
NSEnumerator *epEnumerator;
EOGenericRecord *empProject;
pArray = [projectsForEmployeeController selectedObjects];
employee = [(id)[projectsForEmployeeController dataSource] masterObject];
epEnumerator = [[employee objectForKey:@"toEmpProjects"] objectEnumerator];
[dbContext beginTransaction];
while((empProject=[epEnumerator nextObject]) != nil)
if([pArray indexOfObjectIdenticalTo:[empProject objectForKey:@"toProject"]]!=NSNotFound)
[dbChannel deleteObject:empProject];
[dbContext commitTransaction];
[employeeController fetch];
return self;
}
/******************************************************************************
* Generate unique keys for the new object. Use the instance of UniqueKey
* to dole out a key from its internal buffer. The UniqueKey object has its
* own channel to the DB which it uses to allocate blocks of keys.
******************************************************************************/
- (BOOL)controller:(EOController *)controller willInsertObject:object atIndex: (unsigned)newIndex
{
if(controller==employeeController) {
NSArray *emptyArray1 = [[[NSArray alloc] init] autorelease];
NSArray *emptyArray2 = [[[NSArray alloc] init] autorelease];
NSNumber *empId = [NSNumber numberWithInt:[employeeUniqueKey nextKey]];
[object setObject:empId forKey:@"EmpId"];
[object setObject:@"<FirstName>" forKey:@"FirstName"];
[object setObject:@"<LastName>" forKey:@"LastName"];
[object setObject:@"<Phone>" forKey:@"Phone"];
[object setObject:emptyArray1 forKey:@"toEmpProjects"];
[object setObject:emptyArray2 forKey:@"toProjects"];
return YES;
}
if(controller==projectController) {
NSArray *emptyArray1 = [[[NSArray alloc] init] autorelease];
NSArray *emptyArray2 = [[[NSArray alloc] init] autorelease];
NSNumber *projectId = [NSNumber numberWithInt:[projectUniqueKey nextKey]];
[object setObject:projectId forKey:@"ProjectId"];
[object setObject:@"<ProjectName>" forKey:@"ProjectName"];
[object setObject:emptyArray1 forKey:@"toEmpProjects"];
[object setObject:emptyArray2 forKey:@"toEmployees"];
return YES;
}
return NO;
}
/******************************************************************************
* When a project or employee is deleted, make sure we delete the entry in the
* empProject intermediate table. Both the project and employee entities have
* a toEmpProjects relationship which we can use to delete the intermediate
* table records.
******************************************************************************/
- (BOOL)controller:controller willDeleteObject:object
{
NSArray *epArray;
NSEnumerator *epEnumerator;
EOGenericRecord *empProject;
// The employee and project entities have a toEmpProjects
// relationship to the intermediate table
if(controller==projectController ||
controller==employeeController) {
[dbContext beginTransaction];
epArray=[object objectForKey:@"toEmpProjects"];
epEnumerator=[epArray objectEnumerator];
while((empProject = [epEnumerator nextObject]) != nil)
[dbChannel deleteObject:empProject];
[dbContext commitTransaction];
}
return YES;
}
/******************************************************************************
* Echo SQL when debug is enabled.
******************************************************************************/
- (EODelegateResponse)adaptorChannel:channel willEvaluateExpression:(NSMutableString *)expression
{
NSLog(expression);
return EODelegateApproves;
}
- (void)dealloc
{
[dbContext release];
[dbChannel release];
[projectEntity release];
[employeeEntity release];
[empProjectEntity release];
[projectUniqueKey release];
[employeeUniqueKey release];
[super dealloc];
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.