This is EOModelInspector.m in view mode; [Download] [Up]
/*-------------------------------------------------------------------------- * * You may freely copy, distribute, and reuse the code in this example. * SHL Systemhouse disclaims any warranty of any kind, expressed or * implied, as to its fitness for any particular use. * * * EOModelInspector * * Inherits From: WMInspector * * Conforms To: none * * Declared In: EOModelInspector.h * *------------------------------------------------------------------------*/ #import "EOModelInspector.h" #import "EOModelBrowserCell.h" #import "SwapView.h" #import "EntityPropertiesCategory.h" /*-------------------------------------------------------------------------- * Some basic macros for the cells of our matrices *------------------------------------------------------------------------*/ #define ADAPTOR [connectionDictionaryMatrix cellAt:0 :0] #define DB_AND_HOST [connectionDictionaryMatrix cellAt:1 :0] #define USER_AND_PASSWORD [connectionDictionaryMatrix cellAt:2 :0] #define VALUE_CLASS_AND_TYPE [attributeSettingsMatrix cellAt:0 :0] #define EXTERN_TYPE [attributeSettingsMatrix cellAt:1 :0] #define ATTRIBUTE_EXTERN_NAME [attributeSettingsMatrix cellAt:2 :0] #define CLASS [entitySettingsMatrix cellAt:0 :0] #define ENTITY_EXTERN_NAME [entitySettingsMatrix cellAt:1 :0] static id _SELF = nil; @implementation EOModelInspector + new { char path[MAXPATHLEN+1]; id bundle; if (_SELF) { return _SELF; } _SELF = self = [super new]; if (!(bundle = [NXBundle bundleForClass:[self class]])) { return nil; } if (![bundle getPath:path forResource:[(Object *)[self class] name] ofType:"nib"]) { return nil; } [NXApp loadNibFile:path owner:self withNames:NO fromZone:[(Object *)self zone]]; /* * Let's load in a bunch of images to be used in our inspector... */ if ([bundle getPath:path forResource:"SymbolKey" ofType:"tiff"]) { keyImage = [[NXImage alloc] initFromFile:path]; } else { NSLog (@"no key image: %s", path); } if ([bundle getPath:path forResource:"SymbolClass" ofType:"tiff"]) { classImage = [[NXImage alloc] initFromFile:path]; } else { NSLog (@"no class image: %s", path); } if ([bundle getPath:path forResource:"SymbolLock" ofType:"tiff"]) { lockImage = [[NXImage alloc] initFromFile:path]; } else { NSLog (@"no lock image: %s", path); } /* * Let's setup the splitview */ [splitView addSubview:connectionDictionaryView]; [splitView addSubview:browser]; [splitView addSubview:propertySwapView]; /* * Use our custom browser cell */ [browser setCellClass:[EOModelBrowserCell class]]; /* * We'll determine the column titles, thank you very much. */ [browser getTitleFromPreviousColumn:NO]; return _SELF; } - _entityForCurrentSelectionInColumn: (int) theColumn /*-------------------------------------------------------------------------- * Walks the browser from theColumn and finds/returns the entity that * corresponds to the current selection. Let's say I have a relationship * selected...I need to find out it's destination entity. * * NOTE: The reason this seems to be necessary is that when we go to * fill in a matrix column (after a relationship selection), all we * know is that we've got a selected cell, it has a name and a tag. * * More explanation of what we're doing here... *------------------------------------------------------------------------*/ { id /* * First let's get the "root" entity...that is the entity selected * the first column. */ myEntity = [[model entities] objectAtIndex:[[[browser matrixInColumn:0] selectedCell] tag]]; int x; /* * Now, let's walk from column 1, until we get to the * column that's selected... */ for (x = 1; x < theColumn; x++) { id myProperty; /* * Get the property */ myProperty = [[myEntity properties] objectAtIndex:[[[browser matrixInColumn:x] selectedCell] tag]]; if ([myProperty isKindOfClass:[EOAttribute class]]) { myEntity = [myProperty entity]; } else { myEntity = [myProperty destinationEntity]; } } return myEntity; } - (int) _fillInBrowserMatrix: theMatrix withEntities: (NSArray *) theEntities /*-------------------------------------------------------------------------- * Called by our browser delegate method, to fill in the given matrix * with "theEntities". This is only called for the first column. *------------------------------------------------------------------------*/ { int x = 0; id myCell, myEntity, myString; while (x < [theEntities count]) { myEntity = [theEntities objectAtIndex:x]; [theMatrix addRow]; myCell = [theMatrix cellAt:x :0]; [myCell setTag:x]; myString = [NSString stringWithFormat:@"%@", [(EOEntity *)myEntity name]]; [myCell setStringValue:[myString cString]]; if ([myEntity isReadOnly]) { [myCell setTextColor:NX_COLORDKGRAY]; } [myCell setLeaf:NO]; [myCell setLoaded:YES]; x++; } return x; } - (int) _fillInBrowserMatrix: theMatrix withPropertiesFromEntity: (EOEntity *) theEntity /*-------------------------------------------------------------------------- * Called by our browser delegate method, to fill in the given matrix * with the properties (attributes & relationships) for "theEntity". * This is called many times, particularly for a selected relationship * that must display the properties for its destination entity. *------------------------------------------------------------------------*/ { int x = 0; id myCell, myProperties = [theEntity properties], myProperty, myString; while (x < [myProperties count]) { myProperty = [myProperties objectAtIndex:x]; [theMatrix addRow]; myCell = [theMatrix cellAt:x :0]; [myCell setTag:x]; if ([myProperty isKindOfClass:[EOAttribute class]]) { myString = [NSString stringWithFormat:@"%@", [(EOAttribute *)myProperty name]]; if ([myProperty isReadOnly]) { [myCell setTextColor:NX_COLORDKGRAY]; } [myCell setLeaf:YES]; } else { myString = [NSString stringWithFormat:@"%@", [(EORelationship *)myProperty name]]; [myCell setIsRelationship:YES]; [myCell setIsToManyRelationship:[myProperty isToMany]]; [myCell setLeaf:NO]; } [myCell setStringValue:[myString cString]]; [myCell setLoaded:YES]; x++; } return x; } - revert: sender { char myPath[MAXPATHLEN+1]; /* * Let's get the path of the selected item */ [self selectionPathsInto:myPath separator:'\0']; /* * Let's get rid of the old model */ if (model) { [model release]; model = nil; } /* * Now create a model from our (.eomodel) file */ if (model = [[EOModel alloc] initWithContentsOfFile:[NSString stringWithCString:myPath]]) { id myConnectionDictionary, myString, myStringA, myStringB, myDatabaseKey, myHostKey, myPasswordKey, myUserNameKey, myStringTable; char myPath[MAXPATHLEN+1]; /* * Let's display the viewer */ [swapView swapView:[viewerPanel contentView]]; /* * Let's set the strings for the main model attributes * * adaptor name, database/server name, host name/machine, user name & password */ /* * First the adaptor name */ [ADAPTOR setStringValue:[[model adaptorName] cString]]; /* * Now we need the "connectionDictionary" to get the rest */ myConnectionDictionary = [model connectionDictionary]; /* * database/server name, host name/machine, get 'em then set 'em... * * Like: database/server_name (host_name/machine) * * NOTE: This is tricky, since the Sybase and Oracle adaptors use * slightly different keys (ARRRGGGHHH!). * * Sybase uses: databaseName & hostName * Oracle uses: serverId & hostMachine * * Okay...ready? Here's what we're gonna do. Assuming that these two * keys could be different for any adaptor (since NeXT was too stupid * to force 'em all to be the same), we'll simply gave a (string) table * for each kind of adaptor. This table will contain the keys: * "database" and "host" which will map to that specific adaptor's key * name. Then we'll use that value as a key to our dictionary to get * the real value that we want. Whew...follow? */ /* * Let's use Sybase's key names as a default... */ myDatabaseKey = [NSString stringWithCString:"databaseName"]; myHostKey = [NSString stringWithCString:"hostName"]; myPasswordKey = [NSString stringWithCString:"password"]; myUserNameKey = [NSString stringWithCString:"userName"]; /* * Now, let's get a ".strings" file of the same name as the adaptor * (according to the model)... */ [[NXBundle bundleForClass:[self class]] getPath:myPath forResource:[[model adaptorName] cString] ofType:"strings"]; /* * If there's such a file... */ if (*myPath) { /* * make a string table */ myStringTable = [[NXStringTable alloc] init]; /* * read from the file */ if ([myStringTable readFromFile:myPath]) { /* * get the values for our standard keys: "database" and "host" */ myDatabaseKey = [NSString stringWithCString:[myStringTable valueForStringKey:"database"]]; myHostKey = [NSString stringWithCString:[myStringTable valueForStringKey:"host"]]; myPasswordKey = [NSString stringWithCString:[myStringTable valueForStringKey:"password"]]; myUserNameKey = [NSString stringWithCString:[myStringTable valueForStringKey:"username"]]; } [myStringTable free]; } /* * Now we get a couple of strings based on our keys. * remember, is there was no file for this adaptor, we used defaults * which are Sybase (for now). */ myStringA = [myConnectionDictionary objectForKey:myDatabaseKey]; myStringB = [myConnectionDictionary objectForKey:myHostKey]; myString = [NSString stringWithFormat:@"%@ (%@)", myStringA, myStringB]; [DB_AND_HOST setStringValue:[myString cString]]; /* * user name & password, get 'em then set 'em... * * Like: user_name (password) */ myStringA = [myConnectionDictionary objectForKey:myUserNameKey]; myStringB = [myConnectionDictionary objectForKey:myPasswordKey]; myString = [NSString stringWithFormat:@"%@ (%@)", myStringA, myStringB]; [USER_AND_PASSWORD setStringValue:[myString cString]]; /* * Let's tell the browser to fill up, and force a click... */ [browser loadColumnZero]; [self itemSelect:nil]; } else { /* * If there was an error reading the file, let's display the error view */ [swapView swapView:[errorPanel contentView]]; } [super revert:sender]; return self; } - itemSelect: sender { if ([sender selectedColumn] > 0) { id myEntity = [self _entityForCurrentSelectionInColumn:[sender selectedColumn]], myProperty = [[myEntity properties] objectAtIndex:[[sender selectedCell] tag]]; if ([myProperty isKindOfClass:[EOAttribute class]]) { /* * Get the proper attribute (the for this column's selected cell). */ id myString; /* * Swap in the attribute view */ [propertySwapView swapView:[attributePanel contentView]]; [propertySwapView display]; if ([[[myProperty entity] primaryKeyAttributes] containsObject:myProperty]) { [attributeKeyButton setImage:[keyImage copy]]; } else { [attributeKeyButton setImage:nil]; } if ([[[myProperty entity] attributesUsedForLocking] containsObject:myProperty]) { [attributeLockingButton setImage:[lockImage copy]]; } else { [attributeLockingButton setImage:nil]; } if ([[[myProperty entity] classProperties] containsObject:myProperty]) { [attributeClassButton setImage:[classImage copy]]; } else { [attributeClassButton setImage:nil]; } /* * Set the "value classname" & "value type" string * * We don't want anything in parenthesis is there is no "value * type" (which is most cases). But, if I don't do the "if" here, * I get a string like: * * NSString (nil) * * Which isn't what I want. */ myString = [NSString stringWithFormat:@"%s", [myProperty valueClassName]]; if ([myProperty valueType]) { myString = [myString stringByAppendingFormat:@" (%@)", [myProperty valueType]]; } [VALUE_CLASS_AND_TYPE setStringValue:[myString cString]]; /* * Set the "external type" string */ [EXTERN_TYPE setStringValue:[[myProperty externalType] cString]]; if ([myProperty isDerived] || [myProperty isFlattened]) { [ATTRIBUTE_EXTERN_NAME setStringValue:[(NSString *)[myProperty definition] cString]]; } else { [ATTRIBUTE_EXTERN_NAME setStringValue:[(NSString *)[myProperty columnName] cString]]; } } else { /* * Swap in the relationship view */ [propertySwapView swapView:[relationshipPanel contentView]]; [propertySwapView display]; /* * Set our radio button to reflect the "manyness" of the * relationship. */ [relationshipManynessMatrix selectCellAt:0 :([myProperty isToMany] ? 1 : 0)]; } } else { /* * If there is no selected column, or it is the entities column, * there ARE NO attribute settings. */ id myEntity = [self _entityForCurrentSelectionInColumn:[sender selectedColumn]]; [propertySwapView swapView:[entityPanel contentView]]; [propertySwapView display]; [CLASS setStringValue:[myEntity className]]; [ENTITY_EXTERN_NAME setStringValue:[(NSString *)[myEntity externalName] cString]]; } return self; } /*-------------------------------------------------------------------------- * NXBrowser delegate methods *------------------------------------------------------------------------*/ - (int) browser: sender fillMatrix: matrix inColumn: (int) column { int x = 0; if (column == 0) { /* * If we're the "root" column... */ x = [self _fillInBrowserMatrix:matrix withEntities:[model entities]]; } else { /* * Otherwise... */ x = [self _fillInBrowserMatrix:matrix withPropertiesFromEntity:[self _entityForCurrentSelectionInColumn:column]]; } return x; } - (const char *) browser: sender titleOfColumn: (int) column { NSString *columnTitle; if (column == 0) { columnTitle = [NSString stringWithCString:"Entities"]; } else { columnTitle = [(EOEntity *)[self _entityForCurrentSelectionInColumn:column] name]; } return [columnTitle cString]; } /*-------------------------------------------------------------------------- * NXSplitView delegate methods *------------------------------------------------------------------------*/ - splitView:sender getMinY: (NXCoord *) minY maxY: (NXCoord *) maxY ofSubviewAt: (int) offset { switch (offset) { case 0: *minY = 0.0; *maxY = 45.0; break; case 1: *minY = 155.0; *maxY = 225.0; break; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.