Key binding patch by Chris Farber <chris@chrisfarber.net>.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@25724 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Fred Kiefer 2007-12-11 18:50:42 +00:00
parent f70a4455e6
commit 5966ffcd3f
8 changed files with 881 additions and 10 deletions

View file

@ -1,3 +1,14 @@
2007-12-11 Fred Kiefer <FredKiefer@gmx.de>
* Headers/AppKit/NSKeyValueBinding.h,
* Source/GSBindingHelpers.h,
* Source/NSKeyValueBinding.m: Basic key value binding implementation.
* Source/GNUmakefile: Add new source file.
* Source/externs.m: Variables for key binding.
* Source/NSTextField.m,
* Source/NSView.m: Class specific key bindings.
Patch by Chris Farber <chris@chrisfarber.net>.
2007-12-10 Fred Kiefer <FredKiefer@gmx.de>
* Source/NSColor.m (-numberOfComponents, -getComponents:): Raise

View file

@ -1,6 +1,6 @@
/** <title>NSKeyValueBinding</title>
<abstract>Interfae declaration for key value binding</abstract>
<abstract>Interface declaration for key value binding</abstract>
Copyright <copy>(C) 2006 Free Software Foundation, Inc.</copy>
@ -29,9 +29,11 @@
#ifndef _GNUstep_H_NSKeyValueBinding
#define _GNUstep_H_NSKeyValueBinding
#import <GNUstepBase/GSVersionMacros.h>
#include <Foundation/NSObject.h>
#include <AppKit/AppKitDefines.h>
#if OS_API_VERSION(100300,GS_API_LATEST)
#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST)
@class NSString;
@class NSArray;
@ -49,11 +51,9 @@
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options;
- (void) unbind: (NSString *)binding;
- (void) commitEditingWithDelegate: (id)delegate
didCommitSelector: (SEL)didCommitSelector
contextInfo: (void *)contextInfo;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST)
- (NSDictionary *) infoForBinding: (NSString *)binding;
#endif
@end
@interface NSObject (NSPlaceholder)
@ -71,6 +71,11 @@
- (BOOL) commitEditing;
- (void) discardEditing;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST)
- (void) commitEditingWithDelegate: (id)delegate
didCommitSelector: (SEL)didCommitSelector
contextInfo: (void *)contextInfo;
#endif
@end
@ -85,9 +90,10 @@
// binding values
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST)
// Keys in dictionary returned by infoForBinding
APPKIT_EXPORT NSString *NSObservedObjectKey;
APPKIT_EXPORT NSString *NSObservedKeyPath;
APPKIT_EXPORT NSString *NSObservedKeyPathKey;
APPKIT_EXPORT NSString *NSOptionsKey;
// special markers
@ -95,6 +101,44 @@ APPKIT_EXPORT id NSMultipleValuesMarker;
APPKIT_EXPORT id NSNoSelectionMarker;
APPKIT_EXPORT id NSNotApplicableMarker;
// Binding name constants
APPKIT_EXPORT NSString *NSAlignmentBinding;
APPKIT_EXPORT NSString *NSEditableBinding;
APPKIT_EXPORT NSString *NSEnabledBinding;
APPKIT_EXPORT NSString *NSFontBinding;
APPKIT_EXPORT NSString *NSHiddenBinding;
APPKIT_EXPORT NSString *NSSelectedIndexBinding;
APPKIT_EXPORT NSString *NSTextColorBinding;
APPKIT_EXPORT NSString *NSToolTipBinding;
APPKIT_EXPORT NSString *NSValueBinding;
//Binding options constants
APPKIT_EXPORT NSString *NSAllowsEditingMultipleValuesSelectionBindingOption;
APPKIT_EXPORT NSString *NSAllowsNullArgumentBindingOption;
APPKIT_EXPORT NSString *NSConditionallySetsEditableBindingOption;
APPKIT_EXPORT NSString *NSConditionallySetsEnabledBindingOption;
APPKIT_EXPORT NSString *NSConditionallySetsHiddenBindingOption;
APPKIT_EXPORT NSString *NSContinuouslyUpdatesValueBindingOption;
APPKIT_EXPORT NSString *NSCreatesSortDescriptorBindingOption;
APPKIT_EXPORT NSString *NSDeletesObjectsOnRemoveBindingsOption;
APPKIT_EXPORT NSString *NSDisplayNameBindingOption;
APPKIT_EXPORT NSString *NSDisplayPatternBindingOption;
APPKIT_EXPORT NSString *NSHandlesContentAsCompoundValueBindingOption;
APPKIT_EXPORT NSString *NSInsertsNullPlaceholderBindingOption;
APPKIT_EXPORT NSString *NSInvokesSeparatelyWithArrayObjectsBindingOption;
APPKIT_EXPORT NSString *NSMultipleValuesPlaceholderBindingOption;
APPKIT_EXPORT NSString *NSNoSelectionPlaceholderBindingOption;
APPKIT_EXPORT NSString *NSNotApplicablePlaceholderBindingOption;
APPKIT_EXPORT NSString *NSNullPlaceholderBindingOption;
APPKIT_EXPORT NSString *NSPredicateFormatBindingOption;
APPKIT_EXPORT NSString *NSRaisesForNotApplicableKeysBindingOption;
APPKIT_EXPORT NSString *NSSelectorNameBindingOption;
APPKIT_EXPORT NSString *NSSelectsAllWhenSettingContentBindingOption;
APPKIT_EXPORT NSString *NSValidatesImmediatelyBindingOption;
APPKIT_EXPORT NSString *NSValueTransformerNameBindingOption;
APPKIT_EXPORT NSString *NSValueTransformerBindingOption;
#endif
#endif // OS_API_VERSION
#endif // _GNUstep_H_NSKeyValueBinding

View file

@ -104,6 +104,7 @@ NSImageView.m \
NSInputManager.m \
NSInputServer.m \
NSInterfaceStyle.m \
NSKeyValueBinding.m \
NSLayoutManager.m \
NSLevelIndicator.m \
NSLevelIndicatorCell.m \

77
Source/GSBindingHelpers.h Normal file
View file

@ -0,0 +1,77 @@
/** Private Bindings helper functions for GNUstep
Copyright (C) 2007 Free Software Foundation, Inc.
Written by: Chris Farber <chris@chrisfarber.net>
Date: 2007
This file is part of the GNUstep GUI Library.
This 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 3 of the License, or (at your option) any later version.
This 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 this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _GS_BINDING_HELPER_H
#define _GS_BINDING_HELPER_H
@class NSString;
@class NSDictionary;
@class NSMutableDictionary;
@class NSArray;
typedef enum {
GSBindingOperationAnd = 0,
GSBindingOperationOr
} GSBindingOperationKind;
//Obtain a lock
void GSBindingLock();
//Releases the lock
void GSBindingReleaseLock();
//Get the mutable list of bindings for an object. You must obtain a lock
//with GSBindingLock() before calling this function and release the lock with
//GSBindingReleaseLock() when done with the dictionary.
NSMutableDictionary *GSBindingListForObject(id object);
//TODO: document
BOOL GSBindingResolveMultipleValueBool(NSString *key, NSDictionary *bindings,
GSBindingOperationKind operationKind);
//TODO: document
void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
NSDictionary *bindings);
NSArray *GSBindingExposeMultipleValueBindings(
NSArray *bindingNames,
NSMutableDictionary *bindingList);
NSArray *GSBindingExposePatternBindings(
NSArray *bindingNames,
NSMutableDictionary *bindingList);
void GSBindingUnbindAll(id object);
/* Transforms the value with a value transformer, if specified and available,
* and takes care of any placeholders
*/
id GSBindingTransformedValue(id value, NSDictionary *options);
id GSBindingReverseTransformedValue(id value, NSDictionary *options);
#endif //_GS_BINDING_HELPER_H

