1/** <title>NSMenuItem</title> 2 3 <abstract>The menu cell class.</abstract> 4 5 Copyright (C) 1996 Free Software Foundation, Inc. 6 7 Author: Ovidiu Predescu <ovidiu@net-community.com> 8 Date: May 1997 9 Author: David Lazaro Saz <khelekir@encomix.es> 10 Date: Sep 1999 11 12 This file is part of the GNUstep GUI Library. 13 14 This library is free software; you can redistribute it and/or 15 modify it under the terms of the GNU Lesser General Public 16 License as published by the Free Software Foundation; either 17 version 2 of the License, or (at your option) any later version. 18 19 This library is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 Lesser General Public License for more details. 23 24 You should have received a copy of the GNU Lesser General Public 25 License along with this library; see the file COPYING.LIB. 26 If not, see <http://www.gnu.org/licenses/> or write to the 27 Free Software Foundation, 51 Franklin Street, Fifth Floor, 28 Boston, MA 02110-1301, USA. 29*/ 30 31#import "config.h" 32#import <Foundation/NSAttributedString.h> 33#import <Foundation/NSDebug.h> 34#import <Foundation/NSDictionary.h> 35#import <Foundation/NSException.h> 36#import <Foundation/NSUserDefaults.h> 37 38#import "AppKit/NSCell.h" 39#import "AppKit/NSEvent.h" 40#import "AppKit/NSImage.h" 41#import "AppKit/NSKeyValueBinding.h" 42#import "AppKit/NSMenuItem.h" 43#import "AppKit/NSMenu.h" 44#import "GSBindingHelpers.h" 45 46static BOOL usesUserKeyEquivalents = NO; 47static Class imageClass; 48 49@interface GSMenuSeparator : NSMenuItem 50 51@end 52 53@implementation GSMenuSeparator 54 55- (Class) classForCoder 56{ 57 return [NSMenuItem class]; 58} 59 60- (id) init 61{ 62 self = [super initWithTitle: @"-----------" 63 action: NULL 64 keyEquivalent: @""]; 65 if (self == nil) 66 return nil; 67 68 _enabled = NO; 69 _changesState = NO; 70 return self; 71} 72 73- (BOOL) isSeparatorItem 74{ 75 return YES; 76} 77 78// FIXME: We need a lot of methods to switch off changes for a separator 79@end 80 81 82@implementation NSMenuItem 83 84+ (void) initialize 85{ 86 if (self == [NSMenuItem class]) 87 { 88 [self setVersion: 4]; 89 imageClass = [NSImage class]; 90 91 [self exposeBinding: NSEnabledBinding]; 92 } 93} 94 95+ (void) setUsesUserKeyEquivalents: (BOOL)flag 96{ 97 usesUserKeyEquivalents = flag; 98} 99 100+ (BOOL) usesUserKeyEquivalents 101{ 102 return usesUserKeyEquivalents; 103} 104 105+ (id <NSMenuItem>) separatorItem 106{ 107 return AUTORELEASE([GSMenuSeparator new]); 108} 109 110- (id) init 111{ 112 return [self initWithTitle: @"" 113 action: NULL 114 keyEquivalent: @""]; 115} 116 117- (void) dealloc 118{ 119 // Remove all key value bindings for this view. 120 [GSKeyValueBinding unbindAllForObject: self]; 121 122 TEST_RELEASE(_title); 123 TEST_RELEASE(_keyEquivalent); 124 TEST_RELEASE(_image); 125 TEST_RELEASE(_onStateImage); 126 TEST_RELEASE(_offStateImage); 127 TEST_RELEASE(_mixedStateImage); 128 TEST_RELEASE(_submenu); 129 TEST_RELEASE(_representedObject); 130 TEST_RELEASE(_toolTip); 131 [super dealloc]; 132} 133 134- (id) initWithTitle: (NSString*)aString 135 action: (SEL)aSelector 136 keyEquivalent: (NSString*)charCode 137{ 138 self = [super init]; 139 if (self == nil) 140 return nil; 141 142 //_menu = nil; 143 [self setKeyEquivalent: charCode]; 144 _keyEquivalentModifierMask = NSCommandKeyMask; 145 [self setTitle: aString]; // do this AFTER setKeyEquivalent: in case NSUserKeyEquivalents is defined 146 _mnemonicLocation = 255; // No mnemonic 147 _state = NSOffState; 148 _enabled = YES; 149 //_image = nil; 150 // Set the images according to the spec. On: check mark; off: dash. 151 [self setOnStateImage: [imageClass imageNamed: @"NSMenuCheckmark"]]; 152 [self setMixedStateImage: [imageClass imageNamed: @"NSMenuMixedState"]]; 153 //_offStateImage = nil; 154 //_target = nil; 155 _action = aSelector; 156 //_changesState = NO; 157 return self; 158} 159 160- (void) _updateKeyEquivalent 161{ 162 // Update keyEquivalent based on any entries in NSUserKeyEquivalents in the defaults database 163 // TODO: also check in other defaults domains, to allow NSUserKeyEquivalents dictionaries 164 // in different domains to provide overrides of different menu items. 165 NSString *userKeyEquivalent = [(NSDictionary*)[[NSUserDefaults standardUserDefaults] 166 objectForKey: @"NSUserKeyEquivalents"] 167 objectForKey: _title]; 168 if (userKeyEquivalent) 169 { 170 // check for leading symbols representing modifier flags: @, ~, $, ^ 171 NSUInteger modifierMask = 0; 172 while ([userKeyEquivalent length] > 1) 173 { 174 if ([userKeyEquivalent hasPrefix:@"@"]) 175 { 176 modifierMask |= NSCommandKeyMask; 177 userKeyEquivalent = [userKeyEquivalent substringFromIndex:1]; 178 } 179 else if ([userKeyEquivalent hasPrefix:@"~"]) 180 { 181 modifierMask |= NSAlternateKeyMask; 182 userKeyEquivalent = [userKeyEquivalent substringFromIndex:1]; 183 } 184 else if ([userKeyEquivalent hasPrefix:@"$"]) 185 { 186 modifierMask |= NSShiftKeyMask; 187 userKeyEquivalent = [userKeyEquivalent substringFromIndex:1]; 188 } 189 else if ([userKeyEquivalent hasPrefix:@"^"]) 190 { 191 modifierMask |= NSControlKeyMask; 192 userKeyEquivalent = [userKeyEquivalent substringFromIndex:1]; 193 } 194 else 195 { 196 break; 197 } 198 } 199 [self setKeyEquivalent:userKeyEquivalent]; 200 [self setKeyEquivalentModifierMask:modifierMask]; 201 } 202} 203 204- (void) setMenu: (NSMenu*)menu 205{ 206 /* The menu is retaining us. Do not retain it. */ 207 _menu = menu; 208 if (_submenu != nil) 209 { 210 [_submenu setSupermenu: menu]; 211 [self setTarget: _menu]; 212 } 213} 214 215- (NSMenu*) menu 216{ 217 return _menu; 218} 219 220- (BOOL) hasSubmenu 221{ 222 return (_submenu == nil) ? NO : YES; 223} 224 225- (void) setSubmenu: (NSMenu*)submenu 226{ 227 if (submenu == _submenu) 228 return; // no change 229 230 if ([submenu supermenu] != nil) 231 { 232 [NSException raise: NSInvalidArgumentException 233 format: @"submenu (%@) already has supermenu (%@)", 234 [submenu title], [[submenu supermenu] title]]; 235 } 236 ASSIGN(_submenu, submenu); 237 if (submenu != nil) 238 { 239 [submenu setSupermenu: _menu]; 240 [submenu setTitle: _title]; 241 } 242 [self setTarget: _menu]; 243 [self setAction: @selector(submenuAction:)]; 244 [_menu itemChanged: self]; 245} 246 247- (NSMenu*) submenu 248{ 249 return _submenu; 250} 251 252- (void) setTitle: (NSString*)aString 253{ 254 if (nil == aString) 255 aString = @""; 256 257 if ([_title isEqualToString:aString]) 258 return; // no change 259 260 ASSIGNCOPY(_title, aString); 261 [self _updateKeyEquivalent]; 262 [_menu itemChanged: self]; 263} 264 265- (NSString*) title 266{ 267 return _title; 268} 269 270- (BOOL) isSeparatorItem 271{ 272 return NO; 273} 274 275- (void) setKeyEquivalent: (NSString*)aKeyEquivalent 276{ 277 if (nil == aKeyEquivalent) 278 { 279 /* We warn about nil for compatibiliy with MacOS X, which refuses 280 nil. */ 281 NSDebugMLLog(@"MacOSXCompatibility", 282 @"Attempt to use nil as key equivalent"); 283 aKeyEquivalent = @""; 284 } 285 if ([_keyEquivalent isEqualToString:aKeyEquivalent]) 286 return; // no change 287 288 ASSIGNCOPY(_keyEquivalent, aKeyEquivalent); 289 [_menu itemChanged: self]; 290} 291 292- (NSString*) keyEquivalent 293{ 294 if (usesUserKeyEquivalents) 295 return [self userKeyEquivalent]; 296 else 297 return _keyEquivalent; 298} 299 300- (void) setKeyEquivalentModifierMask: (NSUInteger)mask 301{ 302 if (_keyEquivalentModifierMask == mask) 303 return; // no change 304 _keyEquivalentModifierMask = mask; 305 [_menu itemChanged: self]; 306} 307 308- (NSUInteger) keyEquivalentModifierMask 309{ 310 return _keyEquivalentModifierMask; 311} 312 313- (NSString*) userKeyEquivalent 314{ 315 NSString *userKeyEquivalent = [(NSDictionary*)[[[NSUserDefaults standardUserDefaults] 316 persistentDomainForName: NSGlobalDomain] 317 objectForKey: @"NSCommandKeys"] 318 objectForKey: _title]; 319 320 if (nil == userKeyEquivalent) 321 userKeyEquivalent = @""; 322 323 return userKeyEquivalent; 324} 325 326- (NSUInteger) userKeyEquivalentModifierMask 327{ 328 // FIXME 329 return NSCommandKeyMask; 330} 331 332- (void) setMnemonicLocation: (NSUInteger)location 333{ 334 if (_mnemonicLocation == location) 335 return; // no change 336 337 _mnemonicLocation = location; 338 [_menu itemChanged: self]; 339} 340 341- (NSUInteger) mnemonicLocation 342{ 343 if (_mnemonicLocation != 255) 344 return _mnemonicLocation; 345 else 346 return NSNotFound; 347} 348 349- (NSString*) mnemonic 350{ 351 if (_mnemonicLocation != 255) 352 return [_title substringWithRange: NSMakeRange(_mnemonicLocation, 1)]; 353 else 354 return @""; 355} 356 357- (void) setTitleWithMnemonic: (NSString*)stringWithAmpersand 358{ 359 NSUInteger location = [stringWithAmpersand rangeOfString: @"&"].location; 360 361 [self setTitle: [stringWithAmpersand stringByReplacingString: @"&" 362 withString: @""]]; 363 [self setMnemonicLocation: location]; 364} 365 366- (void) setImage: (NSImage *)image 367{ 368 NSAssert(image == nil || [image isKindOfClass: imageClass], 369 NSInvalidArgumentException); 370 371 if (_image == image) 372 return; // no change 373 374 ASSIGN(_image, image); 375 [_menu itemChanged: self]; 376} 377 378- (NSImage*) image 379{ 380 return _image; 381} 382 383- (void) setState: (NSInteger)state 384{ 385 if (_state == state) 386 return; 387 388 _state = state; 389 _changesState = YES; 390 [_menu itemChanged: self]; 391} 392 393- (NSInteger) state 394{ 395 return _state; 396} 397 398- (void) setOnStateImage: (NSImage*)image 399{ 400 NSAssert(image == nil || [image isKindOfClass: imageClass], 401 NSInvalidArgumentException); 402 403 if (_onStateImage == image) 404 return; // no change 405 406 ASSIGN(_onStateImage, image); 407 [_menu itemChanged: self]; 408} 409 410- (NSImage*) onStateImage 411{ 412 return _onStateImage; 413} 414 415- (void) setOffStateImage: (NSImage*)image 416{ 417 NSAssert(image == nil || [image isKindOfClass: imageClass], 418 NSInvalidArgumentException); 419 420 if (_offStateImage == image) 421 return; // no change 422 423 ASSIGN(_offStateImage, image); 424 [_menu itemChanged: self]; 425} 426 427- (NSImage*) offStateImage 428{ 429 return _offStateImage; 430} 431 432- (void) setMixedStateImage: (NSImage*)image 433{ 434 NSAssert(image == nil || [image isKindOfClass: imageClass], 435 NSInvalidArgumentException); 436 437 if (_mixedStateImage == image) 438 return; // no change 439 440 ASSIGN(_mixedStateImage, image); 441 [_menu itemChanged: self]; 442} 443 444- (NSImage*) mixedStateImage 445{ 446 return _mixedStateImage; 447} 448 449- (void) setEnabled: (BOOL)flag 450{ 451 if (flag == _enabled) 452 return; 453 454 _enabled = flag; 455 [_menu itemChanged: self]; 456} 457 458- (BOOL) isEnabled 459{ 460 return _enabled; 461} 462 463- (void) setTarget: (id)anObject 464{ 465 if (_target == anObject) 466 return; 467 468 _target = anObject; 469 [_menu itemChanged: self]; 470} 471 472- (id) target 473{ 474 return _target; 475} 476 477- (void) setAction: (SEL)aSelector 478{ 479 if (_action == aSelector) 480 return; 481 482 _action = aSelector; 483 [_menu itemChanged: self]; 484} 485 486- (SEL) action 487{ 488 return _action; 489} 490 491- (void) setTag: (NSInteger)anInt 492{ 493 _tag = anInt; 494} 495 496- (NSInteger) tag 497{ 498 return _tag; 499} 500 501- (void) setRepresentedObject: (id)anObject 502{ 503 ASSIGN(_representedObject, anObject); 504} 505 506- (id) representedObject 507{ 508 return _representedObject; 509} 510 511- (NSAttributedString *)attributedTitle 512{ 513 // FIXME 514 return nil; 515} 516 517-(void) setAttributedTitle: (NSAttributedString *)title 518{ 519 // FIXME 520 [self setTitle: [title string]]; 521} 522 523- (NSInteger)indentationLevel 524{ 525 return _indentation; 526} 527 528- (void)setIndentationLevel: (NSInteger)level 529{ 530 _indentation = level; 531} 532 533- (BOOL)isAlternate 534{ 535 return _isAlternate; 536} 537 538- (void) setAlternate: (BOOL)isAlternate 539{ 540 _isAlternate = isAlternate; 541} 542 543- (void) setToolTip: (NSString *)toolTip 544{ 545 ASSIGN(_toolTip, toolTip); 546} 547 548- (NSString *) toolTip 549{ 550 return _toolTip; 551} 552 553/* 554 * NSCopying protocol 555 */ 556- (id) copyWithZone: (NSZone*)zone 557{ 558 NSMenuItem *copy = (NSMenuItem*)NSCopyObject (self, 0, zone); 559 560 // We reset the menu to nil to allow the reuse of the copy 561 copy->_menu = nil; 562 copy->_title = [_title copyWithZone: zone]; 563 copy->_keyEquivalent = [_keyEquivalent copyWithZone: zone]; 564 copy->_image = [_image copyWithZone: zone]; 565 copy->_onStateImage = [_onStateImage copyWithZone: zone]; 566 copy->_offStateImage = [_offStateImage copyWithZone: zone]; 567 copy->_mixedStateImage = [_mixedStateImage copyWithZone: zone]; 568 copy->_representedObject = RETAIN(_representedObject); 569 copy->_submenu = [_submenu copy]; 570 copy->_toolTip = RETAIN(_toolTip); 571 copy->_target = _target; 572 573 return copy; 574} 575 576/* 577 * NSCoding protocol 578 */ 579- (void) encodeWithCoder: (NSCoder*)aCoder 580{ 581 if ([aCoder allowsKeyedCoding]) 582 { 583 if ([self isSeparatorItem]) 584 { 585 [aCoder encodeBool: YES forKey: @"NSIsSeparator"]; 586 } 587 [aCoder encodeObject: _title forKey: @"NSTitle"]; 588 [aCoder encodeObject: NSStringFromSelector(_action) forKey: @"NSAction"]; 589 [aCoder encodeObject: _keyEquivalent forKey: @"NSKeyEquiv"]; 590 [aCoder encodeObject: _onStateImage forKey: @"NSOnImage"]; 591 [aCoder encodeObject: _offStateImage forKey: @"NSOffImage"]; // ??????? 592 [aCoder encodeObject: _mixedStateImage forKey: @"NSMixedImage"]; 593 [aCoder encodeObject: _target forKey: @"NSTarget"]; 594 [aCoder encodeObject: _menu forKey: @"NSMenu"]; 595 596 // If the menu is owned by a popup, then don't encode the children. 597 // This prevents an assertion error in IB as these keys should not 598 // be present in a menu item when it's encoded as part of a popup. 599 if([_menu _ownedByPopUp] == NO) 600 { 601 [aCoder encodeObject: _submenu forKey: @"NSSubmenu"]; 602 } 603 604 [aCoder encodeInt: _keyEquivalentModifierMask forKey: @"NSKeyEquivModMask"]; 605 [aCoder encodeInt: _mnemonicLocation forKey: @"NSMnemonicLoc"]; 606 [aCoder encodeInt: _state forKey: @"NSState"]; 607 [aCoder encodeBool: ![self isEnabled] forKey: @"NSIsDisabled"]; 608 if (_tag) 609 { 610 [aCoder encodeInt: _tag forKey: @"NSTag"]; 611 } 612 } 613 else 614 { 615 [aCoder encodeObject: _title]; 616 [aCoder encodeObject: _keyEquivalent]; 617 [aCoder encodeValueOfObjCType: @encode(NSUInteger) at: &_keyEquivalentModifierMask]; 618 [aCoder encodeValueOfObjCType: @encode(NSUInteger) at: &_mnemonicLocation]; 619 [aCoder encodeValueOfObjCType: @encode(NSInteger) at: &_state]; 620 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_enabled]; 621 [aCoder encodeObject: _image]; 622 [aCoder encodeObject: _onStateImage]; 623 [aCoder encodeObject: _offStateImage]; 624 [aCoder encodeObject: _mixedStateImage]; 625 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_changesState]; 626 [aCoder encodeValueOfObjCType: @encode(SEL) at: &_action]; 627 [aCoder encodeValueOfObjCType: @encode(NSInteger) at: &_tag]; 628 [aCoder encodeConditionalObject: _representedObject]; 629 [aCoder encodeObject: _submenu]; 630 [aCoder encodeConditionalObject: _target]; 631 632 // version 3 633 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_isAlternate]; 634 [aCoder encodeValueOfObjCType: @encode(char) at: &_indentation]; 635 [aCoder encodeObject: _toolTip]; 636 } 637} 638 639- (id) initWithCoder: (NSCoder*)aDecoder 640{ 641 if ([aDecoder allowsKeyedCoding]) 642 { 643 NSString *title; 644 NSString *action; 645 NSString *key; 646 BOOL isSeparator = NO; 647 int keyMask; 648 649 if ([aDecoder containsValueForKey: @"NSIsSeparator"]) 650 { 651 isSeparator = [aDecoder decodeBoolForKey: @"NSIsSeparator"]; 652 } 653 654 if (isSeparator && ![self isSeparatorItem]) 655 { 656 RELEASE(self); 657 658 // 659 // An object returned from initWithCoder: 660 // should not be autoreleased. Do a retain 661 // to prevent it from being released automatically. 662 // 663 self = RETAIN([NSMenuItem separatorItem]); 664 } 665 666 // 667 // Not retained, because we're calling the designated init with 668 // the values. 669 // 670 title = [aDecoder decodeObjectForKey: @"NSTitle"]; 671 action = [aDecoder decodeObjectForKey: @"NSAction"]; 672 key = [aDecoder decodeObjectForKey: @"NSKeyEquiv"]; 673 674 self = [self initWithTitle: title 675 action: NSSelectorFromString(action) 676 keyEquivalent: key]; 677 //[aDecoder decodeObjectForKey: @"NSMenu"]; 678 679 if ([aDecoder containsValueForKey: @"NSTarget"]) 680 { 681 id target = [aDecoder decodeObjectForKey: @"NSTarget"]; 682 [self setTarget: target]; 683 } 684 if ([aDecoder containsValueForKey: @"NSMixedImage"]) 685 { 686 NSImage *mixedImage = [aDecoder decodeObjectForKey: @"NSMixedImage"]; 687 [self setMixedStateImage: mixedImage]; 688 } 689 if ([aDecoder containsValueForKey: @"NSOnImage"]) 690 { 691 NSImage *onImage = [aDecoder decodeObjectForKey: @"NSOnImage"]; 692 [self setOnStateImage: onImage]; 693 } 694 if ([aDecoder containsValueForKey: @"NSSubmenu"]) 695 { 696 NSMenu *submenu = [aDecoder decodeObjectForKey: @"NSSubmenu"]; 697 [self setSubmenu: submenu]; 698 } 699 700 // Set the key mask regardless of whether it is present; 701 // i.e. set it to 0 if it is not present in the nib. 702 keyMask = [aDecoder decodeIntForKey: @"NSKeyEquivModMask"]; 703 [self setKeyEquivalentModifierMask: keyMask]; 704 705 if ([aDecoder containsValueForKey: @"NSMnemonicLoc"]) 706 { 707 int loc = [aDecoder decodeIntForKey: @"NSMnemonicLoc"]; 708 [self setMnemonicLocation: loc]; 709 } 710 if ([aDecoder containsValueForKey: @"NSState"]) 711 { 712 _state = [aDecoder decodeIntForKey: @"NSState"]; 713 } 714 if ([aDecoder containsValueForKey: @"NSIsDisabled"]) 715 { 716 BOOL flag = [aDecoder decodeBoolForKey: @"NSIsDisabled"]; 717 [self setEnabled: !flag]; 718 } 719 if ([aDecoder containsValueForKey: @"NSTag"]) 720 { 721 int tag = [aDecoder decodeIntForKey: @"NSTag"]; 722 [self setTag: tag]; 723 } 724 } 725 else 726 { 727 int version = [aDecoder versionForClassName: 728 @"NSMenuItem"]; 729 730 [aDecoder decodeValueOfObjCType: @encode(id) at: &_title]; 731 [aDecoder decodeValueOfObjCType: @encode(id) at: &_keyEquivalent]; 732 [aDecoder decodeValueOfObjCType: @encode(NSUInteger) at: &_keyEquivalentModifierMask]; 733 if (version <= 3) 734 { 735 _keyEquivalentModifierMask = _keyEquivalentModifierMask << 16; 736 } 737 [aDecoder decodeValueOfObjCType: @encode(NSUInteger) at: &_mnemonicLocation]; 738 [aDecoder decodeValueOfObjCType: @encode(NSInteger) at: &_state]; 739 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_enabled]; 740 [aDecoder decodeValueOfObjCType: @encode(id) at: &_image]; 741 [aDecoder decodeValueOfObjCType: @encode(id) at: &_onStateImage]; 742 [aDecoder decodeValueOfObjCType: @encode(id) at: &_offStateImage]; 743 [aDecoder decodeValueOfObjCType: @encode(id) at: &_mixedStateImage]; 744 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_changesState]; 745 if (version == 1) 746 { 747 _target = [aDecoder decodeObject]; 748 } 749 [aDecoder decodeValueOfObjCType: @encode(SEL) at: &_action]; 750 [aDecoder decodeValueOfObjCType: @encode(NSInteger) at: &_tag]; 751 [aDecoder decodeValueOfObjCType: @encode(id) at: &_representedObject]; 752 [aDecoder decodeValueOfObjCType: @encode(id) at: &_submenu]; 753 if (version >= 2) 754 { 755 _target = [aDecoder decodeObject]; 756 } 757 if (version >= 3) 758 { 759 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_isAlternate]; 760 [aDecoder decodeValueOfObjCType: @encode(char) at: &_indentation]; 761 [aDecoder decodeValueOfObjCType: @encode(id) at: &_toolTip]; 762 } 763 } 764 765 [self _updateKeyEquivalent]; 766 return self; 767} 768 769- (void) bind: (NSString *)binding 770 toObject: (id)anObject 771 withKeyPath: (NSString *)keyPath 772 options: (NSDictionary *)options 773{ 774 if ([binding hasPrefix: NSEnabledBinding]) 775 { 776 GSKeyValueBinding *kvb; 777 778 [self unbind: binding]; 779 kvb = [[GSKeyValueAndBinding alloc] initWithBinding: NSEnabledBinding 780 withName: binding 781 toObject: anObject 782 withKeyPath: keyPath 783 options: options 784 fromObject: self]; 785 // The binding will be retained in the binding table 786 RELEASE(kvb); 787 } 788 else 789 { 790 [super bind: binding 791 toObject: anObject 792 withKeyPath: keyPath 793 options: options]; 794 } 795} 796 797@end 798 799@implementation NSMenuItem (GNUstepExtra) 800 801/* 802 * These methods support the special arranging in columns of menu 803 * items in GNUstep. There's no need to use them outside but if 804 * they are used the display is more pleasant. 805 */ 806- (void) setChangesState: (BOOL)flag 807{ 808 _changesState = flag; 809} 810 811- (BOOL) changesState 812{ 813 return _changesState; 814} 815 816@end 817