home *** CD-ROM | disk | FTP | other *** search
/ OpenStep (Enterprise) / OpenStepENTCD.toast / OEDEV / EODEV.Z / InsertionPopUpAssociation.m < prev    next >
Encoding:
Text File  |  1996-08-23  |  10.0 KB  |  320 lines

  1. /*
  2.         Copyright (c) 1996, NeXT Software, Inc.
  3.         All rights reserved.
  4.  
  5.         You may freely copy, distribute and reuse the code in this example.
  6.         NeXT disclaims any warranty of any kind, expressed or implied,
  7.         as to its fitness for any particular use.
  8. */
  9. #import <EOExtensions/InsertionPopUpAssociation.h>
  10. #import <EOExtensions/NSObjectAdditions.h>
  11.  
  12. static NSString *EOEnabledAspect     = @"enabled";
  13. static NSString *EOTitlesAspect     = @"titles";
  14. static NSString *EOSelectedTitleAspect     = @"selectedTitle";
  15. static NSString *EOSelectedTagAspect     = @"selectedTag";
  16. static NSString *EOSelectedObjectAspect = @"selectedObject";
  17.  
  18. #define POPUPASSOC_CURRENTVERSION 2
  19.  
  20. @implementation InsertionPopUpAssociation
  21. + (NSString *)displayName {
  22.     return @"EOPopupAssoc";
  23. }
  24.  
  25. + (BOOL)isUsableWithObject:(id)object
  26. {
  27.     return [object isKindOfClass:[NSPopUpButton class]];
  28. }
  29.  
  30. + (NSArray *)aspects
  31. {
  32.     static NSArray *array = nil;
  33.     if (!array)
  34.         array = [[NSArray alloc] initWithObjects:EOTitlesAspect, EOSelectedTitleAspect,EOSelectedTagAspect, EOSelectedObjectAspect, EOEnabledAspect, nil];
  35.     return array;
  36. }
  37.  
  38. + (NSArray *)aspectSignatures
  39. {
  40.     static NSArray *array = nil;
  41.     if (!array)
  42.         array = [[NSArray alloc] initWithObjects:@"A", @"A", @"A", @"1", @"A", nil];
  43.     return array;
  44. }
  45.  
  46. + (NSString *)primaryAspect {
  47.     return EOSelectedTitleAspect;
  48. }
  49.  
  50. + (NSArray *)objectKeysTaken {
  51.     static NSArray *array = nil;
  52.     if (!array)
  53.         array = [[NSArray alloc] initWithObjects:@"target", nil];
  54.     return array;
  55. }
  56.  
  57. + (NSArray *)associationClassesSuperseded
  58. {
  59.     return [NSArray arrayWithObject:[EOControlAssociation class]];
  60. }
  61.  
  62. - (void)establishConnection
  63. {
  64.     id object = [self object];
  65.     [super establishConnection];
  66.  
  67.     // Hack cast to get rid of warning about multiple declarations. 
  68.     [(NSControl *)object setTarget:self];
  69.     [object setAction:@selector(controlActed:)];
  70. }
  71.  
  72. + (void)initialize
  73. {
  74.     if (self == [InsertionPopUpAssociation class])
  75.         [EOPopUpAssociation setVersion:POPUPASSOC_CURRENTVERSION];
  76. }
  77.  
  78. - initWithObject:object
  79. {
  80.     [super initWithObject:object];
  81.     _tagValueForOther = -1;
  82.  
  83.     return self;
  84. }
  85.  
  86. - (void)setTagValueForOther:(int)newValue {
  87.     _tagValueForOther = newValue;
  88. }
  89. - (int)tagValueForOther {
  90.     return _tagValueForOther;
  91. }
  92.  
  93. - (void)setAutomaticallyInsertsObject:(BOOL)yn {
  94.     _autoInsertsObject = yn;
  95. }
  96. - (BOOL)automaticallyInsertsObject {
  97.     return _autoInsertsObject;
  98. }
  99.  
  100. - (NSArray *)titleArray {
  101.     EODisplayGroup *dest = [self displayGroupForAspect:EOTitlesAspect];
  102.     return [dest displayedObjects];
  103. }
  104.  
  105. - (NSArray *)valueArray {
  106.     EODisplayGroup *dest = [self displayGroupForAspect:EOTitlesAspect];
  107.     if (dest)
  108.         return [dest displayedObjects];
  109.     else
  110.         return [self titleArray];
  111. }
  112.  
  113. - (int)indexForTag:(int)tag
  114. // helper method, NSPopUpButton does not support tags
  115. {
  116.     NSPopUpButton *popup = [self object];
  117.     NSArray   *cells = [popup itemArray];
  118.     unsigned  i = [cells count];
  119.  
  120.     while (i--) {
  121.         id anObject = [cells objectAtIndex:i];
  122.         if ([anObject tag] == tag)
  123.             return i;
  124.     }
  125.     return -1;
  126. }
  127.  
  128. - (BOOL)autoPrependingOtherItem {
  129.     return [self displayGroupForAspect:EOTitlesAspect] && _autoInsertsObject;
  130. }
  131.  
  132. - (BOOL)indexForOtherItem {
  133.     int index = [self indexForTag:_tagValueForOther];
  134.     if ((index == -1) || [self autoPrependingOtherItem])
  135.         index = 0;
  136.     return index;
  137. }
  138.  
  139. - (int)objectIndexForPopupIndex:(int)index {
  140.     if ([self autoPrependingOtherItem])
  141.         return index-1;
  142.     return index;
  143. }
  144.  
  145. - (void)controlActed:sender
  146. {
  147.     // get currently selected item from itemlist and push it
  148.     // to our value
  149.     NSPopUpButton *popup = [self object];
  150.     int index = [popup indexOfSelectedItem];
  151.     EODisplayGroup *selectedObjectDisplayGroup, *selectedTitleDisplayGroup, *selectedTagDisplayGroup, *activeDisplayGroup;
  152.  
  153.     if (index == -1)
  154.         [NSException raise:NSInternalInconsistencyException format:@"popup sent action message but has no row selected!"];
  155.  
  156.     selectedTagDisplayGroup = [self displayGroupForAspect:EOSelectedTagAspect];
  157.     selectedObjectDisplayGroup = [self displayGroupForAspect:EOSelectedObjectAspect];
  158.     selectedTitleDisplayGroup = [self displayGroupForAspect:EOSelectedTitleAspect];    
  159.  
  160.     activeDisplayGroup = (selectedTitleDisplayGroup) ? selectedTitleDisplayGroup :
  161.         ((selectedObjectDisplayGroup) ? selectedObjectDisplayGroup : selectedTagDisplayGroup);
  162.     
  163.     // If we selected the first item, delete the object from the controller
  164.     if (index == [self indexForOtherItem]) {
  165.         [activeDisplayGroup delete:nil];
  166.         return;
  167.     }
  168.     
  169.     // If we selected and item an there's no object, insert one
  170.     // Set the related EO into the relationship property of the EO at the
  171.     // selected object aspect
  172.     if ([activeDisplayGroup selectedObject]==nil)
  173.         [activeDisplayGroup insert:nil];
  174.     
  175.     if (selectedObjectDisplayGroup) {
  176.         id valueEO, sourceEO;
  177.         NSArray * valueArray = [self valueArray];
  178.  
  179.         index = [self objectIndexForPopupIndex:index];
  180.         if (index >= [valueArray count]) {
  181.             if (_addedTempItem && (index == [valueArray count]))
  182.                 return;  // just reselected the current value
  183.  
  184.             [NSException raise:NSInternalInconsistencyException format:@"Popup index: %d past end of value array of length: %d", index, [valueArray count]];
  185.         }
  186.  
  187.         valueEO = [valueArray objectAtIndex:index];
  188.  
  189.         sourceEO = [selectedObjectDisplayGroup selectedObject];
  190.         [sourceEO addObject:valueEO toBothSidesOfRelationshipWithKey:[self displayGroupKeyForAspect:EOSelectedObjectAspect]];
  191.     }
  192.  
  193.     // set the title into the selectedTitle aspect
  194.     if (selectedTitleDisplayGroup) {
  195.         [self setValue:[popup stringValue] forAspect:EOSelectedTitleAspect];
  196.     }
  197.     
  198.     // set the tag into the selectedTag aspect
  199.     if (selectedTagDisplayGroup) {
  200.         [self setValue:[NSNumber numberWithInt:[[popup selectedItem] tag]] forAspect:EOSelectedTagAspect];
  201.     }
  202. }
  203.  
  204. - (void)subjectChanged
  205. {
  206.     // We have to update our itemlist, and them select and item in
  207.     // it corresponding to our value
  208.     id                eoValue;
  209.     NSPopUpButton      *popup = [self object];
  210.     EODisplayGroup     *titlesDisplayGroup = [self displayGroupForAspect:EOTitlesAspect];
  211.     unsigned               valueIndex;
  212.     EODisplayGroup     *selectedObjectDisplayGroup, *selectedTitleDisplayGroup, *selectedTagDisplayGroup;
  213.     NSArray           *titleEOs;
  214.     NSString           *titleKey;
  215.     BOOL         enabled = NO;
  216.     int index;
  217.     
  218.     if (_addedTempItem) {
  219.         [popup removeItemAtIndex:[popup numberOfItems]-1];
  220.         _addedTempItem = NO;
  221.     }
  222.  
  223.     if (titlesDisplayGroup) {
  224.         titleEOs = [titlesDisplayGroup displayedObjects];
  225.         titleKey = [self displayGroupKeyForAspect:EOTitlesAspect];
  226.  
  227.         if (([popup numberOfItems] != [titleEOs count]) || [titlesDisplayGroup contentsChanged])
  228.         {
  229.             NSArray *titles = [titleEOs arrayContainingValuesForKey:titleKey];
  230.             if (_autoInsertsObject) {
  231.                 // prepend "None" item
  232.                 titles = [[NSArray arrayWithObject:@"None"] arrayByAddingObjectsFromArray:titles];
  233.             }
  234.             [popup removeAllItems];
  235.             [popup addItemsWithTitles:titles];
  236.         }
  237.     }
  238.  
  239.     // We could either be trying to match on EO, or title depending on which aspect
  240.     // was wired up
  241.     if (titlesDisplayGroup && (selectedObjectDisplayGroup = [self displayGroupForAspect:EOSelectedObjectAspect])) {
  242.         // select the item in the list based on the current value
  243.         eoValue = [self valueForAspect:EOSelectedObjectAspect];
  244.  
  245.         if (eoValue) {
  246.             valueIndex = [titleEOs indexOfObjectIdenticalTo:eoValue];
  247.  
  248.             if (valueIndex == NSNotFound) {
  249.                 // add this item temporarily
  250.                 id eoValueTitle = [eoValue valueForKeyPath:titleKey];
  251.                 if (!eoValueTitle) eoValueTitle = @"";
  252.                 [popup setTitle:eoValueTitle];
  253.  
  254.                 if (![eoValueTitle isEqual:@""])
  255.                     _addedTempItem = YES;
  256.             } else {
  257.                 // select the item
  258.                 [popup selectItemAtIndex:valueIndex];
  259.             }
  260.         } else {
  261.             [popup selectItemAtIndex:[self indexForOtherItem]];
  262.         }
  263.         enabled = (eoValue != nil) || _autoInsertsObject;
  264.     } else if ((selectedTitleDisplayGroup = [self displayGroupForAspect:EOSelectedTitleAspect])) {
  265.         eoValue = [self valueForAspect:EOSelectedTitleAspect];
  266.         if (eoValue || !_autoInsertsObject) {
  267.             enabled = (eoValue != nil);
  268.             if (!eoValue) eoValue = @"";
  269.  
  270.             if (([popup indexOfItemWithTitle:eoValue] == -1) && ![eoValue isEqual:@""])
  271.                 _addedTempItem = YES;
  272.             [popup setTitle:eoValue]; // setTitle automatically adds item if title is new
  273.         } else {
  274.             [popup selectItemAtIndex:[self indexForOtherItem]];
  275.             enabled = YES;
  276.         }
  277.     }
  278.     else if ((selectedTagDisplayGroup = [self displayGroupForAspect:EOSelectedTagAspect])) {
  279.         eoValue = [self valueForAspect:EOSelectedTagAspect];
  280.         if (eoValue || !_autoInsertsObject) {
  281.             enabled = (eoValue != nil);
  282.             index = [self indexForTag:[eoValue intValue]];
  283.             if (index == -1) index = [self indexForOtherItem];
  284.             [popup selectItemAtIndex:index];
  285.         } else {
  286.             [popup selectItemAtIndex:[self indexForOtherItem]];
  287.             enabled = YES;
  288.         }
  289.     }
  290.     
  291.     if (enabled && [self displayGroupForAspect:EOEnabledAspect])
  292.         enabled = [[self valueForAspect:EOEnabledAspect] intValue];
  293.     if (enabled != [popup isEnabled])
  294.         [popup setEnabled:enabled];
  295. }
  296.  
  297. - (void)encodeWithCoder:(NSCoder *)coder
  298. {
  299.     [super encodeWithCoder:coder];
  300.  
  301.     [coder encodeValuesOfObjCTypes:"ii", &_tagValueForOther, &_autoInsertsObject];
  302. }
  303.  
  304. - (id)initWithCoder:(NSCoder *)coder
  305. {
  306.     int version = [coder versionForClassName:@"EOInsertionPopUpAssociation"];
  307.  
  308.     self = [super initWithCoder:coder];
  309.  
  310.     if (version == POPUPASSOC_CURRENTVERSION) {
  311.         [coder decodeValuesOfObjCTypes:"ii", &_tagValueForOther, &_autoInsertsObject];
  312.     }
  313.  
  314.     return self;
  315. }
  316.  
  317. @end
  318.  
  319.  
  320.