home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (c) 1996, NeXT Software, Inc.
- All rights reserved.
-
- 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 <EOExtensions/InsertionPopUpAssociation.h>
- #import <EOExtensions/NSObjectAdditions.h>
-
- static NSString *EOEnabledAspect = @"enabled";
- static NSString *EOTitlesAspect = @"titles";
- static NSString *EOSelectedTitleAspect = @"selectedTitle";
- static NSString *EOSelectedTagAspect = @"selectedTag";
- static NSString *EOSelectedObjectAspect = @"selectedObject";
-
- #define POPUPASSOC_CURRENTVERSION 2
-
- @implementation InsertionPopUpAssociation
- + (NSString *)displayName {
- return @"EOPopupAssoc";
- }
-
- + (BOOL)isUsableWithObject:(id)object
- {
- return [object isKindOfClass:[NSPopUpButton class]];
- }
-
- + (NSArray *)aspects
- {
- static NSArray *array = nil;
- if (!array)
- array = [[NSArray alloc] initWithObjects:EOTitlesAspect, EOSelectedTitleAspect,EOSelectedTagAspect, EOSelectedObjectAspect, EOEnabledAspect, nil];
- return array;
- }
-
- + (NSArray *)aspectSignatures
- {
- static NSArray *array = nil;
- if (!array)
- array = [[NSArray alloc] initWithObjects:@"A", @"A", @"A", @"1", @"A", nil];
- return array;
- }
-
- + (NSString *)primaryAspect {
- return EOSelectedTitleAspect;
- }
-
- + (NSArray *)objectKeysTaken {
- static NSArray *array = nil;
- if (!array)
- array = [[NSArray alloc] initWithObjects:@"target", nil];
- return array;
- }
-
- + (NSArray *)associationClassesSuperseded
- {
- return [NSArray arrayWithObject:[EOControlAssociation class]];
- }
-
- - (void)establishConnection
- {
- id object = [self object];
- [super establishConnection];
-
- // Hack cast to get rid of warning about multiple declarations.
- [(NSControl *)object setTarget:self];
- [object setAction:@selector(controlActed:)];
- }
-
- + (void)initialize
- {
- if (self == [InsertionPopUpAssociation class])
- [EOPopUpAssociation setVersion:POPUPASSOC_CURRENTVERSION];
- }
-
- - initWithObject:object
- {
- [super initWithObject:object];
- _tagValueForOther = -1;
-
- return self;
- }
-
- - (void)setTagValueForOther:(int)newValue {
- _tagValueForOther = newValue;
- }
- - (int)tagValueForOther {
- return _tagValueForOther;
- }
-
- - (void)setAutomaticallyInsertsObject:(BOOL)yn {
- _autoInsertsObject = yn;
- }
- - (BOOL)automaticallyInsertsObject {
- return _autoInsertsObject;
- }
-
- - (NSArray *)titleArray {
- EODisplayGroup *dest = [self displayGroupForAspect:EOTitlesAspect];
- return [dest displayedObjects];
- }
-
- - (NSArray *)valueArray {
- EODisplayGroup *dest = [self displayGroupForAspect:EOTitlesAspect];
- if (dest)
- return [dest displayedObjects];
- else
- return [self titleArray];
- }
-
- - (int)indexForTag:(int)tag
- // helper method, NSPopUpButton does not support tags
- {
- NSPopUpButton *popup = [self object];
- NSArray *cells = [popup itemArray];
- unsigned i = [cells count];
-
- while (i--) {
- id anObject = [cells objectAtIndex:i];
- if ([anObject tag] == tag)
- return i;
- }
- return -1;
- }
-
- - (BOOL)autoPrependingOtherItem {
- return [self displayGroupForAspect:EOTitlesAspect] && _autoInsertsObject;
- }
-
- - (BOOL)indexForOtherItem {
- int index = [self indexForTag:_tagValueForOther];
- if ((index == -1) || [self autoPrependingOtherItem])
- index = 0;
- return index;
- }
-
- - (int)objectIndexForPopupIndex:(int)index {
- if ([self autoPrependingOtherItem])
- return index-1;
- return index;
- }
-
- - (void)controlActed:sender
- {
- // get currently selected item from itemlist and push it
- // to our value
- NSPopUpButton *popup = [self object];
- int index = [popup indexOfSelectedItem];
- EODisplayGroup *selectedObjectDisplayGroup, *selectedTitleDisplayGroup, *selectedTagDisplayGroup, *activeDisplayGroup;
-
- if (index == -1)
- [NSException raise:NSInternalInconsistencyException format:@"popup sent action message but has no row selected!"];
-
- selectedTagDisplayGroup = [self displayGroupForAspect:EOSelectedTagAspect];
- selectedObjectDisplayGroup = [self displayGroupForAspect:EOSelectedObjectAspect];
- selectedTitleDisplayGroup = [self displayGroupForAspect:EOSelectedTitleAspect];
-
- activeDisplayGroup = (selectedTitleDisplayGroup) ? selectedTitleDisplayGroup :
- ((selectedObjectDisplayGroup) ? selectedObjectDisplayGroup : selectedTagDisplayGroup);
-
- // If we selected the first item, delete the object from the controller
- if (index == [self indexForOtherItem]) {
- [activeDisplayGroup delete:nil];
- return;
- }
-
- // If we selected and item an there's no object, insert one
- // Set the related EO into the relationship property of the EO at the
- // selected object aspect
- if ([activeDisplayGroup selectedObject]==nil)
- [activeDisplayGroup insert:nil];
-
- if (selectedObjectDisplayGroup) {
- id valueEO, sourceEO;
- NSArray * valueArray = [self valueArray];
-
- index = [self objectIndexForPopupIndex:index];
- if (index >= [valueArray count]) {
- if (_addedTempItem && (index == [valueArray count]))
- return; // just reselected the current value
-
- [NSException raise:NSInternalInconsistencyException format:@"Popup index: %d past end of value array of length: %d", index, [valueArray count]];
- }
-
- valueEO = [valueArray objectAtIndex:index];
-
- sourceEO = [selectedObjectDisplayGroup selectedObject];
- [sourceEO addObject:valueEO toBothSidesOfRelationshipWithKey:[self displayGroupKeyForAspect:EOSelectedObjectAspect]];
- }
-
- // set the title into the selectedTitle aspect
- if (selectedTitleDisplayGroup) {
- [self setValue:[popup stringValue] forAspect:EOSelectedTitleAspect];
- }
-
- // set the tag into the selectedTag aspect
- if (selectedTagDisplayGroup) {
- [self setValue:[NSNumber numberWithInt:[[popup selectedItem] tag]] forAspect:EOSelectedTagAspect];
- }
- }
-
- - (void)subjectChanged
- {
- // We have to update our itemlist, and them select and item in
- // it corresponding to our value
- id eoValue;
- NSPopUpButton *popup = [self object];
- EODisplayGroup *titlesDisplayGroup = [self displayGroupForAspect:EOTitlesAspect];
- unsigned valueIndex;
- EODisplayGroup *selectedObjectDisplayGroup, *selectedTitleDisplayGroup, *selectedTagDisplayGroup;
- NSArray *titleEOs;
- NSString *titleKey;
- BOOL enabled = NO;
- int index;
-
- if (_addedTempItem) {
- [popup removeItemAtIndex:[popup numberOfItems]-1];
- _addedTempItem = NO;
- }
-
- if (titlesDisplayGroup) {
- titleEOs = [titlesDisplayGroup displayedObjects];
- titleKey = [self displayGroupKeyForAspect:EOTitlesAspect];
-
- if (([popup numberOfItems] != [titleEOs count]) || [titlesDisplayGroup contentsChanged])
- {
- NSArray *titles = [titleEOs arrayContainingValuesForKey:titleKey];
- if (_autoInsertsObject) {
- // prepend "None" item
- titles = [[NSArray arrayWithObject:@"None"] arrayByAddingObjectsFromArray:titles];
- }
- [popup removeAllItems];
- [popup addItemsWithTitles:titles];
- }
- }
-
- // We could either be trying to match on EO, or title depending on which aspect
- // was wired up
- if (titlesDisplayGroup && (selectedObjectDisplayGroup = [self displayGroupForAspect:EOSelectedObjectAspect])) {
- // select the item in the list based on the current value
- eoValue = [self valueForAspect:EOSelectedObjectAspect];
-
- if (eoValue) {
- valueIndex = [titleEOs indexOfObjectIdenticalTo:eoValue];
-
- if (valueIndex == NSNotFound) {
- // add this item temporarily
- id eoValueTitle = [eoValue valueForKeyPath:titleKey];
- if (!eoValueTitle) eoValueTitle = @"";
- [popup setTitle:eoValueTitle];
-
- if (![eoValueTitle isEqual:@""])
- _addedTempItem = YES;
- } else {
- // select the item
- [popup selectItemAtIndex:valueIndex];
- }
- } else {
- [popup selectItemAtIndex:[self indexForOtherItem]];
- }
- enabled = (eoValue != nil) || _autoInsertsObject;
- } else if ((selectedTitleDisplayGroup = [self displayGroupForAspect:EOSelectedTitleAspect])) {
- eoValue = [self valueForAspect:EOSelectedTitleAspect];
- if (eoValue || !_autoInsertsObject) {
- enabled = (eoValue != nil);
- if (!eoValue) eoValue = @"";
-
- if (([popup indexOfItemWithTitle:eoValue] == -1) && ![eoValue isEqual:@""])
- _addedTempItem = YES;
- [popup setTitle:eoValue]; // setTitle automatically adds item if title is new
- } else {
- [popup selectItemAtIndex:[self indexForOtherItem]];
- enabled = YES;
- }
- }
- else if ((selectedTagDisplayGroup = [self displayGroupForAspect:EOSelectedTagAspect])) {
- eoValue = [self valueForAspect:EOSelectedTagAspect];
- if (eoValue || !_autoInsertsObject) {
- enabled = (eoValue != nil);
- index = [self indexForTag:[eoValue intValue]];
- if (index == -1) index = [self indexForOtherItem];
- [popup selectItemAtIndex:index];
- } else {
- [popup selectItemAtIndex:[self indexForOtherItem]];
- enabled = YES;
- }
- }
-
- if (enabled && [self displayGroupForAspect:EOEnabledAspect])
- enabled = [[self valueForAspect:EOEnabledAspect] intValue];
- if (enabled != [popup isEnabled])
- [popup setEnabled:enabled];
- }
-
- - (void)encodeWithCoder:(NSCoder *)coder
- {
- [super encodeWithCoder:coder];
-
- [coder encodeValuesOfObjCTypes:"ii", &_tagValueForOther, &_autoInsertsObject];
- }
-
- - (id)initWithCoder:(NSCoder *)coder
- {
- int version = [coder versionForClassName:@"EOInsertionPopUpAssociation"];
-
- self = [super initWithCoder:coder];
-
- if (version == POPUPASSOC_CURRENTVERSION) {
- [coder decodeValuesOfObjCTypes:"ii", &_tagValueForOther, &_autoInsertsObject];
- }
-
- return self;
- }
-
- @end
-
-
-