libs-gdl2/EOInterface/EODisplayGroup.m
Matt Rice b70ec2777a * EOInterface/EOAssociation.m: New variable _objectToAssociations.
(+objectDeallocated:): New private method.
(+initialize): initialize _objectToAssociations.
(-dealloc): Discard any pending notifications.
(-establishConnection): Retain display groups we're bound to.
Retain our self and register our object for dealloc notification.
(-breakConnection): Release display groups we're bound to. Release
our self and discard any pending notifications.
(-subjectChanged): Add comment

* EOInterface/EOColumnAssociation.m (-establishConnection): Assign our
dg ivar after establishing connection.  Use the dg ivar and move 2 if
statements into one.

* EOInterface/EODisplayGroup.m: Remove debugging class/category for
emptyArray and emptyDictionary.
(-indexesForObjectsIndeticalTo:): Fix typo by renaming to
-indexesForObjectsIdenticalTo:.
(-dealloc): Remove our self as an observer for any notifications,
as an editor or message handler for our editing context, our observer
proxies as observers from the observer center. Don't release
array/dictionary ivars that are emptyArray or emptyDictionary.
(-setSelectionIndexes:): Update to reflect change in method name.
(-deleteSelection): Remove unused local var.
(-fetch:): Call -redisplay.
(-updatedObjectIndex:): Return -1 instead of 0 until this is
implemented.
(-setValue:forObject:key:): fix comment in exception handlers.

* EOInterface/EOGenericControlAssociation.m:
(-subjectChanged:): Remove unused local variable.

* EOMasterDetailAssociation.m:
(-establishConnection, -breakConnection, -subjectChanged): Implement.

* EOInterface/EOPopUpAssociation.m: Remove unused local variables.

* EOInterface/EOTableViewAssociation.m:
(-breakConnection:): Remove our NSTableView object from the map table.
(-subjectChanged:): Remove unused local variables. Release temporary
retain on selection indexes.
(+bindToTableView:displayGroup:): Don't retain the table views in the
map table.  Release the newly created association.
(-dealloc): Remove self from the tvAssociationMap.

* EOInterface/SubclassFlags.h: Fix bitmask on MatchKey1AspectMask.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@21439 72102866-910b-0410-8b05-ffd578937521
2005-07-09 03:01:22 +00:00

1131 lines
26 KiB
Objective-C