513
Source/NSKeyValueBinding.m Normal file
View file

@ -0,0 +1,513 @@
/** <title>NSKeyValueBinding informal protocol reference</title>
Implementation of KeyValueBinding for GNUStep
Copyright (C) 2007 Free Software Foundation, Inc.
Written by: Chris Farber <chris@chrisfarber.net>
Date: 2007
This file is part of the GNUstep GUI Library.
This 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 3 of the License, or (at your option) any later version.
This 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 this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSArray.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSKeyValueObserving.h>
#include <Foundation/NSKeyValueCoding.h>
#include <Foundation/NSValueTransformer.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSException.h>
#include <GNUstepBase/GSLock.h>
#include "AppKit/NSKeyValueBinding.h"
#include "GSBindingHelpers.h"
static NSRecursiveLock *bindingLock = nil;
static NSMapTable *classTable = NULL; //available bindings
static NSMapTable *objectTable = NULL; //bound bindings
static inline void setup()
{
if (bindingLock == nil)
{
bindingLock = [GSLazyRecursiveLock new];
classTable = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSOwnedPointerMapValueCallBacks, 128);
objectTable = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSOwnedPointerMapValueCallBacks, 128);
}
}
@implementation NSObject (NSKeyValueBindingCreation)
+ (void) exposeBinding: (NSString *)binding
{
NSMutableArray *bindings;
setup();
[bindingLock lock];
bindings = (NSMutableArray *)NSMapGet(classTable, (void*)self);
if (bindings == nil)
{
bindings = [NSMutableArray arrayWithCapacity: 15];
NSMapInsert(classTable, (void*)self, (void*)bindings);
}
[bindings addObject: binding];
[bindingLock unlock];
}
- (NSArray *) exposedBindings
{
NSMutableArray *exposedBindings = [NSMutableArray array];
NSArray *tmp;
Class class = [self class];
setup();
[bindingLock lock];
while (class && class != [NSObject class])
{
tmp = NSMapGet(classTable, (void*)class);
if (tmp != nil)
{
[exposedBindings addObjectsFromArray: tmp];
}
class = [class superclass];
}
[bindingLock unlock];
return exposedBindings;
}
- (Class) valueClassForBinding: (NSString *)binding
{
return [NSString class];
}
- (void)bind: (NSString *)binding
toObject: (id)anObject
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
NSMutableDictionary *bindings;
NSDictionary *info;
id newValue;
if ([[self exposedBindings] containsObject: binding])
{
[self unbind: binding];
info = [NSDictionary dictionaryWithObjectsAndKeys:
anObject, NSObservedObjectKey,
keyPath, NSObservedKeyPathKey,
options, NSOptionsKey,
nil];
[anObject addObserver: self
forKeyPath: keyPath
options: NSKeyValueObservingOptionNew
context: binding];
[bindingLock lock];
bindings = (NSMutableDictionary *)NSMapGet(objectTable, (void *)self);
if (bindings == nil)
{
bindings = [NSMutableDictionary dictionary];
NSMapInsert(objectTable, (void*)self, (void*)bindings);
}
[bindings setValue: info forKey: binding];
[bindingLock unlock];
newValue = [anObject valueForKeyPath: keyPath];
newValue = GSBindingTransformedValue(newValue, options);
[self setValue: newValue forKey: binding];
}
else
{
NSLog(@"No binding exposed on %@ for %@", self, binding);
}
}
- (NSDictionary *) infoForBinding: (NSString *)binding
{
NSMutableDictionary *bindings;
NSDictionary *info;
setup();
[bindingLock lock];
bindings = (NSMutableDictionary *)NSMapGet(objectTable, (void *)self);
if (bindings != nil)
{
info = [bindings objectForKey: binding];
}
[bindingLock unlock];
return [[info copy] autorelease];
}
- (void) unbind: (NSString *)binding
{
NSMutableDictionary *bindings;
NSDictionary *info;
id observedObject;
NSString *keyPath;
setup();
[bindingLock lock];
bindings = (NSMutableDictionary *)NSMapGet(objectTable, (void *)self);
if (bindings != nil)
{
info = [bindings objectForKey: binding];
if (info != nil)
{
observedObject = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
[observedObject removeObserver: self forKeyPath: keyPath];
[bindings setValue: nil forKey: binding];
}
}
[bindingLock unlock];
}
- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
NSMutableDictionary *bindings;
NSString *binding = (NSString *)context;
setup();
[bindingLock lock];
bindings = (NSMutableDictionary *)NSMapGet(objectTable, (void *)self);
if (bindings != nil)
{
NSDictionary *info;
info = [bindings objectForKey: binding];
if (info != nil)
{
NSDictionary *options;
id newValue;
options = [info objectForKey: NSOptionsKey];
newValue = [change objectForKey: NSKeyValueChangeNewKey];
newValue = GSBindingTransformedValue(newValue, options);
[self setValue: newValue forKey: binding];
}
}
[bindingLock unlock];
}
@end
//Helper functions
BOOL GSBindingResolveMultipleValueBool(NSString *key, NSDictionary *bindings,
GSBindingOperationKind operationKind)
{
NSString *bindingName;
NSDictionary *info;
int count = 1;
id object;
NSString *keyPath;
id value;
NSDictionary *options;
bindingName = key;
while ((info = [bindings objectForKey: bindingName]))
{
object = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
options = [info objectForKey: NSOptionsKey];
value = [object valueForKeyPath: keyPath];
value = GSBindingTransformedValue(value, options);
if ([value boolValue] == operationKind)
{
return operationKind;
}
bindingName = [NSString stringWithFormat: @"%@%i", key, ++count];
}
return !operationKind;
}
void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
NSDictionary *bindings)
{
NSString *bindingName;
NSDictionary *info;
NSDictionary *options;
int count = 1;
id object;
id target;
SEL selector;
NSString *keyPath;
NSInvocation *invocation;
info = [bindings objectForKey: targetKey];
object = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
options = [info objectForKey: NSOptionsKey];
target = [object valueForKeyPath: keyPath];
selector = NSSelectorFromString([options objectForKey:
NSSelectorNameBindingOption]);
if (target == nil || selector == NULL) return;
invocation = [NSInvocation invocationWithMethodSignature:
[target methodSignatureForSelector: selector]];
[invocation setSelector: selector];
bindingName = argumentKey;
while ((info = [bindings objectForKey: bindingName]))
{
object = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
if ((object = [object valueForKeyPath: keyPath]))
{
[invocation setArgument: object atIndex: ++count];
}
bindingName = [NSString stringWithFormat: @"%@%i", argumentKey, count];
}
[invocation invoke];
}
void GSBindingLock()
{
[bindingLock lock];
}
void GSBindingReleaseLock()
{
[bindingLock unlock];
}
NSMutableDictionary * GSBindingListForObject(id object)
{
NSMutableDictionary * list;
list = (NSMutableDictionary *) NSMapGet(objectTable, (void *)object);
if (list == nil)
{
list = [NSMutableDictionary dictionary];
NSMapInsert(objectTable, (void *)object, (void *)list);
}
return list;
}
void GSBindingUnbindAll(id object)
{
NSEnumerator *enumerator;
NSString *binding;
NSArray *bindings;
[bindingLock lock];
bindings = [(GSBindingListForObject(object)) allKeys];
enumerator = [bindings objectEnumerator];
while ((binding = [enumerator nextObject]))
{
[object unbind: binding];
}
NSMapRemove(objectTable, (void *)object);
[bindingLock unlock];
}
NSArray *GSBindingExposeMultipleValueBindings(
NSArray *bindingNames,
NSMutableDictionary *bindingList)
{
NSEnumerator *nameEnum;
NSString *name;
NSString *numberedName;
NSMutableArray *additionalBindings;
int count;
additionalBindings = [NSMutableArray array];
nameEnum = [bindingNames objectEnumerator];
while ((name = [nameEnum nextObject]))
{
count = 1;
numberedName = name;
while ([bindingList objectForKey: numberedName] != nil)
{
numberedName = [NSString stringWithFormat: @"%@%i", name, ++count];
[additionalBindings addObject: numberedName];
}
}
return additionalBindings;
}
NSArray *GSBindingExposePatternBindings(
NSArray *bindingNames,
NSMutableDictionary *bindingList)
{
NSEnumerator *nameEnum;
NSString *name;
NSString *numberedName;
NSMutableArray *additionalBindings;
int count;
additionalBindings = [NSMutableArray array];
nameEnum = [bindingNames objectEnumerator];
while ((name = [nameEnum nextObject]))
{
count = 1;
numberedName = [NSString stringWithFormat:@"%@1", name];
while ([bindingList objectForKey: numberedName] != nil)
{
numberedName = [NSString stringWithFormat:@"%@%i", name, ++count];
[additionalBindings addObject: numberedName];
}
}
return additionalBindings;
}
id GSBindingTransformedValue(id value, NSDictionary *options)
{
NSString *valueTransformerName;
NSValueTransformer *valueTransformer;
NSString *placeholder;
if (value == NSMultipleValuesMarker)
{
placeholder = [options objectForKey: NSMultipleValuesPlaceholderBindingOption];
if (placeholder == nil)
{
placeholder = @"Multiple Values";
}
return placeholder;
}
if (value == NSNoSelectionMarker)
{
placeholder = [options objectForKey: NSNoSelectionPlaceholderBindingOption];
if (placeholder == nil)
{
placeholder = @"No Selection";
}
return placeholder;
}
if (value == NSNotApplicableMarker)
{
if ([[options objectForKey: NSRaisesForNotApplicableKeysBindingOption]
boolValue])
{
[NSException raise: NSGenericException
format: @"This binding does not accept not applicable keys"];
}
placeholder = [options objectForKey:
NSNotApplicablePlaceholderBindingOption];
if (placeholder == nil)
{
placeholder = @"Not Applicable";
}
return placeholder;
}
if (value == nil)
{
placeholder = [options objectForKey:
NSNullPlaceholderBindingOption];
if (placeholder == nil)
{
placeholder = @"";
}
return placeholder;
}
valueTransformerName = [options objectForKey:
NSValueTransformerNameBindingOption];
if (valueTransformerName != nil)
{
valueTransformer = [NSValueTransformer valueTransformerForName:
valueTransformerName];
}
else
{
valueTransformer = [options objectForKey:
NSValueTransformerBindingOption];
}
if (valueTransformer != nil)
{
value = [valueTransformer transformedValue: value];
}
return value;
}
id GSBindingReverseTransformedValue(id value, NSDictionary *options)
{
NSValueTransformer *valueTransformer;
NSString *valueTransformerName;
valueTransformerName = [options objectForKey:
NSValueTransformerNameBindingOption];
valueTransformer = [NSValueTransformer valueTransformerForName:
valueTransformerName];
if (valueTransformer && [[valueTransformer class]
allowsReverseTransformation])
{
value = [valueTransformer reverseTransformedValue: value];
}
return value;
}
/*
@interface _GSStateMarker : NSObject
{
NSString * description;
}
@end
@implementation _GSStateMarker
- (id) initWithType: (int)type
{
if (type == 0)
{
description = @"<MULTIPLE VALUES MARKER>";
}
else if (type == 1)
{
description = @"<NO SELECTION MARKER>";
}
else
{
description = @"<NOT APPLICABLE MARKER>";
}
return self;
}
- (id) valueForKey: (NSString *)key
{
return self;
}
- (id) retain { return self; }
- (oneway void) release {}
- (NSString *) description
{
return description;
}
@end
*/

