diff --git a/ChangeLog b/ChangeLog index 7a6dbb1..bdc2c0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,45 @@ -2006-31-08 Matt Rice - David Ayers +2006-05-09 Matt Rice + * EOInterface/EOAssociation.m (-establishConnection): Simplify to + allow posing. + (-canBindAspect:displayGroup:key:): Return YES by default. + * EOInterface/EOTextAssociation.m: Minor formatting issue. Include + privat header: + (-subjectChanged): Set empty string when nil/null value is set. + * EODisplayGroup.m (-initWithCoder:): Fetch when auto fetch is enabled. + (-setObjectArray:): Select new selected objects. + (-redisplay): Don't call notifyObserversObjectWillChange: explicitly. + (-setSelectionIndexes:): Implement displayGroup:didChangeSelection: + handling. + (-selectObjectsIdenticalTo:): Reimplement. + (-selectObjectsIdenticalTo:selectFirstOnNoMatch:): Ditto. + (-deleteSelection): Ditto. + (-insertObject:atIndex:): Fix redisplay timing with respect to + delegate. + (-deleteObjectAtIndex:): Implement. + (-association:failedToValidateValue:forKey:object:errorDescription:) + Ditto. + (-editorHasChangesForEditingContext:): Ditto. + (-editingContextWillSaveChanges:): Ditto. + (-setValue:forObjectAtIndex:key:): Validate index range. + (-objectsChangedInEditingContext:): Add workaround until issues + can be investigated. + * EOInterface/EOMasterDetailAssociation.m (subjectChanged): Qualify + datasource's relationship independent of selected object. + * EOInterface/EOTableViewAssociation.m (associationClassesSuperseded): + Implement. + (subjectChanged): Reimplement. + (tableViewSelectionDidChange:): Ditto. + +2006-05-09 Matt Rice + David Ayers + + * configure.ac (gorm-palette): Add configure option to exclude + building of palette until auto detection works reliably. + * config.make.in: New file. + * configure: Regenerate. + * GNUmakefile: Include new file. + * Makefile.postamble: Remove generated config.make on distclean. 2006-04-24 David Ayers diff --git a/EOInterface/EOAssociation.m b/EOInterface/EOAssociation.m index f099e0b..2293489 100644 --- a/EOInterface/EOAssociation.m +++ b/EOInterface/EOAssociation.m @@ -214,7 +214,6 @@ static NSMapTable *_objectToAssociations; { NSMapEnumerator displayGroupEnum; EODisplayGroup *displayGroup; - Class EOObserverCenterClass = [EOObserverCenter class]; void *unusedKey; GDL2NonRetainingMutableArray *associations; @@ -223,7 +222,7 @@ static NSMapTable *_objectToAssociations; &unusedKey, (void*)&displayGroup)) { [displayGroup retain]; - [EOObserverCenterClass addObserver: self forObject: displayGroup]; + [EOObserverCenter addObserver:self forObject:displayGroup]; } NSEndMapTableEnumeration (&displayGroupEnum); @@ -284,7 +283,7 @@ static NSMapTable *_objectToAssociations; displayGroup: (EODisplayGroup *)displayGroup key: (NSString *)key { - return NO; + return YES; } - (id)object diff --git a/EOInterface/EOColumnAssociation.m b/EOInterface/EOColumnAssociation.m index a48089e..aa40630 100644 --- a/EOInterface/EOColumnAssociation.m +++ b/EOInterface/EOColumnAssociation.m @@ -103,7 +103,7 @@ - (void)establishConnection { EODisplayGroup *dg; - + [super establishConnection]; dg = [self displayGroupForAspect:@"value"]; diff --git a/EOInterface/EODisplayGroup.m b/EOInterface/EODisplayGroup.m index fa6019a..657e1b8 100644 --- a/EOInterface/EODisplayGroup.m +++ b/EOInterface/EODisplayGroup.m @@ -73,6 +73,10 @@ RCS_ID("$Id$") @selector(displayGroup:didInsertObject:) #define DG_DID_CHANGE_SELECTION \ @selector(displayGroupDidChangeSelection:) +#define DG_DID_DELETE_OBJECT \ + @selector(displayGroup:didDeleteObject:) +#define DG_SHOULD_DELETE_OBJECT \ + @selector(displayGroup:shouldDeleteObject:) /* undocumented notification */ NSString *EODisplayGroupWillFetchNotification = @"EODisplayGroupWillFetch"; @@ -269,6 +273,10 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; _flags.selectsFirstObjectAfterFetch = tmpI; [decoder decodeValueOfObjCType: @encode(int) at: &tmpI]; _flags.autoFetch = tmpI; + if (_flags.autoFetch) + { + [self fetch]; + } return self; } @@ -506,7 +514,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; NSArray *objects; center = [NSNotificationCenter defaultCenter]; - [center postNotificationName: EODisplayGroupWillFetchNotification + [center postNotificationName: EODisplayGroupWillFetchNotification object: self]; if ([_dataSource respondsToSelector: @@ -517,7 +525,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; objects = [_dataSource fetchObjects]; [self setObjectArray: objects]; - + if (_delegate && [_delegate respondsToSelector: DG_DID_FETCH_OBJECTS]) { @@ -539,21 +547,19 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; - (void)setObjectArray: (NSArray *)objects { - NSArray *oldSelection = [self selectedObjects]; - BOOL selectFirstOnNoMatch = [self selectsFirstObjectAfterFetch]; - if (objects == nil) { objects = emptyArray; } - + ASSIGN(_allObjects, AUTORELEASE([objects mutableCopyWithZone: [self zone]])); [self updateDisplayedObjects]; - [self selectObjectsIdenticalTo: oldSelection - selectFirstOnNoMatch: selectFirstOnNoMatch]; + [self selectObjectsIdenticalTo:[self selectedObjects] + selectFirstOnNoMatch:_flags.selectsFirstObjectAfterFetch]; + [self redisplay]; } @@ -567,7 +573,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; { /* TODO: Check this again! */ _flags.didChangeContents = YES; - [EOObserverCenter notifyObserversObjectWillChange: nil]; +// [EOObserverCenter notifyObserversObjectWillChange: nil]; [self willChange]; } @@ -579,9 +585,8 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; if (_delegate && [_delegate respondsToSelector: DG_DISPLAY_ARRAY_FOR_OBJECTS]) { - displayedObjects - = [_delegate displayGroup: self - displayArrayForObjects: (id)displayedObjects]; + displayedObjects = [_delegate displayGroup: self + displayArrayForObjects: (id)displayedObjects]; } NS_DURING @@ -615,6 +620,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; - (BOOL)setSelectionIndexes: (NSArray *)selection { + if ([self endEditing] && selection) { if (_delegate @@ -632,6 +638,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; NSMutableArray *newObjects; id object; unsigned c, i, count, index; + count = [_displayedObjects count]; c = [selection count]; newObjects = (id)[NSMutableArray arrayWithCapacity: c]; @@ -640,24 +647,32 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; { number = [selection objectAtIndex: i]; index = [number unsignedIntValue]; - object = index < count - ? [_displayedObjects objectAtIndex: index] : nil; + object = (index < count) + ? [_displayedObjects objectAtIndex: index] + : nil; if (object != nil) { [newObjects addObject: object]; } } - ASSIGNCOPY(_selectedObjects, newObjects); - newSelection = - [_displayedObjects indexesForObjectsIdenticalTo: _selectedObjects]; - /* don't release emptyArray */ - (_selection == emptyArray) ? _selection = RETAIN(newSelection) : ASSIGN(_selection, newSelection); - _flags.didChangeSelection = YES; - if ([_delegate respondsToSelector: DG_DID_CHANGE_SELECTION]) + + if ([_selectedObjects isEqual:newObjects] == NO + || [_selection isEqual:selection] == NO) { - [_delegate displayGroupDidChangeSelection:self]; + ASSIGNCOPY(_selectedObjects, newObjects); + newSelection = [_displayedObjects + indexesForObjectsIdenticalTo: _selectedObjects]; + /* don't release emptyArray */ + (_selection == emptyArray) ? _selection = RETAIN(newSelection) + : ASSIGN(_selection, newSelection); + _flags.didChangeSelection = YES; + if ([_delegate respondsToSelector: DG_DID_CHANGE_SELECTION]) + { + [_delegate displayGroupDidChangeSelection:self]; + } + + [self willChange]; } - [self willChange]; return YES; } } @@ -681,35 +696,35 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; - (BOOL)selectObjectsIdenticalTo: (NSArray *)selection { NSArray *indices; - if (selection && [selection count]) - { - indices = [_displayedObjects indexesForObjectsIdenticalTo: selection]; - if (indices && ![indices count]) - { - indices = nil; - } - } - else - { - indices = selection; - } + indices = [_displayedObjects indexesForObjectsIdenticalTo: selection]; + if ([selection count] && ![indices count]) return NO; return [self setSelectionIndexes: indices]; } - (BOOL)selectObjectsIdenticalTo: (NSArray *)selection selectFirstOnNoMatch: (BOOL)flag { - BOOL selectflag = [self selectObjectsIdenticalTo: selection]; + BOOL selected = [self selectObjectsIdenticalTo: selection]; - if (selectflag && flag - && [_selection count] == 0 - && [_displayedObjects count] != 0) + if (!selected) { - id object = [_displayedObjects objectAtIndex: 0]; - selectflag = [self selectObject: object]; + unsigned c = [_displayedObjects count]; + if (flag && c != 0) + { + id object = [_displayedObjects objectAtIndex: 0]; + selected = [self selectObject: object]; + } + else if (c) + { + [self setSelectionIndexes:_selection]; + } + else + { + [self clearSelection]; + } } - - return selectflag; + + return selected; } - (BOOL)selectNext @@ -730,6 +745,7 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; { return AUTORELEASE([_selectedObjects copy]); } + - (void)setSelectedObjects: (NSArray *)objects { ASSIGN (_selectedObjects, @@ -836,7 +852,6 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; strange. OTOH _allObjects should probably be viewed as set. */ [_allObjects insertObject: object atIndex: index]; [_displayedObjects insertObject: object atIndex: index]; - [self redisplay]; if (_delegate && [_delegate respondsToSelector: DG_DID_INSERT_OBJECT]) @@ -844,7 +859,8 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; [_delegate displayGroup: self didInsertObject: object]; } - [self selectObjectsIdenticalTo: [NSArray arrayWithObject: object]]; + [self selectObject: object]; + [self redisplay]; } } } @@ -860,19 +876,52 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; - (BOOL)deleteObjectAtIndex: (unsigned)index { + id object = [_displayedObjects objectAtIndex:index]; + if (!_delegate + || ([_delegate respondsToSelector:DG_SHOULD_DELETE_OBJECT] + && [_delegate displayGroup:self shouldDeleteObject:object])) + { + NS_DURING + [_dataSource deleteObject:object]; + if ([_delegate respondsToSelector:DG_DID_DELETE_OBJECT]) + { + [_delegate displayGroup:self didDeleteObject:object]; + } + [_displayedObjects removeObjectAtIndex:index]; + [_allObjects removeObject:object]; + return YES; + NS_HANDLER + return NO; + NS_ENDHANDLER + } + return NO; } - (BOOL)deleteSelection { - if ([self endEditing]) + BOOL flag = YES; + NSArray *sel = [self selectionIndexes]; + int c = [sel count]; + + if (c == 0) { - NSArray *selections = [self selectedObjects]; - int c = [selections count]; - int i; - for (i = 0; i < c; i++) - [[self dataSource] deleteObject: [selections objectAtIndex:i]]; + return YES; } - return NO; + + if ((flag = [self endEditing])) + { + int i; + + [self redisplay]; + for (i = 0; i < c && flag; i++) + { + unsigned int index = [[sel objectAtIndex:i] unsignedIntValue]; + id selection = [self selectedObjects]; + flag = [self deleteObjectAtIndex:index]; + [self selectObjectsIdenticalTo:selection selectFirstOnNoMatch:NO]; + } + } + return flag; } - (NSArray *)localKeys @@ -1018,24 +1067,23 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; return NO; NS_ENDHANDLER - if ([self validatesChangesImmediately]) - exception = [object validateValue: &value forKey: key]; - - if (exception == nil && [_delegate respondsToSelector:didSetValue]) + exception = [object validateValue: &value forKey: key]; + + if (exception && _flags.validateImmediately) + { + [self _presentAlertWithTitle:@"Validation error" + message:[exception reason]]; + return NO; + } + else if ([_delegate respondsToSelector:didSetValue]) { [_delegate displayGroup: self didSetValue: value forObject: object key: key]; - return YES; } - if (exception) - { - /* -userInfo likely contains useful information... */ - NSLog(@"Exception in %@ name:%@ reason:%@ userInfo:%@", NSStringFromSelector(_cmd), [exception name], [exception reason], [exception userInfo]); - } - return (exception == nil); + return YES; } - (BOOL)setSelectedObjectValue: (id)value forKey: (NSString *)key @@ -1046,9 +1094,11 @@ static BOOL _globalDefaultForValidatesChangesImmediately = NO; - (BOOL)setValue: (id)value forObjectAtIndex: (unsigned)index key: (NSString *)key { - return [self setValue: value + if ([_displayedObjects count] > index) + return [self setValue: value forObject: [_displayedObjects objectAtIndex: index] key: key]; + return NO; } - (BOOL)enabledToSetSelectedObjectValueForKey:(NSString *)key @@ -1062,8 +1112,10 @@ failedToValidateValue: (NSString *)value object: (id)object errorDescription: (NSString *)description { + [self _presentAlertWithTitle:@"Validation error" message:description]; return NO; } + - (void)associationDidBeginEditing: (EOAssociation *)association { ASSIGN(_editingAssociation,association); @@ -1077,13 +1129,16 @@ failedToValidateValue: (NSString *)value @end @implementation EODisplayGroup (EOEditors) +/* FIXME GDL2 currently never calls this.. */ - (BOOL)editorHasChangesForEditingContext: (EOEditingContext *)editingContext { - return NO; + /* check */ + [self endEditing]; + return _flags.didChangeContents; } - (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext { - + [self endEditing]; } @end @@ -1109,11 +1164,27 @@ failedToValidateValue: (NSString *)value - (void)objectsInvalidatedInEditingContext: (NSNotification *)notif { } + - (void)objectsChangedInEditingContext: (NSNotification *)notif { +/* + // hmmm this doesn't work because of relationships.... (WHY?) + NSDictionary *userInfo = [notif userInfo]; + NSArray *upd = [userInfo objectForKey:EOUpdatedKey]; + NSArray *ins = [userInfo objectForKey:EOInsertedKey]; + NSArray *del = [userInfo objectForKey:EODeletedKey]; + _flags.didChangeContents = [_allObjects firstObjectCommonWithArray:upd] + || [_allObjects firstObjectCommonWithArray:ins] + || [_allObjects firstObjectCommonWithArray:del]; +*/ + /* FIXME this doesn't seem correct. + * display groups/data sources can share editing contexts. + * which will lead to spurious updates + */ _flags.didChangeContents = YES; [self willChange]; } + @end @implementation EODisplayGroup (GDL2Private) diff --git a/EOInterface/EOMasterDetailAssociation.m b/EOInterface/EOMasterDetailAssociation.m index a5ba33e..cdad86f 100644 --- a/EOInterface/EOMasterDetailAssociation.m +++ b/EOInterface/EOMasterDetailAssociation.m @@ -104,15 +104,11 @@ id selectedObject = [[self displayGroupForAspect:@"parent"] selectedObject]; id key = [self displayGroupKeyForAspect:@"parent"]; - if (selectedObject) - { - [[_object dataSource] + [[_object dataSource] qualifyWithRelationshipKey:key ofObject:selectedObject]; - - if ([_object fetch]) - [_object redisplay]; - } + if ([_object fetch]) + [_object redisplay]; } } diff --git a/EOInterface/EOTableViewAssociation.m b/EOInterface/EOTableViewAssociation.m index 62733d0..a2f2050 100644 --- a/EOInterface/EOTableViewAssociation.m +++ b/EOInterface/EOTableViewAssociation.m @@ -40,8 +40,8 @@ #include "EOColumnAssociation.h" #include "EODisplayGroup.h" - @implementation EOTableViewAssociation + static NSMapTable *tvAssociationMap; + (NSArray *)aspects { @@ -80,11 +80,29 @@ static NSMapTable *tvAssociationMap; } return _keys; } + + (BOOL)isUsableWithObject: (id)object { return [object isKindOfClass: [NSTableView class]]; } +@class EOControlAssociation; +@class EOPickTextAssociation; +@class EOActionAssociation; +@class EOActionInsertionAssociation; ++ (NSArray *) associationClassesSuperseded +{ + static NSArray *_superseded; + + if (!_superseded) + _superseded = [[NSArray arrayWithObjects:[EOControlAssociation class], + [EOPickTextAssociation class], + [EOActionAssociation class], + [EOActionInsertionAssociation class], + nil] retain]; + return _superseded; +} + + (NSString *)primaryAspect { return @"source"; @@ -118,22 +136,51 @@ static NSMapTable *tvAssociationMap; is not yet inserted */ if ([dg contentsChanged]) [[self object] reloadData]; - + + if ([dg selectionChanged]) { - NSArray *selectionIndexes = RETAIN([dg selectionIndexes]); - unsigned int i, count; - count = [selectionIndexes count]; - for (i = 0; i < count; i++) + if (!_extras) { - int rowIndex = [[selectionIndexes objectAtIndex:i] intValue]; - [[self object] selectRow: rowIndex - byExtendingSelection: (i != 0)]; /* don't extend the first selection */ - [[self object] scrollRowToVisible:rowIndex]; - } - RELEASE(selectionIndexes); + NSArray *selectionIndexes = RETAIN([dg selectionIndexes]); + unsigned int i, count; + count = [selectionIndexes count]; + if (count) + { + for (i = 0; i < count; i++) + { + int rowIndex = [[selectionIndexes objectAtIndex:i] intValue]; + + /* don't extend the first selection */ + [EOObserverCenter suppressObserverNotification]; + [[self object] selectRow: rowIndex + byExtendingSelection: (i != 0)]; + + [[self object] scrollRowToVisible:rowIndex]; + [EOObserverCenter enableObserverNotification]; + } + } + else + { + /* hmm not sure what to do about it if it doesn't allow empty + * selection. In that case NSTableView no-ops and the dg + * will think nothing is selected table view will leave + * whatever index was selected still selected. + */ + if ([[self object] allowsEmptySelection]) + { + [EOObserverCenter suppressObserverNotification]; + [[self object] deselectAll:self]; + [EOObserverCenter enableObserverNotification]; + } + else + NSLog(@"attempting to clear selection when table view won't allow empty selection"); + + } + RELEASE(selectionIndexes); + } + _extras = 0; } - } + (void)bindToTableView: (NSTableView *)tableView @@ -252,18 +299,21 @@ shouldEditTableColumn: (NSTableColumn *)tableColumn - (void)tableViewSelectionDidChange: (NSNotification *)notification { - EODisplayGroup *dg = [self displayGroupForAspect:@"source"]; - NSMutableArray *selectionIndices = [[NSMutableArray alloc] init]; - NSTableView *tv = [notification object]; - NSEnumerator *selectionEnum = [tv selectedRowEnumerator]; - id index; - - while ((index = [selectionEnum nextObject])) + _extras = 1; { - [selectionIndices addObject:index]; - } + EODisplayGroup *dg = [self displayGroupForAspect:@"source"]; + NSMutableArray *selectionIndices = [[NSMutableArray alloc] init]; + NSTableView *tv = [notification object]; + NSEnumerator *selectionEnum = [tv selectedRowEnumerator]; + id index; + + while ((index = [selectionEnum nextObject])) + { + [selectionIndices addObject:index]; + } - [dg setSelectionIndexes: AUTORELEASE(selectionIndices)]; + [dg setSelectionIndexes: AUTORELEASE(selectionIndices)]; + } } - (BOOL)control: (NSControl *)control diff --git a/EOInterface/EOTextAssociation.m b/EOInterface/EOTextAssociation.m index 9087e35..f6fc177 100644 --- a/EOInterface/EOTextAssociation.m +++ b/EOInterface/EOTextAssociation.m @@ -38,7 +38,7 @@ #include "EODisplayGroup.h" #include "EOTextAssociation.h" #include "SubclassFlags.h" - +#include "../EOControl/EOPrivate.h" @implementation EOTextAssociation + (NSArray *)aspects @@ -58,8 +58,7 @@ static NSArray *_signatures = nil; if (_signatures == nil) { - NSArray *arr = [NSArray arrayWithObjects: - @"A", @"A", @"A", nil]; + NSArray *arr = [NSArray arrayWithObjects:@"A", @"A", @"A", nil]; arr = [[super aspectSignatures] arrayByAddingObjectsFromArray: arr]; _signatures = RETAIN(arr); } @@ -99,15 +98,15 @@ if (subclassFlags & ValueAspectMask) { id value = [self valueForAspect:@"value"]; - if ([value isKindOfClass: [NSString class]]) + if ([value isKindOfClass:[NSString class]]) { [_object setString:value]; } - else if ([value isKindOfClass: [NSData class]]) + else if ([value isKindOfClass:[NSData class]]) { int oldLength = [[_object string] length]; [_object replaceCharactersInRange:NSMakeRange(0,oldLength) - withRTF: value]; + withRTF:value]; } } } @@ -139,13 +138,19 @@ int oldLength = [[_object string] length]; [_object replaceCharactersInRange:NSMakeRange(0,oldLength) withRTF: value]; + } + else if (_isNilOrEONull(value)) + { + [_object setString:@""]; + } } if (subclassFlags & EditableAspectMask) { [_object setEditable: [[self valueForAspect:@"editable"] boolValue]]; } } + - (BOOL)endEditing { BOOL flag = NO; @@ -162,10 +167,10 @@ { value = [[_object string] copy]; } - flag = [self setValue: value forAspect:@"value"]; + flag = [self setValue:value forAspect:@"value"]; if (flag) { - [[self displayGroupForAspect:@"value"] associationDidEndEditing: self]; } + [[self displayGroupForAspect:@"value"] associationDidEndEditing:self]; } } /* dunno if this is neccesary */ if (flag && (subclassFlags & EditableAspectMask)) @@ -175,7 +180,7 @@ return flag; } -- (BOOL)control: (NSControl *)control isValidObject: (id)object +- (BOOL)control:(NSControl *)control isValidObject:(id)object { /* FIXME */ NSLog(@"FIXME %@",NSStringFromSelector(_cmd));