/*
EODisplayGroup.m
Copyright (C) 2004 Free Software Foundation, Inc.
Author: David Ayers <d.ayers@inode.at>
This file is part of the GNUstep Database Library
The GNUstep Database Library is free software; you can redistribute it
and/or modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2,
or (at your option) any later version.
The GNUstep Database Library is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNUstep Database Library; see the file COPYING. If not,
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
RCS_ID("$Id$")
#ifdef GNUSTEP
#include <Foundation/NSArray.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSException.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSString.h>
#include <Foundation/NSValue.h>
#include <AppKit/NSPanel.h>
#else
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#endif
#include <EOControl/EOClassDescription.h>
#include <EOControl/EODataSource.h>
#include <EOControl/EOEditingContext.h>
#include <EOControl/EOKeyValueCoding.h>
#include <EOControl/EOObserver.h>
#include <EOControl/EOQualifier.h>
#include <EOControl/EOSortOrdering.h>
#include "EODisplayGroup.h"
#include "EODeprecated.h"
#include "EOAssociation.h"
#include <limits.h>
#define DG_SHOULD_CHANGE_SELECTION_TO_IDX \
@selector(displayGroup:shouldChangeSelectionToIndexes:)
#define DG_DISPLAY_ARRAY_FOR_OBJECTS \
@selector(displayGroup:displayArrayForObjects:)
#define DG_SHOULD_DISPLAY_ALERT \
@selector(displayGroup:shouldDisplayAlertWithTitle:message:)
#define DG_DID_FETCH_OBJECTS \
@selector(displayGroup:didFetchObjects:)
#define DG_CREATE_OBJECT_FAILED \
@selector(displayGroup:createObjectFailedForDataSource:)
#define DG_SHOULD_INSERT_OBJECT \
@selector(displayGroup:shouldInsertObject:atIndex:)
#define DG_DID_INSERT_OBJECT \
@selector(displayGroup:didInsertObject:)
#define DG_DID_CHANGE_SELECTION \
@selector(displayGroupDidChangeSelection:)
/* undocumented notification */
NSString *EODisplayGroupWillFetchNotification = @"EODisplayGroupWillFetch";
@interface NSArray (private)
- (NSArray *)indexesForObjectsIdenticalTo: (NSArray *)array;
@end
@implementation NSArray (private)
- (NSArray *)indexesForObjectsIdenticalTo: (NSArray *)array
{
unsigned idx, i, c = [array count];
NSMutableArray *indices = (id)[NSMutableArray arrayWithCapacity: c];
id object;
NSNumber *number;
for (i = 0; i < c; i++)
{
object = [array objectAtIndex: i];
idx = [self indexOfObjectIdenticalTo: object];
if (idx != NSNotFound)
{
/* We should cache all these numbers. */
number = [NSNumber numberWithUnsignedInt: idx];
[indices addObject: number];
}
}
return AUTORELEASE ([indices copy]);
}
@end
@interface EODisplayGroup (private)
- (void)_presentAlertWithTitle:(NSString *)title
message:(NSString *)message;
@end
@implementation EODisplayGroup (private)
- (void)_presentAlertWithTitle:(NSString *)title
message:(NSString *)message
{
if (_delegate
&& [_delegate respondsToSelector: DG_SHOULD_DISPLAY_ALERT]
&& [_delegate displayGroup: self
shouldDisplayAlertWithTitle: title
message: message] == NO)
{
return;
}
NSRunAlertPanel(title, message, nil, nil, nil);
}
@end
/**
* The EODisplayGoup keeps track of all enterprise objects from
* a particular EODataSource to coordinate their internal state
* with other objects such as UI elements and other EODisplayGroups.
* Commonly the data source is a EODatabaseDataSource (EOAccess)
* which manages the objects of a single entity for a specific
* editing context. The display group is connected to the UI elements
* or other display groups via EOAssociations. This framework is
* responsible to update the enterprise objects when the contents
* and state of the UI elements are changed and to update the UI
* elements when the state of the enterprise objects are changed.
*/
@implementation EODisplayGroup
NSArray *emptyArray;
NSDictionary *emptyDictionary;
+ (void)initialize
{
if (emptyArray == nil)
{
emptyArray = [NSArray new];
emptyDictionary = [NSDictionary new];
}
}
static NSString *_globalDefaultStringMatchOperator = @"caseInsensitiveLike";
+ (NSString *)globalDefaultStringMatchOperator
{
return _globalDefaultStringMatchOperator;
}
+ (void)setGlobalDefaultStringMatchOperator: (NSString *)operator
{
ASSIGNCOPY(_globalDefaultStringMatchOperator, operator);
}
static BOOL _globalDefaultForValidatesChangesImmediately = NO;
+ (BOOL)globalDefaultForValidatesChangesImmediately
{
return _globalDefaultForValidatesChangesImmediately;
}
+ (void)setGlobalDefaultForValidatesChangesImmediately: (BOOL)flag
{
_globalDefaultForValidatesChangesImmediately = flag ? YES : NO;
}
- (id)init
{
if ((self = [super init]))
{
_allObjects = [NSMutableArray new];
_displayedObjects = [NSMutableArray new];
_selection = emptyArray;
_observerNotificationBeginProxy
= [[EOObserverProxy alloc] initWithTarget: self
action:
@selector(_beginObserverNotification:)
priority: EOObserverPriorityFirst];
[EOObserverCenter addObserver: _observerNotificationBeginProxy
forObject: self];
_observerNotificationEndProxy
= [[EOObserverProxy alloc] initWithTarget: self
action:
@selector(_endObserverNotification:)
priority: EOObserverPrioritySixth];
[EOObserverCenter addObserver: _observerNotificationEndProxy
forObject: self];
_insertedObjectDefaultValues = emptyDictionary;
_queryMatch = [NSMutableDictionary new];
_queryMin = [NSMutableDictionary new];
_queryMax = [NSMutableDictionary new];
_queryOperator = [NSMutableDictionary new];
_defaultStringMatchOperator
= [[self class] globalDefaultStringMatchOperator];
_defaultStringMatchFormat = @"%@*";
_queryBindings = [NSMutableDictionary new];
_flags.selectsFirstObjectAfterFetch = YES;
_flags._initialized = YES;
}
return self;
}
- (void)dealloc
{
EOEditingContext *context = [_dataSource editingContext];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[context removeEditor:self];
if ([context messageHandler] == self)
[context setMessageHandler:nil];
DESTROY(_dataSource);
if (_allObjects != emptyArray)
DESTROY(_allObjects);
DESTROY(_displayedObjects);
if (_selection != emptyArray)
DESTROY(_selection);
DESTROY(_sortOrdering);
DESTROY(_qualifier);
DESTROY(_localKeys);
DESTROY(_selectedObjects);
[EOObserverCenter removeObserver:_observerNotificationBeginProxy
forObject:self];
[EOObserverCenter removeObserver:_observerNotificationEndProxy
forObject:self];
DESTROY(_observerNotificationBeginProxy);
DESTROY(_observerNotificationEndProxy);
if (_insertedObjectDefaultValues != emptyDictionary)
DESTROY(_insertedObjectDefaultValues);
DESTROY(_savedAllObjects);
DESTROY(_queryMatch);
DESTROY(_queryMin);
DESTROY(_queryMax);
DESTROY(_queryOperator);
DESTROY(_defaultStringMatchOperator);
DESTROY(_defaultStringMatchFormat);
DESTROY(_queryBindings);
DESTROY(_editingAssociation);
[super dealloc];
}
- (id) initWithCoder:(NSCoder *)decoder
{
int tmpI;
self = [self init];
[self setDataSource:[decoder decodeObject]];
_delegate = [decoder decodeObject];
ASSIGN(_sortOrdering, [decoder decodeObject]);
ASSIGN(_qualifier, [decoder decodeObject]);
ASSIGN(_localKeys, [decoder decodeObject]);
/* encode _query*, _defaultStringMatch* ?? */
[decoder decodeValueOfObjCType: @encode(int) at: &tmpI];
_flags.selectsFirstObjectAfterFetch = tmpI;
[decoder decodeValueOfObjCType: @encode(int) at: &tmpI];
_flags.autoFetch = tmpI;
return self;
}
- (void)encodeWithCoder: (NSCoder *)encoder
{
int tmpI;
[encoder encodeObject: _dataSource];
[encoder encodeObject: _delegate];
[encoder encodeObject: _sortOrdering];
[encoder encodeObject: _qualifier];
[encoder encodeObject: _localKeys];
tmpI = _flags.selectsFirstObjectAfterFetch;
[encoder encodeValueOfObjCType: @encode(int) at: &tmpI];
tmpI = _flags.autoFetch;
[encoder encodeValueOfObjCType: @encode(int) at: &tmpI];
}
- (BOOL)fetchesOnLoad
{
return _flags.autoFetch;
}
- (void)setFetchesOnLoad: (BOOL)flag
{
_flags.autoFetch = flag ? YES : NO;
}
- (BOOL)selectsFirstObjectAfterFetch
{
return _flags.selectsFirstObjectAfterFetch;
}
- (void)setSelectsFirstObjectAfterFetch: (BOOL)flag
{
_flags.selectsFirstObjectAfterFetch = flag ? YES : NO;
}
- (BOOL)validatesChangesImmediately
{
return _flags.validateImmediately;
}
- (void)setValidatesChangesImmediately: (BOOL)flag
{
_flags.validateImmediately = flag ? YES : NO;
}
- (BOOL)usesOptimisticRefresh
{
return _flags.optimisticRefresh;
}
- (void)setUsesOptimisticRefresh: (BOOL)flag
{
_flags.optimisticRefresh = flag ? YES : NO;
}
- (NSDictionary *)queryBindingValues
{
return AUTORELEASE([_queryBindings copy]);
}
- (void)setQueryBindingValues: (NSDictionary *)values
{
ASSIGN(_queryBindings, [values mutableCopyWithZone: [self zone]]);
}
- (NSDictionary *)queryOperatorValues
{
return AUTORELEASE([_queryOperator copy]);
}
- (void)setQueryOperatorValues: (NSDictionary *)values
{
ASSIGN(_queryOperator,
AUTORELEASE([values mutableCopyWithZone: [self zone]]));
}
- (NSString *)defaultStringMatchFormat
{
return _defaultStringMatchFormat;
}
- (void)setDefaultStringMatchFormat: (NSString *)format
{
ASSIGNCOPY(_defaultStringMatchFormat, format);
}
- (NSString *)defaultStringMatchOperator
{
return _defaultStringMatchOperator;
}
- (void)setDefaultStringMatchOperator: (NSString *)operator
{
ASSIGNCOPY(_defaultStringMatchOperator, operator);
}
- (EODataSource *)dataSource
{
return _dataSource;
}
- (void)setDataSource: (EODataSource *)dataSource
{
if (_dataSource != dataSource)
{
EOEditingContext *context;
NSNotificationCenter *center;
center = [NSNotificationCenter defaultCenter];
if (_dataSource
&& (context = [_dataSource editingContext]))
{
[context removeEditor: self];
if ([context messageHandler] == self)
{
[context setMessageHandler: nil];
}
[center removeObserver: self
name: EOObjectsChangedInEditingContextNotification
object: context];
[center removeObserver: self
name: EOObjectsChangedInStoreNotification
object: context];
}
[self setObjectArray: nil];
ASSIGN(_dataSource, dataSource);
if ((context = [_dataSource editingContext]))
{
[context addEditor: self];
if ([context messageHandler] == nil)
{
[context setMessageHandler: self];
}
[center addObserver: self
selector: @selector(objectsInvalidatedInEditingContext:)
name: EOInvalidatedAllObjectsInStoreNotification
object: context];
[center addObserver: self
selector: @selector(objectsChangedInEditingContext:)
name: EOObjectsChangedInEditingContextNotification
object: context];
}
if (_delegate
&& [_delegate respondsToSelector:
@selector(displayGroupDidChangeDataSource:)])
{
[_delegate displayGroupDidChangeDataSource: self];
}
}
}
- (EOQualifier *)qualifier
{
return _qualifier;
}
- (void)setQualifier: (EOQualifier *)qualifier
{
ASSIGN(_qualifier, qualifier);
}
- (NSArray *)sortOrderings
{
return _sortOrdering;
}
- (void)setSortOrderings: (NSArray *)orderings
{
ASSIGNCOPY(_sortOrdering, orderings);
}
- (EOQualifier *)qualifierFromQueryValues
{
return nil;
}
- (NSDictionary *)equalToQueryValues
{
return nil;
}
- (void)setEqualToQueryValues: (NSDictionary *)values
{
}
- (NSDictionary *)greaterThanQueryValues
{
return nil;
}
- (void)setGreaterThanQueryValues: (NSDictionary *)values
{
}
- (NSDictionary *)lessThanQueryValues
{
return nil;
}
- (void)setLessThanQueryValues: (NSDictionary *)values
{
}
- (void)qualifyDisplayGroup
{
}
- (void)qualifyDataSource
{
}
- (BOOL)inQueryMode
{
return _flags.queryMode;
}
- (void)setInQueryMode: (BOOL)flag
{
_flags.queryMode = flag ? YES : NO;
}
- (BOOL)fetch
{
BOOL flag = YES;
if (_dataSource
&& (flag = [self endEditing]))
{
if (_delegate
&& [_delegate respondsToSelector:
@selector(displayGroupShouldFetch:)])
{
flag = [_delegate displayGroupShouldFetch: self];
}
if (flag)
{
NSNotificationCenter *center;
NSArray *objects;
center = [NSNotificationCenter defaultCenter];
[center postNotificationName: EODisplayGroupWillFetchNotification
object: self];
if ([_dataSource respondsToSelector:
@selector(setQualifierBindings:)])
{
[_dataSource setQualifierBindings: _queryBindings];
}
objects = [_dataSource fetchObjects];
[self setObjectArray: objects];
if (_delegate
&& [_delegate respondsToSelector: DG_DID_FETCH_OBJECTS])
{
[_delegate displayGroup: self
didFetchObjects: objects];
}
flag = objects ? YES : NO;
}
}
return flag;
}
- (NSArray *)allObjects
{
return AUTORELEASE([[NSArray alloc] initWithArray:_allObjects copyItems: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 redisplay];
}
- (NSArray *)displayedObjects
{
return AUTORELEASE([_displayedObjects copy]);
}
- (void)redisplay
{
/* TODO: Check this again! */
_flags.didChangeContents = YES;
[EOObserverCenter notifyObserversObjectWillChange: nil];
[self willChange];
}
- (void)updateDisplayedObjects
{
NSArray *oldSelection = [self selectedObjects];
volatile NSArray *displayedObjects = [self allObjects];
if (_delegate
&& [_delegate respondsToSelector: DG_DISPLAY_ARRAY_FOR_OBJECTS])
{
displayedObjects
= [_delegate displayGroup: self
displayArrayForObjects: (id)displayedObjects];
}
NS_DURING
{
displayedObjects
= [(id)displayedObjects filteredArrayUsingQualifier: _qualifier];
displayedObjects
= [(id)displayedObjects sortedArrayUsingKeyOrderArray: _sortOrdering];
}
NS_HANDLER
{
[self _presentAlertWithTitle:
@"Exception during sort or filter operatation."
message: [localException reason]];
}
NS_ENDHANDLER;
ASSIGN(_displayedObjects,
AUTORELEASE([(id)displayedObjects mutableCopyWithZone:[self zone]]));
[self selectObjectsIdenticalTo: oldSelection
selectFirstOnNoMatch: NO];
[self redisplay];
}
- (NSArray *)selectionIndexes
{
return _selection;
}
- (BOOL)setSelectionIndexes: (NSArray *)selection
{
if ([self endEditing] && selection)
{
if (_delegate
&& [_delegate respondsToSelector: DG_SHOULD_CHANGE_SELECTION_TO_IDX]
&& [_delegate displayGroup: self
shouldChangeSelectionToIndexes: selection] == NO)
{
return NO;
}
else
{
NSNumber *number;
NSArray *newSelection;
NSMutableArray *newObjects;
id object;
unsigned c, i, count, index;
count = [_displayedObjects count];
c = [selection count];
newObjects = (id)[NSMutableArray arrayWithCapacity: c];
for (i = 0; i < c; i++)
{
number = [selection objectAtIndex: i];
index = [number unsignedIntValue];
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])
{
[_delegate displayGroupDidChangeSelection:self];
}
[self willChange];
return YES;
}
}
return NO;
}
- (BOOL)selectObject: (id)object
{
NSArray *array;
if (object)
{
array = [NSArray arrayWithObject: object];
}
else
{
array = [NSArray array];
}
return [self selectObjectsIdenticalTo: array];
}
- (BOOL)selectObjectsIdenticalTo: (NSArray *)selection
{
NSArray *indices;
if (selection && [selection count])
{
indices = [_displayedObjects indexesForObjectsIdenticalTo: selection];
if (indices && ![indices count])
{
indices = nil;
}
}
else
{
indices = selection;
}
return [self setSelectionIndexes: indices];
}
- (BOOL)selectObjectsIdenticalTo: (NSArray *)selection
selectFirstOnNoMatch: (BOOL)flag
{
BOOL selectflag = [self selectObjectsIdenticalTo: selection];
if (selectflag && flag
&& [_selection count] == 0
&& [_displayedObjects count] != 0)
{
id object = [_displayedObjects objectAtIndex: 0];
selectflag = [self selectObject: object];
}
return selectflag;
}
- (BOOL)selectNext
{
return NO;
}
- (BOOL)selectPrevious
{
return NO;
}
- (BOOL)clearSelection
{
return [self setSelectionIndexes: emptyArray];
}
- (NSArray *)selectedObjects
{
return AUTORELEASE([_selectedObjects copy]);
}
- (void)setSelectedObjects: (NSArray *)objects
{
ASSIGN (_selectedObjects,
AUTORELEASE([objects mutableCopyWithZone: [self zone]]));
}
- (id)selectedObject
{
id object = nil;
if ([_selectedObjects count])
{
object = [_selectedObjects objectAtIndex: 0];
}
return object;
}
- (void)setSelectedObject: (id)object
{
if (object)
{
[self selectObject: object];
}
else
{
[self clearSelection];
}
}
- (id)insertObjectAtIndex: (unsigned)index
{
id object = nil;
if ([self endEditing])
{
object = [_dataSource createObject];
if (object == nil)
{
if (_delegate
&& [_delegate respondsToSelector: DG_CREATE_OBJECT_FAILED])
{
[_delegate displayGroup: self
createObjectFailedForDataSource: _dataSource];
}
else
{
[self _presentAlertWithTitle: @"EODisplayGroup"
message: @"Data source did not provide new object. "];
}
}
else
{
NSArray *defaultValueKeys = [_insertedObjectDefaultValues allKeys];
unsigned i, c = [defaultValueKeys count];
NSString *key;
id value;
/* We cannot use -takeValuesFromDictionary because
we need to call -takeValue:forKeyPath:. */
for (i = 0; i < c; i++)
{
key = [defaultValueKeys objectAtIndex: i];
value = [_insertedObjectDefaultValues valueForKeyPath: key];
[object smartTakeValue: value forKeyPath: key];
}
[self insertObject: object atIndex: index];
}
}
return object;
}
- (void)insertObject: (id)object atIndex: (unsigned)index
{
if ([self endEditing])
{
unsigned c = [_displayedObjects count];
if (c < index)
{
[NSException raise: NSRangeException
format: @"-[%@ %@]: Index %d is out of range %d",
NSStringFromClass([self class]),
NSStringFromSelector(_cmd),
index, c];
}
if (_delegate == nil
|| [_delegate respondsToSelector: DG_SHOULD_INSERT_OBJECT] == NO
|| [_delegate displayGroup: self
shouldInsertObject: object
atIndex: index])
{
NS_DURING
{
[_dataSource insertObject: object];
}
NS_HANDLER
{
[self _presentAlertWithTitle: @"EODisplayGroup insertion error"
message: [localException reason]];
return;
}
NS_ENDHANDLER;
/* It is safe to use the index for _allObjects but it seems
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])
{
[_delegate displayGroup: self didInsertObject: object];
}
[self selectObjectsIdenticalTo: [NSArray arrayWithObject: object]];
}
}
}
- (NSDictionary *)insertedObjectDefaultValues
{
return _insertedObjectDefaultValues;
}
- (void)setInsertedObjectDefaultValues: (NSDictionary *)values
{
(_insertedObjectDefaultValues == emptyDictionary) ? _insertedObjectDefaultValues = [values copy] : ASSIGNCOPY(_insertedObjectDefaultValues, values);
}
- (BOOL)deleteObjectAtIndex: (unsigned)index
{
return NO;
}
- (BOOL)deleteSelection
{
if ([self endEditing])
{
NSArray *selections = [self selectedObjects];
int c = [selections count];
int i;
for (i = 0; i < c; i++)
[[self dataSource] deleteObject: [selections objectAtIndex:i]];
}
return NO;
}
- (NSArray *)localKeys
{
return _localKeys;
}
- (void)setLocalKeys: (NSArray *)keys
{
ASSIGNCOPY(_localKeys, keys);
}
- (id)delegate
{
return _delegate;
}
- (void)setDelegate: (id)delegate
{
_delegate = delegate;
}
- (NSArray *)observingAssociations
{
/* not sure if this should be using an EOQualifier somehow */
NSMutableArray *oa = [[NSMutableArray alloc] init];
NSArray *observers = [EOObserverCenter observersForObject: self];
int i, count;
count = [observers count];
for (i = 0; i < count; i ++)
{
id currentObject = [observers objectAtIndex:i];
if ([currentObject isKindOfClass:[EOAssociation class]])
[oa addObject: currentObject];
}
return AUTORELEASE(oa);
}
- (EOAssociation *)editingAssociation
{
return _editingAssociation;
}
- (BOOL)endEditing
{
return _editingAssociation ? [_editingAssociation endEditing] : YES;
}
@end
@implementation EODisplayGroup (EODisplayGroupTargetAction)
/* TODO: check for return value handling and exception handling. */
- (void)selectNext: (id)sender
{
[self selectNext];
}
- (void)selectPrevious: (id)sender
{
[self selectPrevious];
}
- (void)fetch: (id)sender
{
[self fetch];
[self redisplay];
}
- (void)insert: (id)sender
{
unsigned idx = 0;
NSArray *selections = [self selectionIndexes];
if ([selections count])
{
NSNumber *index = [selections objectAtIndex: 0];
idx = [index unsignedIntValue];
}
[self insertObjectAtIndex: idx];
}
- (void)delete: (id)sender
{
[self deleteSelection];
}
- (void)qualifyDataSource: (id)sender
{
[self qualifyDataSource];
}
- (void)qualifyDisplayGroup: (id)sender
{
[self qualifyDisplayGroup];
}
- (void)enterQueryMode: (id)sender
{
[self setInQueryMode: YES];
}
@end
@implementation EODisplayGroup (EOAssociationInteraction)
- (BOOL)selectionChanged
{
return _flags.didChangeSelection;
}
- (BOOL)contentsChanged
{
return _flags.didChangeContents;
}
- (int)updatedObjectIndex
{
return -1;
}
- (id)valueForObject: (id)object key: (NSString *)key
{
return [object valueForKeyPath: key];
}
- (id)selectedObjectValueForKey: (NSString *)key
{
return [self valueForObject: [self selectedObject] key: key];
}
- (id)valueForObjectAtIndex: (unsigned)index key: (NSString *)key
{
return [self valueForObject: [_displayedObjects objectAtIndex: index]
key: key];
}
- (BOOL)setValue: (id)value forObject: (id)object key: (NSString *)key
{
SEL didSetValue = @selector(displayGroup:didSetValue:forKey:);
NSException *exception = nil;
NS_DURING
{
[object takeValue:value forKeyPath:key];
}
NS_HANDLER
/* -userInfo likely contains useful information... */
NSLog(@"Exception in %@ name:%@ reason:%@ userInfo:%@", NSStringFromSelector(_cmd), [localException name], [localException reason], [localException userInfo]);
return NO;
NS_ENDHANDLER
if ([self validatesChangesImmediately])
exception = [object validateValue: &value forKey: key];
if (exception == nil && [_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);
}
- (BOOL)setSelectedObjectValue: (id)value forKey: (NSString *)key
{
return [self setValue: value forObject: [self selectedObject] key: key];
}
- (BOOL)setValue: (id)value forObjectAtIndex: (unsigned)index
key: (NSString *)key
{
return [self setValue: value
forObject: [_displayedObjects objectAtIndex: index]
key: key];
}
- (BOOL)enabledToSetSelectedObjectValueForKey:(NSString *)key
{
return NO;
}
- (BOOL)association: (EOAssociation *)association
failedToValidateValue: (NSString *)value
forKey: (NSString *)key
object: (id)object
errorDescription: (NSString *)description
{
return NO;
}
- (void)associationDidBeginEditing: (EOAssociation *)association
{
ASSIGN(_editingAssociation,association);
}
- (void)associationDidEndEditing: (EOAssociation *)association
{
ASSIGN(_editingAssociation,nil);
}
@end
@implementation EODisplayGroup (EOEditors)
- (BOOL)editorHasChangesForEditingContext: (EOEditingContext *)editingContext
{
return NO;
}
- (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext
{
}
@end
@implementation EODisplayGroup (EOMessageHandlers)
- (void)editingContext: (EOEditingContext *)editingContext
presentErrorMessage: (NSString *)message
{
}
@end
@implementation EODisplayGroup (EODeprecated)
- (void)setSortOrdering: (NSArray *)sortOrderings
{
[self setSortOrderings: sortOrderings];
}
- (NSArray *)sortOrdering
{
return [self sortOrderings];
}
@end
@implementation EODisplayGroup (notifications)
- (void)objectsInvalidatedInEditingContext: (NSNotification *)notif
{
}
- (void)objectsChangedInEditingContext: (NSNotification *)notif
{
_flags.didChangeContents = YES;
[self willChange];
}
@end
@implementation EODisplayGroup (GDL2Private)
- (void) _beginObserverNotification:(id)sender
{
/* FIXME what goes here?? */
}
- (void) _endObserverNotification:(id)sender
{
_flags.didChangeContents = NO;
_flags.didChangeSelection = NO;
[EOObserverCenter notifyObserversObjectWillChange:nil];
}
@end