View file

@ -36,6 +36,7 @@
#include <Foundation/NSNotification.h>
#include <Foundation/NSString.h>
#include <Foundation/NSValue.h>
#include <Foundation/NSKeyValueObserving.h>
#include "AppKit/NSApplication.h"
#include "AppKit/NSCursor.h"
@ -43,6 +44,9 @@
#include "AppKit/NSTextField.h"
#include "AppKit/NSTextFieldCell.h"
#include "AppKit/NSWindow.h"
#include "AppKit/NSKeyValueBinding.h"
#include "GSBindingHelpers.h"
static NSNotificationCenter *nc;
/*
@ -63,6 +67,11 @@ static Class textFieldCellClass;
textFieldCellClass = [NSTextFieldCell class];
usedCellClass = textFieldCellClass;
nc = [NSNotificationCenter defaultCenter];
[self exposeBinding: NSEditableBinding];
[self exposeBinding: NSEnabledBinding];
[self exposeBinding: NSAlignmentBinding];
[self exposeBinding: NSFontBinding];
}
}
@ -731,5 +740,111 @@ static Class textFieldCellClass;
return self;
}
//
// Bindings
//
/*
* Bindings implemented:
* alignment, hidden, editable, enabled, font, toolTip
*
* Bindings left to implement:
* other font bindings, value, displayPatternValue1
*/
- (void) bind: (NSString *)binding
toObject: (id)object
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
NSMutableDictionary *bindings;
NSDictionary *info;
BOOL bVal;
if ([binding hasPrefix: NSEditableBinding])
{
[self unbind: binding];
[object addObserver: self
forKeyPath: keyPath
options: 0
context: NSEditableBinding];
info = [NSDictionary dictionaryWithObjectsAndKeys:
object, NSObservedObjectKey,
keyPath, NSObservedKeyPathKey,
options, NSOptionsKey,
nil];
GSBindingLock();
bindings = GSBindingListForObject(self);
[bindings setValue: info forKey: binding];
bVal = GSBindingResolveMultipleValueBool(NSHiddenBinding, bindings,
GSBindingOperationAnd);
GSBindingReleaseLock();
[self setEditable: bVal];
}
else if ([binding hasPrefix: NSEnabledBinding])
{
[object addObserver: self
forKeyPath: keyPath
options: 0
context: NSEnabledBinding];
info = [NSMutableDictionary dictionaryWithObjectsAndKeys:
object, NSObservedObjectKey,
keyPath, NSObservedKeyPathKey,
options, NSOptionsKey,
nil];
[self unbind: binding];
GSBindingLock();
bindings = GSBindingListForObject(self);
[bindings setValue: info forKey: binding];
bVal = GSBindingResolveMultipleValueBool(NSHiddenBinding, bindings,
GSBindingOperationAnd);
GSBindingReleaseLock();
[self setEnabled: bVal];
}
else
{
[super bind: binding
toObject: object
withKeyPath: keyPath
options: options];
}
}
- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
BOOL bVal;
NSDictionary *bindings;
if (context == NSEditableBinding)
{
GSBindingLock();
bindings = GSBindingListForObject(self);
bVal = GSBindingResolveMultipleValueBool(NSEditableBinding, bindings,
GSBindingOperationAnd);
GSBindingReleaseLock();
[self setEditable: bVal];
}
else if (context == NSEnabledBinding)
{
GSBindingLock();
bindings = GSBindingListForObject(self);
bVal = GSBindingResolveMultipleValueBool(NSEnabledBinding, bindings,
GSBindingOperationAnd);
GSBindingReleaseLock();
[self setEnabled: bVal];
}
else
{
[super observeValueForKeyPath: keyPath
ofObject: object
change: change
context: context];
}
}
@end

View file

@ -41,6 +41,7 @@
#include <Foundation/NSCalendarDate.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSKeyedArchiver.h>
#include <Foundation/NSKeyValueObserving.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSThread.h>
#include <Foundation/NSLock.h>
@ -62,6 +63,7 @@
#include "AppKit/NSClipView.h"
#include "AppKit/NSFont.h"
#include "AppKit/NSGraphics.h"
#include "AppKit/NSKeyValueBinding.h"
#include "AppKit/NSMenu.h"
#include "AppKit/NSPasteboard.h"
#include "AppKit/NSPrintInfo.h"
@ -74,6 +76,7 @@
#include "GNUstepGUI/GSDisplayServer.h"
#include "GNUstepGUI/GSTrackingRect.h"
#include "GSToolTips.h"
#include "GSBindingHelpers.h"
/*
* We need a fast array that can store objects without retain/release ...
@ -431,6 +434,10 @@ GSSetDragTypes(NSView* obj, NSArray *types)
rectClass = [GSTrackingRect class];
NSDebugLLog(@"NSView", @"Initialize NSView class\n");
[self setVersion: 1];
// expose bindings
[self exposeBinding: NSToolTipBinding];
[self exposeBinding: NSHiddenBinding];
}
}
@ -504,6 +511,8 @@ GSSetDragTypes(NSView* obj, NSArray *types)
NSView *tmp;
unsigned count;
GSBindingUnbindAll(self);
while ([_sub_views count] > 0)
{
[[_sub_views lastObject] removeFromSuperviewWithoutNeedingDisplay];
@ -4718,5 +4727,70 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
return YES;
}
- (void) bind: (NSString *)binding
toObject: (id)object
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
NSMutableDictionary *bindings;
NSDictionary *info;
BOOL hidden;
if ([binding hasPrefix: NSHiddenBinding])
{
[self unbind: binding];
[object addObserver: self
forKeyPath: keyPath
options: 0
context: NSHiddenBinding];
info = [NSDictionary dictionaryWithObjectsAndKeys:
object, NSObservedObjectKey,
keyPath, NSObservedKeyPathKey,
options, NSOptionsKey,
nil];
GSBindingLock();
bindings = GSBindingListForObject(self);
[bindings setValue: info forKey: binding];
hidden = GSBindingResolveMultipleValueBool(NSHiddenBinding, bindings,
GSBindingOperationOr);
GSBindingReleaseLock();
[self setHidden: hidden];
}
else
{
[super bind: binding
toObject: object
withKeyPath: keyPath
options: options];
}
}
- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
BOOL hidden;
NSDictionary * bindings;
if (context == NSHiddenBinding)
{
GSBindingLock();
bindings = GSBindingListForObject(self);
hidden = GSBindingResolveMultipleValueBool(NSHiddenBinding, bindings,
GSBindingOperationOr);
GSBindingReleaseLock();
[self setHidden: hidden];
}
else
{
[super observeValueForKeyPath: keyPath
ofObject: object
change: change
context: context];
}
}
@end

View file

@ -592,9 +592,45 @@ const NSWindowDepth _GSWindowDepths[7] = { 258, 264, 514, 516, 517, 520, 0 };
/* End of color functions externs */
// NSKeyValueBinding
NSString *NSObservedObjectKey = @"NSObservedObjectKey";
NSString *NSObservedKeyPath = @"NSObservedKeyPath";
NSString *NSOptionsKey = @"NSOptionsKey";
NSString *NSObservedObjectKey = @"NSObservedObject";
NSString *NSObservedKeyPathKey = @"NSObservedKeyPath";
NSString *NSOptionsKey = @"NSOptions";
NSString *NSAllowsEditingMultipleValuesSelectionBindingOption = @"NSAllowsEditingMultipleValuesSelection";
NSString *NSAllowsNullArgumentBindingOption = @"NSAllowsNullArgument";
NSString *NSConditionallySetsEditableBindingOption = @"NSConditionallySetsEditable";
NSString *NSConditionallySetsEnabledBindingOption = @"NSConditionallySetsEnabled";
NSString *NSConditionallySetsHiddenBindingOption = @"NSConditionallySetsHidden";
NSString *NSContinuouslyUpdatesValueBindingOption = @"NSContinuouslyUpdatesValue";
NSString *NSCreatesSortDescriptorBindingOption = @"NSCreatesSortDescriptor";
NSString *NSDeletesObjectsOnRemoveBindingsOption = @"NSDeletesObjectsOnRemove";
NSString *NSDisplayNameBindingOption = @"NSDisplayName";
NSString *NSDisplayPatternBindingOption = @"NSDisplayPattern";
NSString *NSHandlesContentAsCompoundValueBindingOption = @"NSHandlesContentAsCompoundValue";
NSString *NSInsertsNullPlaceholderBindingOption = @"NSInsertsNullPlaceholder";
NSString *NSInvokesSeparatelyWithArrayObjectsBindingOption = @"NSInvokesSeparatelyWithArrayObjects";
NSString *NSMultipleValuesPlaceholderBindingOption = @"NSMultipleValuesPlaceholder";
NSString *NSNoSelectionPlaceholderBindingOption = @"NSNoSelectionPlaceholder";
NSString *NSNotApplicablePlaceholderBindingOption = @"NSNotApplicablePlaceholder";
NSString *NSNullPlaceholderBindingOption = @"NSNullPlaceholder";
NSString *NSPredicateFormatBindingOption = @"NSPredicateFormat";
NSString *NSRaisesForNotApplicableKeysBindingOption = @"NSRaisesForNotApplicableKeys";
NSString *NSSelectorNameBindingOption = @"NSSelectorName";
NSString *NSSelectsAllWhenSettingContentBindingOption = @"NSSelectsAllWhenSettingContent";
NSString *NSValidatesImmediatelyBindingOption = @"NSValidatesImmediately";
NSString *NSValueTransformerNameBindingOption = @"NSValueTransformerName";
NSString *NSValueTransformerBindingOption = @"NSValueTransformer";
NSString *NSAlignmentBinding = @"alignment";
NSString *NSEditableBinding = @"editable";
NSString *NSEnabledBinding = @"enabled";
NSString *NSFontBinding = @"font";
NSString *NSHiddenBinding = @"hidden";
NSString *NSSelectedIndexBinding = @"selectedIndex";
NSString *NSTextColorBinding = @"textColor";
NSString *NSToolTipBinding = @"toolTip";
NSString *NSValueBinding = @"value";
// FIXME: Need to defined!
id NSMultipleValuesMarker = nil;
id NSNoSelectionMarker = nil;