1/** <title>GSNibLoading</title>
2
3   <abstract>
4   These are templates for use with OSX Nib files.  These classes are the
5   templates and other things which are needed for reading/writing nib files.
6   </abstract>
7
8   Copyright (C) 1997, 1999 Free Software Foundation, Inc.
9
10   Author: Gregory John Casamento
11   Date: 2003, 2005
12   Author: Fred Kiefer
13   Date: 2003, 2010
14
15   This file is part of the GNUstep GUI Library.
16
17   This library is free software; you can redistribute it and/or
18   modify it under the terms of the GNU Lesser General Public
19   License as published by the Free Software Foundation; either
20   version 2 of the License, or (at your option) any later version.
21
22   This library is distributed in the hope that it will be useful,
23   but WITHOUT ANY WARRANTY; without even the implied warranty of
24   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
25   Lesser General Public License for more details.
26
27   You should have received a copy of the GNU Lesser General Public
28   License along with this library; see the file COPYING.LIB.
29   If not, see <http://www.gnu.org/licenses/> or write to the
30   Free Software Foundation, 51 Franklin Street, Fifth Floor,
31   Boston, MA 02110-1301, USA.
32*/
33
34#define EXPOSE_NSKeyedUnarchiver_IVARS
35
36#import <Foundation/NSArchiver.h>
37#import <Foundation/NSArray.h>
38#import <Foundation/NSBundle.h>
39#import <Foundation/NSByteOrder.h>
40#import <Foundation/NSCoder.h>
41#import <Foundation/NSData.h>
42#import <Foundation/NSDecimalNumber.h>
43#import <Foundation/NSDictionary.h>
44#import <Foundation/NSDebug.h>
45#import <Foundation/NSEnumerator.h>
46#import <Foundation/NSException.h>
47#import <Foundation/NSKeyedArchiver.h>
48#import <Foundation/NSKeyValueCoding.h>
49#import <Foundation/NSObjCRuntime.h>
50#import <Foundation/NSSet.h>
51#import <Foundation/NSString.h>
52
53#import "GNUstepGUI/GSNibLoading.h"
54#import "AppKit/NSApplication.h"
55#import "AppKit/NSFontManager.h"
56#import "AppKit/NSImage.h"
57#import "AppKit/NSMenuItem.h"
58#import "AppKit/NSMenuView.h"
59#import "AppKit/NSNib.h"
60#import "AppKit/NSScreen.h"
61#import "AppKit/NSSound.h"
62#import "AppKit/NSToolbar.h"
63#import "GNUstepGUI/GSInstantiator.h"
64#import "GSGuiPrivate.h"
65
66static BOOL _isInInterfaceBuilder = NO;
67
68@interface NSKeyedUnarchiver (NSClassSwapperPrivate)
69- (Class) replacementClassForClassName: (NSString *)className;
70@end
71
72@interface NSApplication (NibCompatibility)
73- (void) _setMainMenu: (NSMenu*)aMenu;
74@end
75
76@interface NSView (NibCompatibility)
77- (void) _fixSubviews;
78@end
79
80/* Correct some instances where the ":" is missing from the method name in the label */
81@interface NSNibControlConnector (NibCompatibility)
82- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator;
83@end
84
85@interface NSNibConnector (NibCompatibility)
86- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator;
87@end
88
89@interface NSDecimalNumberPlaceholder : NSObject
90@end
91
92@interface _NSCornerView : NSView
93@end
94
95@interface NSMenu (NibCompatibility)
96- (void) _setMain: (BOOL)isMain;
97@end
98@interface NSMenu (GNUstepPrivate)
99- (void) _setGeometry;
100- (BOOL) _isMainMenu;
101@end
102
103@implementation NSMenu (NibCompatibility)
104// FIXME: Why can't this be merged with setMain: ?
105- (void) _setMain: (BOOL)isMain
106{
107  if (isMain)
108    {
109      NSMenuView	*oldRep;
110      NSInterfaceStyle	oldStyle;
111      NSInterfaceStyle	newStyle;
112      NSString          *processName;
113
114      if ([self numberOfItems] == 0)
115        return;
116
117      oldRep = [self menuRepresentation];
118      oldStyle = [oldRep interfaceStyle];
119      newStyle = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
120      processName = [[NSProcessInfo processInfo] processName];
121
122      /*
123       * If necessary, rebuild menu for (different) style
124       */
125      if (oldStyle != newStyle)
126        {
127	  NSMenuView	*newRep;
128
129	  newRep = [[NSMenuView alloc] initWithFrame: NSZeroRect];
130	  if (newStyle == NSMacintoshInterfaceStyle
131	    || newStyle == NSWindows95InterfaceStyle)
132	    {
133	      [newRep setHorizontal: YES];
134	    }
135	  else
136	    {
137	      [newRep setHorizontal: NO];
138	    }
139	  [newRep setInterfaceStyle: newStyle];
140	  [self setMenuRepresentation: newRep];
141	  RELEASE(newRep);
142	}
143
144      [[self window] setTitle: processName];
145      [[self window] setLevel: NSMainMenuWindowLevel];
146
147      // if it's a standard menu, transform it to be more NeXT'ish/GNUstep-like
148      if (_menu.horizontal == NO)
149        {
150          NSMenuItem *appItem;
151	  NSMenu *sub;
152	  SEL	sel = @selector(terminate:);
153
154	  /* The title of the main menu should be the process name.
155	   */
156          [self setTitle: processName];
157
158	  /* If there is no 'quite' item (one which sends a -terminate:
159	   * actions) we add one.
160	   */
161	  if ([self indexOfItemWithTarget: nil andAction: sel] < 0
162	    && [self indexOfItemWithTarget: NSApp andAction: sel] < 0)
163	    {
164	      NSString *quitString;
165	      NSMenuItem *quitItem;
166
167	      quitString = [NSString stringWithFormat: @"%@ %@",
168		NSLocalizedString (@"Quit", @"Quit"), processName];
169	      quitItem = [[NSMenuItem alloc] initWithTitle: quitString
170		action: @selector(terminate:)
171		keyEquivalent: @"q"];
172              [self addItem: quitItem];
173	    }
174
175	  /* An OSX main menu has the first item pointing to a submenu
176	   * whose contents are much the same as a GNUstep info menu.
177	   */
178          appItem = (NSMenuItem*)[self itemAtIndex: 0]; // Info item.
179	  sub = [appItem submenu];
180	  if (sub != nil)
181	    {
182              NSString	*infoString;
183	      NSInteger	index;
184
185	      infoString = NSLocalizedString (@"Info", @"Info");
186	      [appItem setTitle: infoString];
187	      [sub setTitle: infoString];
188	      /* The submenu may contain a 'quit' item ... if so we need to
189	       * remove it as we already added one to the main menu.
190	       */
191	      index = [sub indexOfItemWithTarget: nil andAction: sel];
192	      if (index < 0)
193		{
194	          index = [sub indexOfItemWithTarget: NSApp andAction: sel];
195		}
196	      if (index >= 0)
197		{
198		  [sub removeItemAtIndex: index];
199		}
200	    }
201        }
202
203      [self _setGeometry];
204      [self sizeToFit];
205
206      if ([NSApp isActive])
207        {
208	  [self display];
209	}
210    }
211  else
212    {
213      [self close];
214      [[self window] setLevel: NSSubmenuWindowLevel];
215    }
216}
217@end
218
219@implementation NSApplication (NibCompatibility)
220- (void) _setMainMenu: (NSMenu*)aMenu
221{
222  if (_main_menu == aMenu)
223    {
224      return;
225    }
226
227  if (_main_menu != nil)
228    {
229      [_main_menu setMain: NO];
230    }
231
232  ASSIGN(_main_menu, aMenu);
233
234  if (_main_menu != nil)
235    {
236      [_main_menu _setMain: YES];
237    }
238}
239@end
240
241@implementation NSView (NibCompatibility)
242- (void) _setWindow: (id) w
243{
244  _window = w;
245}
246
247- (void) _fixSubviews
248{
249  NSEnumerator *en = [[self subviews] objectEnumerator];
250  id v = nil;
251  while ((v = [en nextObject]) != nil)
252    {
253      if ([v window] != [self window] ||
254         [v superview] != self)
255        {
256          [v _setWindow: [self window]];
257          RETAIN(v);
258          [_sub_views removeObject: v];
259          [self addSubview: v];
260          RELEASE(v);
261        }
262      [v _fixSubviews];
263    }
264}
265@end
266
267/**
268 * NSWindowTemplate
269 *
270 * Instances of this class take the place of all windows in the nib file.
271 */
272@implementation NSWindowTemplate
273+ (void) initialize
274{
275  if (self == [NSWindowTemplate class])
276    {
277      [self setVersion: 0];
278    }
279}
280
281- (void) dealloc
282{
283  RELEASE(_title);
284  RELEASE(_viewClass);
285  RELEASE(_windowClass);
286  RELEASE(_view);
287  RELEASE(_autosaveName);
288  RELEASE(_realObject);
289  [super dealloc];
290}
291
292/**
293 * Designated initializer for NSWindowTemplate.
294 */
295- (id) initWithWindow: (NSWindow *)window
296            className: (NSString *)windowClass
297           isDeferred: (BOOL) deferred
298            isOneShot: (BOOL) oneShot
299            isVisible: (BOOL) visible
300       wantsToBeColor: (BOOL) wantsToBeColor
301     autoPositionMask: (int) autoPositionMask
302{
303  if ((self = [super init]) != nil)
304    {
305      if (window != nil)
306        {
307          // object members
308          ASSIGN(_title, [window title]);
309          ASSIGN(_viewClass, NSStringFromClass([[window contentView] class]));
310          ASSIGN(_windowClass, windowClass);
311          ASSIGN(_view, [window contentView]);
312          ASSIGN(_autosaveName, [window frameAutosaveName]);
313
314          // style & size
315          _windowStyle = [window styleMask];
316          _backingStoreType = [window backingType];
317          //_maxSize = [window maxSize];
318          //_minSize = [window minSize];
319          _maxSize = [window contentMaxSize];
320          _minSize = [window contentMinSize];
321          _windowRect = [window frame];
322          _screenRect = [[NSScreen mainScreen] frame];
323
324          // flags
325          _flags.isHiddenOnDeactivate = [window hidesOnDeactivate];
326          _flags.isNotReleasedOnClose = (![window isReleasedWhenClosed]);
327          _flags.isDeferred = deferred;
328          _flags.isOneShot = oneShot;
329          _flags.isVisible = visible;
330          _flags.isNotShadowed = ![window hasShadow];
331          _flags.wantsToBeColor = wantsToBeColor;
332          _flags.dynamicDepthLimit = [window hasDynamicDepthLimit];
333          _flags.autoPositionMask = autoPositionMask;
334          _flags.savePosition = YES; // not yet implemented.
335          _flags.autorecalculatesKeyViewLoop = [window autorecalculatesKeyViewLoop];
336        }
337    }
338  return self;
339}
340
341- (id) initWithCoder: (NSCoder *)coder
342{
343  if ([coder allowsKeyedCoding])
344    {
345      if ([coder containsValueForKey: @"NSViewClass"])
346        {
347          ASSIGN(_viewClass, [coder decodeObjectForKey: @"NSViewClass"]);
348        }
349      else
350        {
351          ASSIGN(_viewClass, @"NSView");
352        }
353      if ([coder containsValueForKey: @"NSWindowClass"])
354        {
355          ASSIGN(_windowClass, [coder decodeObjectForKey: @"NSWindowClass"]);
356        }
357      else
358        {
359          ASSIGN(_windowClass, @"NSWindow");
360        }
361      if ([coder containsValueForKey: @"NSWindowStyleMask"])
362        {
363          _windowStyle = [coder decodeIntForKey: @"NSWindowStyleMask"];
364        }
365      else
366        {
367          _windowStyle = 0;
368        }
369      if ([coder containsValueForKey: @"NSWindowBacking"])
370        {
371          _backingStoreType = [coder decodeIntForKey: @"NSWindowBacking"];
372        }
373      if ([coder containsValueForKey: @"NSWindowView"])
374        {
375          ASSIGN(_view, [coder decodeObjectForKey: @"NSWindowView"]);
376        }
377      if ([coder containsValueForKey: @"NSWTFlags"])
378        {
379          unsigned long flags = [coder decodeIntForKey: @"NSWTFlags"];
380          memcpy((void *)&_flags,(void *)&flags,sizeof(struct _GSWindowTemplateFlags));
381        }
382
383      if ([coder containsValueForKey: @"NSWindowContentMinSize"])
384        {
385          _minSize = [coder decodeSizeForKey: @"NSWindowContentMinSize"];
386        }
387      else if ([coder containsValueForKey: @"NSMinSize"])
388        {
389          NSRect rect = NSZeroRect;
390          rect.size = [coder decodeSizeForKey: @"NSMinSize"];
391          rect = [NSWindow contentRectForFrameRect: rect
392                                         styleMask: _windowStyle];
393          _minSize = rect.size;
394        }
395
396      if ([coder containsValueForKey: @"NSWindowContentMaxSize"])
397        {
398          _maxSize = [coder decodeSizeForKey: @"NSWindowContentMaxSize"];
399        }
400      else if ([coder containsValueForKey: @"NSMaxSize"])
401        {
402          NSRect rect = NSZeroRect;
403          rect.size = [coder decodeSizeForKey: @"NSMaxSize"];
404          rect = [NSWindow contentRectForFrameRect: rect
405                                         styleMask: _windowStyle];
406          _maxSize = rect.size;
407        }
408      else
409        {
410          _maxSize = NSMakeSize (10e4, 10e4);
411        }
412
413      if ([coder containsValueForKey: @"NSWindowRect"])
414        {
415          _windowRect = [coder decodeRectForKey: @"NSWindowRect"];
416        }
417      if ([coder containsValueForKey: @"NSFrameAutosaveName"])
418        {
419	  ASSIGN(_autosaveName, [coder decodeObjectForKey: @"NSFrameAutosaveName"]);
420        }
421      if ([coder containsValueForKey: @"NSWindowTitle"])
422        {
423          ASSIGN(_title, [coder decodeObjectForKey: @"NSWindowTitle"]);
424          _windowStyle |= NSTitledWindowMask;
425        }
426
427      if ([coder containsValueForKey: @"NSToolbar"])
428        {
429          _toolbar = [coder decodeObjectForKey: @"NSToolbar"];
430        }
431
432      _baseWindowClass = [NSWindow class];
433    }
434  else
435    {
436      [NSException raise: NSInvalidArgumentException
437                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
438                   NSStringFromClass([coder class])];
439    }
440  return self;
441}
442
443- (void) encodeWithCoder: (NSCoder *)aCoder
444{
445  if ([aCoder allowsKeyedCoding])
446    {
447      unsigned long flags = 0;
448      NSRect rect = [NSWindow contentRectForFrameRect: _windowRect
449                              styleMask: _windowStyle];
450      memcpy((void *)&flags,(void *)&_flags,sizeof(unsigned long));
451
452      [aCoder encodeObject: _viewClass forKey: @"NSViewClass"];
453      [aCoder encodeObject: _windowClass forKey: @"NSWindowClass"];
454      [aCoder encodeInt: _windowStyle forKey: @"NSWindowStyleMask"];
455      [aCoder encodeInt: _backingStoreType forKey: @"NSWindowBacking"];
456      [aCoder encodeObject: _view forKey: @"NSWindowView"];
457      [aCoder encodeInt: flags forKey: @"NSWTFlags"];
458      [aCoder encodeSize: _minSize forKey: @"NSWindowContentMinSize"];
459      [aCoder encodeSize: _maxSize forKey: @"NSWindowContentMaxSize"];
460      [aCoder encodeRect: rect forKey: @"NSWindowRect"];
461      [aCoder encodeObject: _title forKey: @"NSWindowTitle"];
462      [aCoder encodeObject: _autosaveName forKey: @"NSFrameAutosaveName"];
463      [aCoder encodeObject: _toolbar forKey: @"NSToolbar"];
464    }
465}
466
467/**
468 * This method is used to get the real object when connections are established.
469 */
470- (id) nibInstantiate
471{
472  if (_realObject == nil)
473    {
474      Class aClass;
475
476      if ([NSClassSwapper isInInterfaceBuilder])
477        {
478          aClass = [self baseWindowClass];
479        }
480      else
481        {
482          aClass = NSClassFromString(_windowClass);
483        }
484
485      if (aClass == nil)
486        {
487          [NSException raise: NSInternalInconsistencyException
488                       format: @"Unable to find class '%@'", _windowClass];
489        }
490
491      _realObject = [[aClass allocWithZone: NSDefaultMallocZone()]
492                      initWithContentRect: _windowRect
493                      styleMask: _windowStyle
494                      backing: _backingStoreType
495                      defer: _flags.isDeferred];
496
497      // set flags...
498      [_realObject setHidesOnDeactivate: _flags.isHiddenOnDeactivate];
499      [_realObject setReleasedWhenClosed: !(_flags.isNotReleasedOnClose)];
500      [_realObject setOneShot: _flags.isOneShot];
501      // [_realObject setVisible: _flags.isVisible]; // this is determined by whether it's in the visible windows array...
502      // [_realObject setWantsToBeColor: _flags.wantsToBeColor]; // not applicable on GNUstep.
503      [_realObject setAutodisplay: YES];
504      [_realObject setDynamicDepthLimit: _flags.dynamicDepthLimit];
505      // [_realObject setAutoPositionMask: _flags.autoPositionMask]; // currently not implemented for nibs
506      // [_realObject setAutoPosition: _flags.autoPosition];
507      [_realObject setDynamicDepthLimit: _flags.dynamicDepthLimit];
508      // [_realObject setFrameAutosaveName: _autosaveName]; // done after setting the min/max sizes
509      [_realObject setHasShadow: !_flags.isNotShadowed];
510      [_realObject setAutorecalculatesKeyViewLoop: _flags.autorecalculatesKeyViewLoop];
511
512      // reset attributes...
513      [_realObject setContentView: _view];
514      //[_realObject setMinSize: _minSize];
515      //[_realObject setMaxSize: _maxSize];
516      [_realObject setTitle: _title];
517
518      if ([_viewClass isKindOfClass: [NSToolbar class]])
519	{
520          // FIXME: No idea what is going on here
521	  [_realObject setToolbar: (NSToolbar*)_viewClass];
522	}
523      if (_toolbar)
524        {
525          [_realObject setToolbar: _toolbar];
526        }
527
528      [_realObject setContentMinSize: _minSize];
529      [_realObject setContentMaxSize: _maxSize];
530
531      [_view _fixSubviews];
532
533      // FIXME What is the point of calling -setFrame:display: here? It looks
534      // like an effective no op to me.
535      // resize the window...
536      [_realObject setFrame: [NSWindow frameRectForContentRect: [self windowRect]
537                                       styleMask: [self windowStyle]]
538                   display: NO];
539      [_realObject setFrameAutosaveName: _autosaveName];
540    }
541  return _realObject;
542}
543
544// setters and getters
545/**
546 * sets the type of backing store the window uses.
547 */
548- (void) setBackingStoreType: (NSBackingStoreType)type
549{
550  _backingStoreType = type;
551}
552
553/**
554 * Returns the type of backing store which is used.
555 */
556- (NSBackingStoreType) backingStoreType
557{
558  return _backingStoreType;
559}
560
561/**
562 * Sets whether or not the window is deferred.
563 */
564- (void) setDeferred: (BOOL)flag
565{
566  _flags.isDeferred = flag;
567}
568
569/**
570 * Returns YES, if the window is deferred, NO otherwise.
571 */
572- (BOOL) isDeferred
573{
574  return _flags.isDeferred;
575}
576
577/**
578 * Sets the maximum size of the window.
579 */
580- (void) setMaxSize: (NSSize)maxSize
581{
582  _maxSize = maxSize;
583}
584
585/**
586 * Returns the maximum size of the window.
587 */
588- (NSSize) maxSize
589{
590  return _maxSize;
591}
592
593/**
594 * Sets the minimum size of the window.
595 */
596- (void) setMinSize: (NSSize)minSize
597{
598  _minSize = minSize;
599}
600
601/**
602 * Returns the maximum size of the window.
603 */
604- (NSSize) minSize
605{
606  return _minSize;
607}
608
609/**
610 * Sets the window style.
611 */
612- (void) setWindowStyle: (unsigned)style
613{
614  _windowStyle = style;
615}
616
617/**
618 * Returns the window style.
619 */
620- (unsigned) windowStyle
621{
622  return _windowStyle;
623}
624
625/**
626 * Sets the window title.
627 */
628- (void) setTitle: (NSString *) title
629{
630  ASSIGN(_title, title);
631}
632
633/**
634 * Returns the window style.
635 */
636- (NSString *)title;
637{
638  return _title;
639}
640
641/**
642 * Sets the class used for the content view.
643 */
644- (void) setViewClass: (NSString *)viewClass
645{
646  ASSIGN(_viewClass,viewClass);
647}
648
649/**
650 * Returns the name of the class used for the content view.
651 */
652- (NSString *)viewClass
653{
654  return _viewClass;
655}
656
657/**
658 * Sets the window rect.
659 */
660- (void) setWindowRect: (NSRect)rect
661{
662  _windowRect = rect;
663}
664
665/**
666 * Returns the window rect.
667 */
668- (NSRect)windowRect
669{
670  return _windowRect;
671}
672
673/**
674 * Sets the screen rect.
675 */
676- (void) setScreenRect: (NSRect)rect
677{
678  _screenRect = rect;
679}
680
681/**
682 * Returns the screen rect.
683 */
684- (NSRect) screenRect
685{
686  return _screenRect;
687}
688
689/**
690 * Sets the instantiated object/real object.
691 */
692- (void) setRealObject: (id)o
693{
694  ASSIGN(_realObject,o);
695}
696
697/**
698 * Returns the real object represented by this template.
699 */
700- (id) realObject
701{
702  return _realObject;
703}
704
705/**
706 * Sets the view instance.
707 */
708- (void) setView: (id)view
709{
710  ASSIGN(_view,view);
711}
712
713/**
714 * Gets the view instance.
715 */
716- (id) view
717{
718  return _view;
719}
720
721/**
722 * sets the class name to be used when unarchiving the window.
723 */
724- (void) setClassName: (NSString *)name
725{
726  ASSIGN(_windowClass, name);
727}
728
729/**
730 * Returns the class instance.
731 */
732- (NSString *)className
733{
734  return _windowClass;
735}
736
737/**
738 * Returns the base window class.   This is usually NSWindow, but this method
739 * is overriden in the editor so that a different class may be used to take the
740 * place of the window.   In the case of Gorm, this is GormNSWindow.
741 */
742- (Class) baseWindowClass
743{
744  return _baseWindowClass;
745}
746@end
747
748/*
749 * NSViewTemplate
750 *
751 * Template for any classes which derive from NSView
752 */
753@implementation NSViewTemplate
754+ (void) initialize
755{
756  if (self == [NSViewTemplate class])
757    {
758      [self setVersion: 0];
759    }
760}
761
762- (void) dealloc
763{
764  RELEASE(_className);
765  RELEASE(_realObject);
766  [super dealloc];
767}
768
769/**
770 * Designated initializer for NSViewTemplate.
771 */
772- (id) initWithObject: (id)o
773	    className: (NSString *)name
774{
775  if ((self = [super init]) != nil)
776    {
777      [self setRealObject: o];
778      [self setClassName: name];
779    }
780  return self;
781}
782
783- (id) initWithCoder: (NSCoder *)coder
784{
785  self = [super initWithCoder: coder];
786  if (self != nil)
787    {
788      if ([coder allowsKeyedCoding])
789        {
790          _className = [coder decodeObjectForKey: @"NSClassName"];
791        }
792
793      if (_realObject == nil)
794	{
795	  Class aClass = NSClassFromString(_className);
796	  if (aClass == nil)
797	    {
798	      [NSException raise: NSInternalInconsistencyException
799			   format: @"Unable to find class '%@'", _className];
800	    }
801	  else
802	    {
803	      ASSIGN(_realObject, [[aClass allocWithZone: NSDefaultMallocZone()] initWithCoder: coder]);
804	      [[self superview] replaceSubview: self with: _realObject]; // replace the old view...
805	    }
806	}
807
808      AUTORELEASE(self);
809      return _realObject;
810    }
811  else
812    {
813      [NSException raise: NSInvalidArgumentException
814                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
815                   NSStringFromClass([coder class])];
816    }
817  return nil;
818}
819
820- (void) encodeWithCoder: (NSCoder *)coder
821{
822  if ([coder allowsKeyedCoding])
823    {
824      [coder encodeObject: (id)_className forKey: @"NSClassName"];
825      [_realObject encodeWithCoder: coder];
826    }
827  else
828    {
829      [NSException raise: NSInvalidArgumentException
830                   format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
831                   NSStringFromClass([coder class])];
832    }
833}
834
835// setters and getters
836/**
837 * Set the class name to be used by the NSView subclass.
838 */
839- (void) setClassName: (NSString *)name
840{
841  ASSIGN(_className, name);
842}
843
844/**
845 * Returns the classname.
846 */
847- (NSString *)className
848{
849  return _className;
850}
851
852/**
853 * Set the real object of the template.
854 */
855- (void) setRealObject: (id)o
856{
857  ASSIGN(_realObject, o);
858}
859
860/**
861 * Get the real object represented by the template.
862 */
863- (id) realObject
864{
865  return _realObject;
866}
867@end
868
869// Template for any classes which derive from NSText
870@implementation NSTextTemplate
871+ (void) initialize
872{
873  if (self == [NSTextTemplate class])
874    {
875      [self setVersion: 0];
876    }
877}
878@end
879
880/**
881 * NSTextViewTemplate
882 *
883 * Template for any classes which derive from NSTextView
884 */
885@implementation NSTextViewTemplate
886+ (void) initialize
887{
888  if (self == [NSTextViewTemplate class])
889    {
890      [self setVersion: 0];
891    }
892}
893@end
894
895// Template for any classes which derive from NSMenu.
896@implementation NSMenuTemplate
897+ (void) initialize
898{
899  if (self == [NSMenuTemplate class])
900    {
901      [self setVersion: 0];
902    }
903}
904
905- (void) dealloc
906{
907  RELEASE(_menuClass);
908  RELEASE(_realObject);
909  [super dealloc];
910}
911
912- (id) initWithCoder: (NSCoder *)aCoder
913{
914  RELEASE(self);
915  return nil;
916}
917
918- (void) encodeWithCoder: (NSCoder *)aCoder
919{
920}
921
922- (void) setClassName: (NSString *)className
923{
924  ASSIGN(_menuClass, className);
925}
926
927- (NSString *)className
928{
929  return _menuClass;
930}
931
932- (void) setRealObject: (id)o
933{
934  ASSIGN(_realObject,o);
935}
936
937- (id) realObject
938{
939  return _realObject;
940}
941@end
942
943@implementation NSCustomObject
944- (void) setClassName: (NSString *)name
945{
946  ASSIGNCOPY(_className, name);
947}
948
949- (NSString *)className
950{
951  return _className;
952}
953
954- (void) setExtension: (NSString *)name
955{
956  ASSIGNCOPY(_extension, name);
957}
958
959- (NSString *)extension
960{
961  return _extension;
962}
963
964- (void) setRealObject: (id)obj
965{
966  ASSIGN(_object, obj);
967}
968
969- (id) realObject
970{
971  return _object;
972}
973
974- (id) initWithCoder: (NSCoder *)coder
975{
976  if ([coder allowsKeyedCoding])
977    {
978      ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
979      ASSIGN(_extension, [coder decodeObjectForKey: @"NSExtension"]);
980      ASSIGN(_object, [coder decodeObjectForKey: @"NSObject"]);
981    }
982  else
983    {
984      [NSException raise: NSInvalidArgumentException
985                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
986                   NSStringFromClass([coder class])];
987    }
988  return self;
989}
990
991- (void) encodeWithCoder: (NSCoder *)coder
992{
993  if ([coder allowsKeyedCoding])
994    {
995      [coder encodeObject: (id)_className forKey: @"NSClassName"];
996      [coder encodeConditionalObject: (id)_extension forKey: @"NSExtension"];
997      [coder encodeConditionalObject: (id)_object forKey: @"NSObject"];
998    }
999  else
1000    {
1001      [NSException raise: NSInvalidArgumentException
1002                   format: @"Keyed coding not implemented for %@.",
1003                   NSStringFromClass([self class])];
1004    }
1005
1006}
1007
1008- (id) nibInstantiate
1009{
1010  if (_object == nil)
1011    {
1012      Class aClass;
1013
1014      if ([NSClassSwapper isInInterfaceBuilder])
1015        {
1016          aClass = [self class];
1017        }
1018      else
1019        {
1020          aClass = NSClassFromString(_className);
1021        }
1022
1023      if (aClass == nil)
1024        {
1025          [NSException raise: NSInternalInconsistencyException
1026                       format: @"Unable to find class '%@'", _className];
1027        }
1028
1029      if (GSObjCIsKindOf(aClass, [NSApplication class]) ||
1030	 [_className isEqual: @"NSApplication"])
1031        {
1032	  _object = RETAIN([aClass sharedApplication]);
1033        }
1034      else if ((GSObjCIsKindOf(aClass, [NSFontManager class])) ||
1035               ([_className isEqual: @"NSFontManager"]))
1036        {
1037          _object = RETAIN([aClass sharedFontManager]);
1038        }
1039      else
1040	{
1041	  _object = [[aClass allocWithZone: NSDefaultMallocZone()] init];
1042	}
1043    }
1044  return _object;
1045}
1046
1047- (void) awakeFromNib
1048{
1049  NSDebugLog(@"Called awakeFromNib on an NSCustomObject instance: %@", self);
1050  if ([_object respondsToSelector: @selector(awakeFromNib)])
1051    {
1052      [_object awakeFromNib];
1053    }
1054}
1055
1056- (NSString *) description
1057{
1058  return [NSString stringWithFormat: @"<%s: %lx> = <<className: %@, object: %@>>",
1059		   GSClassNameFromObject(self),
1060		   (unsigned long)self,
1061		   _className,_object];
1062}
1063
1064- (void) dealloc
1065{
1066  RELEASE(_className);
1067  RELEASE(_extension);
1068  RELEASE(_object);
1069  [super dealloc];
1070}
1071@end
1072
1073@implementation NSCustomView
1074- (void) setClassName: (NSString *)name
1075{
1076  ASSIGNCOPY(_className, name);
1077}
1078
1079- (NSString *)className
1080{
1081  return _className;
1082}
1083- (void) setExtension: (NSString *)ext;
1084{
1085  ASSIGNCOPY(_extension, ext);
1086}
1087
1088- (NSString *)extension
1089{
1090  return _extension;
1091}
1092
1093- (id) nibInstantiate
1094{
1095  if ([NSClassSwapper isInInterfaceBuilder])
1096    {
1097      _view = self;
1098      return self;
1099    }
1100
1101  if (_view == nil)
1102    {
1103      Class aClass;
1104
1105      // If the class name is nil, assume NSView.
1106      if (_className == nil)
1107        {
1108          aClass = [NSView class];
1109        }
1110      else
1111        {
1112          aClass = NSClassFromString(_className);
1113        }
1114
1115      if (aClass == nil)
1116        {
1117          [NSException raise: NSInternalInconsistencyException
1118                      format: @"Unable to find class '%@'", _className];
1119        }
1120      else
1121        {
1122          _view = [[aClass allocWithZone: NSDefaultMallocZone()] initWithFrame: [self frame]];
1123        }
1124    }
1125
1126  return _view;
1127}
1128
1129- (id) nibInstantiateWithCoder: (NSCoder *)coder
1130{
1131  if ([NSClassSwapper isInInterfaceBuilder])
1132    {
1133      return _view;
1134    }
1135  else if ([coder allowsKeyedCoding])
1136    {
1137      NSArray *subs = nil;
1138      id nextKeyView = nil;
1139      id prevKeyView = nil;
1140      NSEnumerator *en = nil;
1141      id v = nil;
1142
1143      // Tell the decoder that the object gets replaced before decoding subviews
1144      [(NSKeyedUnarchiver *)coder replaceObject: self withObject: _view];
1145
1146      prevKeyView = [coder decodeObjectForKey: @"NSPreviousKeyView"];
1147      nextKeyView = [coder decodeObjectForKey: @"NSNextKeyView"];
1148      if (nextKeyView != nil)
1149        {
1150          [_view setNextKeyView: nextKeyView];
1151        }
1152      if (prevKeyView != nil)
1153        {
1154          [_view setPreviousKeyView: prevKeyView];
1155        }
1156      if ([coder containsValueForKey: @"NSvFlags"])
1157	{
1158	  int vFlags = [coder decodeIntForKey: @"NSvFlags"];
1159	  [_view setAutoresizingMask: vFlags & 0x3F];
1160	  [_view setAutoresizesSubviews: ((vFlags & 0x100) == 0x100)];
1161	  [_view setHidden: ((vFlags & 0x80000000) == 0x80000000)];
1162	}
1163      /*
1164      if ([coder containsValueForKey: @"NSNextResponder"])
1165	{
1166	  [_view setNextResponder: [coder decodeObjectForKey: @"NSNextResponder"]];
1167	}
1168      */
1169
1170      // reset the bounds...
1171      // [_view setBounds: [_view frame]];
1172
1173      subs = [coder decodeObjectForKey: @"NSSubviews"];
1174      en = [subs objectEnumerator];
1175      while((v = [en nextObject]) != nil)
1176	{
1177	  [_view addSubview: v];
1178	}
1179    }
1180  else
1181    {
1182      [NSException raise: NSInternalInconsistencyException
1183		   format: @"Called NSCustomView awakeAfterUsingCoder with non-keyed archiver."];
1184    }
1185
1186  return _view;
1187}
1188
1189- (id) initWithCoder: (NSCoder *)coder
1190{
1191  // if in interface builder, then initialize as normal.
1192  if ([NSClassSwapper isInInterfaceBuilder])
1193    {
1194      self = [super initWithCoder: coder];
1195      if (self == nil)
1196        {
1197          return nil;
1198        }
1199    }
1200
1201  if ([coder allowsKeyedCoding])
1202    {
1203      // get the super stuff without calling super...
1204      if ([coder containsValueForKey: @"NSFrame"])
1205        {
1206          _frame = [coder decodeRectForKey: @"NSFrame"];
1207        }
1208      else
1209        {
1210          _frame = NSZeroRect;
1211          if ([coder containsValueForKey: @"NSFrameSize"])
1212            {
1213              _frame.size = [coder decodeSizeForKey: @"NSFrameSize"];
1214            }
1215        }
1216
1217      ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
1218      ASSIGN(_extension, [coder decodeObjectForKey: @"NSExtension"]);
1219
1220      if ([self nibInstantiate] != nil)
1221        {
1222          [self nibInstantiateWithCoder: coder];
1223        }
1224
1225      if (self != _view)
1226        {
1227          AUTORELEASE(self);
1228        }
1229    }
1230  else
1231    {
1232      [NSException raise: NSInvalidArgumentException
1233                  format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
1234                   NSStringFromClass([coder class])];
1235    }
1236
1237  return (id)_view;
1238}
1239
1240- (void) encodeWithCoder: (NSCoder *)coder
1241{
1242  [super encodeWithCoder: coder];
1243  if ([coder allowsKeyedCoding])
1244    {
1245      [coder encodeObject: _className forKey: @"NSClassName"];
1246      [coder encodeObject: _extension forKey: @"NSExtension"];
1247    }
1248  else
1249    {
1250      [NSException raise: NSInvalidArgumentException
1251                   format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
1252                   NSStringFromClass([coder class])];
1253    }
1254}
1255@end
1256
1257/**
1258 * This class represents an image or a sound which is referenced by the nib file.
1259 */
1260@implementation NSCustomResource
1261- (void) setClassName: (NSString *)className
1262{
1263  ASSIGNCOPY(_className, className);
1264}
1265
1266- (NSString *)className
1267{
1268  return _className;
1269}
1270
1271- (void) setResourceName: (NSString *)resourceName
1272{
1273  ASSIGNCOPY(_resourceName, resourceName);
1274}
1275
1276- (NSString *)resourceName
1277{
1278  return _resourceName;
1279}
1280
1281- (id) initWithCoder: (NSCoder *)coder
1282{
1283  id realObject = nil;
1284  if ([coder allowsKeyedCoding])
1285    {
1286      ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
1287      ASSIGN(_resourceName, [coder decodeObjectForKey: @"NSResourceName"]);
1288
1289      // FIXME: this is a hack, but for now it should do.
1290      if ([_className isEqual: @"NSSound"])
1291        {
1292          realObject = RETAIN([NSSound soundNamed: _resourceName]);
1293        }
1294      else if ([_className isEqual: @"NSImage"])
1295        {
1296          realObject = RETAIN([NSImage imageNamed: _resourceName]);
1297        }
1298
1299      if (realObject == nil)
1300        {
1301          NSLog(@"Could not load NSCustomResource %@ for class %@", _resourceName, _className);
1302          // Use a default instead of the missing object
1303          if ([_className isEqual: @"NSSound"])
1304            {
1305              realObject = RETAIN([NSSound soundNamed: @"Ping"]);
1306            }
1307          else if ([_className isEqual: @"NSImage"])
1308            {
1309              realObject  = RETAIN([NSImage imageNamed: @"GNUstep"]);
1310            }
1311        }
1312      // The object has been substituted, release the placeholder.
1313      RELEASE(self);
1314    }
1315  else
1316    {
1317      [NSException raise: NSInvalidArgumentException
1318                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
1319                   NSStringFromClass([coder class])];
1320    }
1321
1322  return realObject;
1323}
1324
1325- (void) encodeWithCoder: (NSCoder *)coder
1326{
1327  if ([coder allowsKeyedCoding])
1328    {
1329      [coder encodeObject: (id)_className forKey: @"NSClassName"];
1330      [coder encodeObject: (id)_resourceName forKey: @"NSResourceName"];
1331    }
1332}
1333@end
1334
1335/**
1336 * Category to add methods to NSKeyedUnarchiver which are needed during
1337 * nib reading.
1338 */
1339@implementation NSKeyedUnarchiver (NSClassSwapperPrivate)
1340/**
1341 * This method returns the class which replaces the class named
1342 * by className.   It uses the classes map to do this.
1343 */
1344- (Class) replacementClassForClassName: (NSString *)className
1345{
1346  Class aClass;
1347  if ((aClass = [self classForClassName: className]) == nil)
1348    {
1349      if ((aClass = [[self class] classForClassName: className]) == nil)
1350        {
1351          aClass = NSClassFromString(className);
1352          if (aClass == nil)
1353            {
1354              [NSException raise: NSInternalInconsistencyException
1355                          format: @"NSClassSwapper unable to find class '%@'", className];
1356            }
1357        }
1358    }
1359  return aClass;
1360}
1361@end
1362
1363/**
1364 * NSClassSwapper
1365 *
1366 * This class is used to stand-in for objects which need to be replaced by another object.
1367 * When this class is loaded in the live application, it unarchives and immediately replaces
1368 * itself with the instance of the object requested.   This is necessary since IB/Gorm does
1369 * have objects this is used for in palettes, so there is no "live" or actual instance saved
1370 * in the gorm file... only this object as a stand in.
1371 */
1372@implementation NSClassSwapper
1373- (id) initWithObject: (id)object
1374        withClassName: (NSString *)className
1375    originalClassName: (NSString *)origClassName
1376{
1377  if ((self = [super init]) != nil)
1378    {
1379      [self setTemplate: object];
1380      [self setClassName: className];
1381      [self setOriginalClassName: origClassName];
1382    }
1383  return self;
1384}
1385
1386/**
1387 * This class method keeps track of whether or not we are operating within IB/Gorm.
1388 * When unarchiving in IB/Gorm some behavior may need to be surpressed for some objects
1389 * or it
1390 */
1391+ (void) setIsInInterfaceBuilder: (BOOL)flag
1392{
1393  _isInInterfaceBuilder = flag;
1394}
1395
1396/**
1397 * returns YES, if we are currently in IB/Gorm.
1398 */
1399+ (BOOL) isInInterfaceBuilder
1400{
1401  return _isInInterfaceBuilder;
1402}
1403
1404/**
1405 * Sets the template represented by temp.
1406 */
1407- (void) setTemplate: (id)temp
1408{
1409  ASSIGN(_template, temp);
1410}
1411
1412/**
1413 * Returns the template.
1414 */
1415- (id) template
1416{
1417  return _template;
1418}
1419
1420/**
1421 * Sets the class name.
1422 */
1423- (void) setClassName: (NSString *)className
1424{
1425  ASSIGNCOPY(_className, className);
1426}
1427
1428/**
1429 * Returns the class name.
1430 */
1431- (NSString *)className
1432{
1433  return _className;
1434}
1435
1436/**
1437 * Sets the original class name.
1438 */
1439- (void) setOriginalClassName: (NSString *)className
1440{
1441  ASSIGNCOPY(_originalClassName, className);
1442}
1443
1444/**
1445 * Returns the original class name.
1446 */
1447- (NSString *)originalClassName
1448{
1449  return _originalClassName;
1450}
1451
1452/**
1453 * Instantiates the real object using className.
1454 */
1455- (void) instantiateRealObject: (NSCoder *)coder withClassName: (NSString *)className
1456{
1457  Class newClass = nil;
1458  id object = nil;
1459  NSKeyedUnarchiver *decoder = (NSKeyedUnarchiver *)coder;
1460
1461  if ([NSClassSwapper isInInterfaceBuilder] == YES)
1462    {
1463      newClass = [decoder replacementClassForClassName: _originalClassName];
1464    }
1465  else
1466    {
1467      newClass = [decoder replacementClassForClassName: className];
1468    }
1469
1470  // swap the class...
1471  object = [newClass allocWithZone: NSDefaultMallocZone()];
1472  [decoder setDelegate: self]; // set the delegate...
1473  [decoder replaceObject: self withObject: object];
1474  [self setTemplate: [object initWithCoder: decoder]];
1475  if (object != _template)
1476    {
1477      [decoder replaceObject: object withObject: _template];
1478    }
1479  [decoder setDelegate: nil]; // unset the delegate...
1480}
1481
1482/**
1483 * This delegate method makes the proper substitution for cellClass
1484 * when the object needs to have it's own cell.   An example of this
1485 * is NSSecureTextField/NSSecureTextFieldCell.
1486 */
1487- (id) unarchiver: (NSKeyedUnarchiver *)coder
1488  didDecodeObject: (id)obj
1489{
1490  Class newClass = nil;
1491  id result = obj;
1492
1493  // if we are in an interface builder, then return the original object.
1494  if ([NSClassSwapper isInInterfaceBuilder] == YES)
1495    {
1496      newClass = [coder replacementClassForClassName: _originalClassName];
1497    }
1498  else
1499    {
1500      newClass = [coder replacementClassForClassName: _className];
1501    }
1502
1503  // if this is a class which uses cells, override with the new cellClass, if the
1504  // subclass responds to cellClass.
1505  if ([obj isKindOfClass: [NSCell class]] &&
1506      [newClass respondsToSelector: @selector(cellClass)] &&
1507      [_className isEqualToString: _originalClassName] == NO)
1508    {
1509      Class newCellClass = [newClass cellClass];
1510      if (newCellClass != [NSCell class])
1511        {
1512          RELEASE(obj);
1513          result = [[newCellClass alloc] initWithCoder: coder];
1514        }
1515    }
1516
1517  return result;
1518}
1519
1520/**
1521 * Decode NSClassSwapper.
1522 */
1523- (id) initWithCoder: (NSCoder *)coder
1524{
1525  if ([coder allowsKeyedCoding])
1526    {
1527      ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
1528      ASSIGN(_originalClassName, [coder decodeObjectForKey: @"NSOriginalClassName"]);
1529
1530      // build the real object...
1531      if ([NSClassSwapper isInInterfaceBuilder] == YES)
1532        {
1533          [self instantiateRealObject: coder withClassName: _originalClassName];
1534        }
1535      else
1536        {
1537          [self instantiateRealObject: coder withClassName: _className];
1538        }
1539
1540      {
1541        id object;
1542
1543        object = RETAIN(_template);
1544        RELEASE(self);
1545        return AUTORELEASE(object);
1546      }
1547    }
1548  else
1549    {
1550      [NSException raise: NSInvalidArgumentException
1551                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
1552                   NSStringFromClass([coder class])];
1553    }
1554
1555  return self;
1556}
1557
1558/**
1559 * Encode NSClassSwapper.
1560 */
1561- (void) encodeWithCoder: (NSCoder *)coder
1562{
1563  if ([coder allowsKeyedCoding])
1564    {
1565      [coder encodeObject: _originalClassName forKey: @"NSOriginalClassName"];
1566      [coder encodeObject: _className forKey: @"NSClassName"];
1567      [_template encodeWithCoder: coder]; // encode the actual object;
1568    }
1569  else
1570    {
1571      [NSException raise: NSInvalidArgumentException
1572                   format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
1573                   NSStringFromClass([coder class])];
1574    }
1575}
1576
1577/**
1578 * Deallocate NSClassSwapper instance.
1579 */
1580- (void) dealloc
1581{
1582  RELEASE(_className);
1583  RELEASE(_originalClassName);
1584  RELEASE(_template);
1585  [super dealloc];
1586}
1587@end
1588
1589@implementation NSNibConnector (NibCompatibility)
1590/**
1591 * This method causes the connection to instantiate the objects in it's source
1592 * and destination.   The instantiator is the object which holds any custom
1593 * class information which might be needed to do the proprer substitution of
1594 * objects based on the contents of the maps.
1595 */
1596- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator
1597{
1598  [self setSource: [instantiator instantiateObject: _src]];
1599  [self setDestination: [instantiator instantiateObject: _dst]];
1600}
1601
1602- (id) nibInstantiate
1603{
1604  if ([_src respondsToSelector: @selector(nibInstantiate)])
1605    {
1606      [self setSource: [_src nibInstantiate]];
1607    }
1608  if ([_dst respondsToSelector: @selector(nibInstantiate)])
1609    {
1610      [self setDestination: [_dst nibInstantiate]];
1611    }
1612  return self;
1613}
1614
1615@end
1616
1617@implementation NSNibControlConnector (NibCompatibility)
1618/**
1619 * This method overrides the default implementation of instantiate with
1620 * instantiator.   It also corrects a common issue in some nib files
1621 * by adding a colon to the end if none was given.   It then calls the
1622 * superclass with the corrected label.
1623 */
1624- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator
1625{
1626  NSRange colonRange = [_tag rangeOfString: @":"];
1627  NSUInteger location = colonRange.location;
1628
1629  if (location == NSNotFound)
1630    {
1631      NSString *newTag = [NSString stringWithFormat: @"%@:",_tag];
1632      [self setLabel: (id)newTag];
1633    }
1634
1635  [super instantiateWithInstantiator: instantiator];
1636}
1637@end
1638
1639/**
1640 * NSIBObjectData
1641 *
1642 * This class is the container for all of the nib data.  It contains several maps.
1643 * The maps are the following:
1644 *
1645 *     name -> object (name table)
1646 *     object -> name (name table reverse lookup)
1647 *     classes -> object (for custom class storage)
1648 *     oids -> object (for relating the oid to each object)
1649 *     accessibilityOids -> object
1650 *
1651 * The maps are stored in the nib itself as a set of synchronized
1652 * arrays one array containing the keys and the other the values.  This is why, in the
1653 * initWithCoder: and encodeWithCoder: methods they are saved as arrays and then
1654 * loaded into NSMapTables.
1655 */
1656@implementation NSIBObjectData
1657/**
1658 * Get the values from the map in the same order as the keys.
1659 */
1660- (NSArray *) _valuesForKeys: (NSArray *)keys inMap: (NSMapTable *)map
1661{
1662  NSMutableArray *result = [NSMutableArray array];
1663  NSEnumerator *en = [keys objectEnumerator];
1664  id key = nil;
1665  while ((key = [en nextObject]) != nil)
1666    {
1667      id value = (id)NSMapGet(map,key);
1668      [result addObject: value];
1669    }
1670  return result;
1671}
1672
1673/**
1674 * Build a map with two arrays of keys and values.
1675 */
1676- (void) _buildMap: (NSMapTable *)mapTable
1677          withKeys: (NSArray *)keys
1678         andValues: (NSArray *)values
1679{
1680  NSEnumerator *ken = [keys objectEnumerator];
1681  NSEnumerator *ven = [values objectEnumerator];
1682  id key = nil;
1683  id value = nil;
1684
1685  while ((key = [ken nextObject]) != nil && (value = [ven nextObject]) != nil)
1686    {
1687      NSMapInsert(mapTable, key, value);
1688      if (value == nil)
1689	{
1690	  NSLog(@"==> WARNING: Value for key %@ is %@",key , value);
1691	}
1692    }
1693}
1694
1695/**
1696 * Encode the NSIBObjectData container
1697 */
1698- (void) encodeWithCoder: (NSCoder *)coder
1699{
1700  if ([coder allowsKeyedCoding])
1701    {
1702      NSArray *accessibilityOidsKeys = (NSArray *)NSAllMapTableKeys(_accessibilityOids);
1703      NSArray *accessibilityOidsValues = [self _valuesForKeys: accessibilityOidsKeys inMap: _accessibilityOids];
1704      NSArray *classKeys = (NSArray *)NSAllMapTableKeys(_classes);
1705      NSArray *classValues = [self _valuesForKeys: classKeys inMap: _classes];
1706      NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
1707      NSArray *nameValues = [self _valuesForKeys: nameKeys inMap: _names];
1708      NSArray *objectsKeys = (NSArray *)NSAllMapTableKeys(_objects);
1709      NSArray *objectsValues = [self _valuesForKeys: objectsKeys inMap: _objects];
1710      NSArray *oidsKeys = (NSArray *)NSAllMapTableKeys(_oids);
1711      NSArray *oidsValues = [self _valuesForKeys: oidsKeys inMap: _oids];
1712
1713      [(NSKeyedArchiver *)coder setClassName: @"_NSCornerView" forClass: NSClassFromString(@"GSTableCornerView")];
1714
1715      [coder encodeObject: (id)_accessibilityConnectors forKey: @"NSAccessibilityConnectors"];
1716      [coder encodeObject: (id) accessibilityOidsKeys forKey: @"NSAccessibilityOidsKeys"];
1717      [coder encodeObject: (id) accessibilityOidsValues forKey: @"NSAccessibilityOidsValues"];
1718      [coder encodeObject: (id) classKeys forKey: @"NSClassesKeys"];
1719      [coder encodeObject: (id) classValues forKey: @"NSClassesValues"];
1720      [coder encodeObject: (id) nameKeys forKey: @"NSNamesKeys"];
1721      [coder encodeObject: (id) nameValues forKey: @"NSNamesValues"];
1722      [coder encodeObject: (id) objectsKeys forKey: @"NSObjectsKeys"];
1723      [coder encodeObject: (id) objectsValues forKey: @"NSObjectsValues"];
1724      [coder encodeObject: (id) oidsKeys forKey: @"NSOidsKeys"];
1725      [coder encodeObject: (id) oidsValues forKey: @"NSOidsValues"];
1726      [coder encodeObject: (id) _connections forKey: @"NSConnections"];
1727      [coder encodeObject: (id) _fontManager forKey: @"NSFontManager"];
1728      [coder encodeObject: (id) _framework forKey: @"NSFramework"];
1729      [coder encodeObject: (id) _visibleWindows forKey: @"NSVisibleWindows"];
1730      [coder encodeInt: _nextOid forKey: @"NSNextOid"];
1731      [coder encodeConditionalObject: (id) _root forKey: @"NSRoot"];
1732    }
1733  else
1734    {
1735      [NSException raise: NSInvalidArgumentException
1736                   format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
1737                   NSStringFromClass([coder class])];
1738    }
1739}
1740
1741/**
1742 * Decode the NSIBObjectData container.
1743 */
1744- (id) initWithCoder: (NSCoder *)coder
1745{
1746  if ([coder allowsKeyedCoding])
1747    {
1748      NSArray *nameKeys = nil;
1749      NSArray *nameValues = nil;
1750      NSArray *classKeys = nil;
1751      NSArray *classValues = nil;
1752      NSArray *objectsKeys = nil;
1753      NSArray *objectsValues = nil;
1754      NSArray *oidsKeys = nil;
1755      NSArray *oidsValues = nil;
1756      NSArray *accessibilityOidsKeys = nil;
1757      NSArray *accessibilityOidsValues = nil;
1758
1759      [(NSKeyedUnarchiver *)coder setClass: NSClassFromString(@"GSTableCornerView")
1760			      forClassName: @"_NSCornerView"];
1761
1762      //
1763      // Get root, font, framwork and oid.
1764      // Retain objects since NSKeyedUnarchiver autoreleases unarchived objects.
1765      //
1766      ASSIGN(_root, [coder decodeObjectForKey: @"NSRoot"]);
1767      ASSIGN(_fontManager, [coder decodeObjectForKey: @"NSFontManager"]);
1768      ASSIGN(_framework, [coder decodeObjectForKey: @"NSFramework"]);
1769      _nextOid = [coder decodeIntForKey: @"NSNextOid"];
1770
1771      // get connections.
1772      ASSIGN(_connections, (NSMutableArray *)
1773	[coder decodeObjectForKey: @"NSConnections"]);
1774      ASSIGN(_accessibilityConnectors, (NSMutableArray *)
1775	[coder decodeObjectForKey: @"NSAccessibilityConnectors"]);
1776
1777      // get visible windows
1778      ASSIGN(_visibleWindows, (NSMutableArray *)
1779	[coder decodeObjectForKey: @"NSVisibleWindows"]);
1780
1781      // instantiate the maps..
1782      _classes = NSCreateMapTable(NSObjectMapKeyCallBacks,
1783				  NSObjectMapValueCallBacks, 2);
1784      _names = NSCreateMapTable(NSObjectMapKeyCallBacks,
1785				NSObjectMapValueCallBacks, 2);
1786      _objects = NSCreateMapTable(NSObjectMapKeyCallBacks,
1787				  NSObjectMapValueCallBacks, 2);
1788      _oids = NSCreateMapTable(NSObjectMapKeyCallBacks,
1789			       NSObjectMapValueCallBacks, 2);
1790
1791      //
1792      // Get the maps.  There is no need to retain these,
1793      // since they are going to be placed into the NSMapTable
1794      // structures anyway.
1795      //
1796      nameKeys = (NSArray *)
1797	[coder decodeObjectForKey: @"NSNamesKeys"];
1798      nameValues = (NSArray *)
1799	[coder decodeObjectForKey: @"NSNamesValues"];
1800      classKeys = (NSArray *)
1801	[coder decodeObjectForKey: @"NSClassesKeys"];
1802      classValues = (NSArray *)
1803	[coder decodeObjectForKey: @"NSClassesValues"];
1804      objectsKeys = (NSArray *)
1805	[coder decodeObjectForKey: @"NSObjectsKeys"];
1806      objectsValues = (NSArray *)
1807	[coder decodeObjectForKey: @"NSObjectsValues"];
1808      oidsKeys = (NSArray *)
1809	[coder decodeObjectForKey: @"NSOidsKeys"];
1810      oidsValues = (NSArray *)
1811	[coder decodeObjectForKey: @"NSOidsValues"];
1812
1813      // Fill in the maps...
1814      [self _buildMap: _classes
1815	    withKeys: classKeys
1816	    andValues: classValues];
1817      [self _buildMap: _names
1818	    withKeys: nameKeys
1819	    andValues: nameValues];
1820      [self _buildMap: _objects
1821	    withKeys: objectsKeys
1822	    andValues: objectsValues];
1823      [self _buildMap: _oids
1824	    withKeys: oidsKeys
1825	    andValues: oidsValues];
1826
1827      //
1828      // Only get these maps when in the editor.  They
1829      // aren't useful outside of it and only waste memory if
1830      // unarchived in the live application.
1831      //
1832      if ([NSClassSwapper isInInterfaceBuilder])
1833	{
1834	  // Only get these when in the editor...
1835	  accessibilityOidsKeys = (NSArray *)
1836	    [coder decodeObjectForKey: @"NSAccessibilityOidsKeys"];
1837	  accessibilityOidsValues = (NSArray *)
1838	    [coder decodeObjectForKey: @"NSAccessibilityOidsValues"];
1839
1840	  _accessibilityOids = NSCreateMapTable(NSObjectMapKeyCallBacks,
1841						NSObjectMapValueCallBacks, 2);
1842	  [self _buildMap: _accessibilityOids
1843		withKeys: accessibilityOidsKeys
1844		andValues: accessibilityOidsValues];
1845	}
1846
1847      // instantiate...
1848      _topLevelObjects = [[NSMutableSet alloc] init];
1849    }
1850  else
1851    {
1852      [NSException raise: NSInvalidArgumentException
1853                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
1854                   NSStringFromClass([coder class])];
1855    }
1856
1857  return self;
1858}
1859
1860/**
1861 * Initialize a new NSIBObjectData.
1862 */
1863- (id) init
1864{
1865  if ((self = [super init]) != nil)
1866    {
1867      // instantiate the maps..
1868      _objects = NSCreateMapTable(NSObjectMapKeyCallBacks,
1869                                  NSObjectMapValueCallBacks, 2);
1870      _names = NSCreateMapTable(NSObjectMapKeyCallBacks,
1871                                NSObjectMapValueCallBacks, 2);
1872      _oids = NSCreateMapTable(NSObjectMapKeyCallBacks,
1873                               NSObjectMapValueCallBacks, 2);
1874      _classes = NSCreateMapTable(NSObjectMapKeyCallBacks,
1875                                  NSObjectMapValueCallBacks, 2);
1876      _accessibilityOids = NSCreateMapTable(NSObjectMapKeyCallBacks,
1877                                            NSObjectMapValueCallBacks, 2);
1878
1879      // initialize the objects...
1880      _accessibilityConnectors = [[NSMutableArray alloc] init];
1881      _connections = [[NSMutableArray alloc] init];
1882      _visibleWindows = [[NSMutableArray alloc] init];
1883      _framework = nil;
1884      _fontManager = nil;
1885      _root = nil;
1886      _nextOid = 0;
1887    }
1888  return self;
1889}
1890
1891/**
1892 * Deallocate NSIBObjectData.
1893 */
1894- (void) dealloc
1895{
1896  // free the maps.
1897  NSFreeMapTable(_objects);
1898  NSFreeMapTable(_names);
1899  NSFreeMapTable(_classes);
1900  NSFreeMapTable(_oids);
1901  // these are not allocated when not in interface builder.
1902  if ([NSClassSwapper isInInterfaceBuilder])
1903    {
1904      NSFreeMapTable(_accessibilityOids);
1905    }
1906
1907  // free other objects.
1908  RELEASE(_accessibilityConnectors);
1909  RELEASE(_connections);
1910  RELEASE(_fontManager);
1911  RELEASE(_framework);
1912  RELEASE(_visibleWindows);
1913  RELEASE(_root);
1914  RELEASE(_topLevelObjects);
1915  [super dealloc];
1916}
1917
1918/**
1919 * Call nibInstantiate on an object, if it responds to the nibInstantiate selector.
1920 */
1921- (id)instantiateObject: (id)obj
1922{
1923  id newObject = obj;
1924  if ([obj respondsToSelector: @selector(nibInstantiate)])
1925    {
1926      newObject = [obj nibInstantiate];
1927    }
1928  return newObject;
1929}
1930
1931/**
1932 * Instantiate all of the objects in the nib file.
1933 */
1934- (void) nibInstantiateWithOwner: (id)owner topLevelObjects: (NSMutableArray *)topLevelObjects
1935{
1936  NSEnumerator *en;
1937  NSArray *objs;
1938  id obj = nil;
1939  id menu = nil;
1940
1941  // set the new root object.
1942  [_root setRealObject: owner];
1943
1944  // iterate over all objects, instantiate them and fill in top level array.
1945  /* Note: We instantiate all objects before establishing any connections
1946     between them, so that any shared instances defined in the nib are
1947     initialized before being used. This sequence is important when, e.g.,
1948     the nib defines a shared document controller that is an instance of a
1949     subclass of NSDocumentController. */
1950  objs = NSAllMapTableKeys(_objects);
1951  en = [objs objectEnumerator];
1952  while ((obj = [en nextObject]) != nil)
1953    {
1954      id v = NSMapGet(_objects, obj);
1955      NSInteger oid = [(id)NSMapGet(_oids, obj) intValue];
1956
1957      obj = [self instantiateObject: obj];
1958      // Object is top level if it isn't the owner but points to it.
1959      /* Don't record proxy objects in the top level array. The only
1960	 reliable way to identify proxy objects seems to look at their
1961	 object ID. Apparently, Apple is using fixed negative IDs for
1962	 proxy objects (-1 = File's Owner, -2 = First Responder,
1963	 -3 = NSApplication). */
1964      if (oid >= 0)
1965	{
1966	  if ((v == owner || v == _root) && (obj != owner) && (obj != _root))
1967	    {
1968	      [topLevelObjects addObject: obj];
1969	      // All top level objects must be released by the caller to avoid
1970	      // leaking, unless they are going to be released by other nib
1971	      // objects on behalf of the owner.
1972	      RETAIN(obj);
1973	    }
1974          if ([obj isKindOfClass: [NSMenu class]] &&
1975              [obj _isMainMenu])
1976            {
1977              [NSApp _setMainMenu: obj];
1978            }
1979        }
1980    }
1981
1982  // iterate over connections, instantiate and then establish them.
1983  en = [_connections objectEnumerator];
1984  while ((obj = [en nextObject]) != nil)
1985    {
1986      if ([obj respondsToSelector: @selector(instantiateWithInstantiator:)])
1987        {
1988          [obj instantiateWithInstantiator: self];
1989          [obj establishConnection];
1990        }
1991      else
1992        {
1993          if ([obj respondsToSelector: @selector(instantiateWithObjectInstantiator:)])
1994            {
1995              [obj instantiateWithObjectInstantiator: self];
1996              [obj establishConnection];
1997            }
1998        }
1999    }
2000
2001  // awaken all objects except proxy objects.
2002  objs = NSAllMapTableKeys(_objects);
2003  en = [objs objectEnumerator];
2004  while ((obj = [en nextObject]) != nil)
2005    {
2006      NSInteger oid = [(id)NSMapGet(_oids, obj) intValue];
2007      if (oid >= 0)
2008        {
2009          if ([obj respondsToSelector: @selector(realObject)])
2010            {
2011              obj = [obj realObject];
2012            }
2013          if ([obj respondsToSelector: @selector(awakeFromNib)])
2014            {
2015              [obj awakeFromNib];
2016            }
2017        }
2018    }
2019
2020  // awaken the owner
2021  if ([owner respondsToSelector: @selector(awakeFromNib)])
2022    {
2023      [owner awakeFromNib];
2024    }
2025
2026  // bring visible windows to front...
2027  en = [_visibleWindows objectEnumerator];
2028  while ((obj = [en nextObject]) != nil)
2029    {
2030      id w = [obj realObject];
2031      [w orderFront: self];
2032    }
2033
2034  // add the menu...
2035  menu = [self objectForName: @"MainMenu"];
2036  if (menu != nil)
2037    {
2038      menu = [self instantiateObject: menu];
2039      [NSApp _setMainMenu: menu];
2040    }
2041}
2042
2043/**
2044 * Awake after loading the nib and extract the top level and owner for nib instantiation,
2045 * then call nibInstantateWithOwner:topLevelObjects:
2046 */
2047- (void) awakeWithContext: (NSDictionary *)context
2048{
2049  NSMutableArray *tlo = [context objectForKey: NSNibTopLevelObjects];
2050  id owner = [context objectForKey: NSNibOwner];
2051
2052  // instantiate...
2053  [self nibInstantiateWithOwner: owner topLevelObjects: tlo];
2054}
2055
2056/**
2057 * Retrieve an object by name from the map.
2058 */
2059- (id) objectForName: (NSString *)name
2060{
2061  NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
2062  NSArray *nameValues = (NSArray *)NSAllMapTableValues(_names);
2063  NSUInteger i = [nameValues indexOfObject: name];
2064  id result = nil;
2065
2066  if (i != NSNotFound)
2067    {
2068      result = [nameKeys objectAtIndex: i];
2069    }
2070
2071  return result;
2072}
2073
2074/**
2075 * Get the name for an object.
2076 */
2077- (NSString *) nameForObject: (id)obj
2078{
2079  NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
2080  NSArray *nameValues = (NSArray *)NSAllMapTableValues(_names);
2081  int i = [nameKeys indexOfObject: obj];
2082  NSString *result = [nameValues objectAtIndex: i];
2083  return result;
2084}
2085
2086/**
2087 * Set the root object.
2088 */
2089- (void) setRoot: (id) root
2090{
2091  ASSIGN(_root, root);
2092}
2093
2094/**
2095 * Return the root object.
2096 */
2097- (id) root
2098{
2099  return _root;
2100}
2101
2102/**
2103 * Set the value of the next available oid.
2104 */
2105- (void) setNextOid: (int)noid
2106{
2107  _nextOid = noid;
2108}
2109
2110/**
2111 * Get the value of the next available oid.
2112 */
2113- (int) nextOid
2114{
2115  return _nextOid;
2116}
2117
2118/**
2119 * Connections between objects.
2120 */
2121- (NSMutableArray *) connections
2122{
2123  return _connections;
2124}
2125
2126/**
2127 * Set of top level objects.
2128 */
2129- (NSMutableSet *) topLevelObjects
2130{
2131  return _topLevelObjects;
2132}
2133
2134/**
2135 * Names to objects
2136 */
2137- (NSMutableDictionary *) nameTable
2138{
2139  return nil;
2140}
2141
2142/**
2143 * Set of all visible windows.
2144 */
2145- (NSMutableArray *) visibleWindows
2146{
2147  return _visibleWindows;
2148}
2149
2150/**
2151 * Objects to names table.
2152 */
2153- (NSMapTable *) objects
2154{
2155  return _objects;
2156}
2157
2158/**
2159 * Names to objects table.
2160 */
2161- (NSMapTable *) names
2162{
2163  return _names;
2164}
2165
2166/**
2167 * Classes to objects table.
2168 */
2169- (NSMapTable *) classes
2170{
2171  return _classes;
2172}
2173
2174/**
2175 * Oids to objects table.
2176 */
2177- (NSMapTable *) oids
2178{
2179  return _oids;
2180}
2181@end
2182
2183/**
2184 * NSButtonImageSource
2185 *
2186 * This class is used by buttons to pull the correct image based on a given state.
2187 */
2188@implementation NSButtonImageSource
2189- (id) initWithCoder: (NSCoder *)coder
2190{
2191  if ([coder allowsKeyedCoding])
2192    {
2193      ASSIGN(imageName, [coder decodeObjectForKey: @"NSImageName"]);
2194    }
2195  else
2196    {
2197      [NSException raise: NSInvalidArgumentException
2198                   format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
2199                   NSStringFromClass([coder class])];
2200    }
2201
2202  AUTORELEASE(self);
2203  return RETAIN([NSImage imageNamed: imageName]);
2204}
2205
2206- (void) encodeWithCoder: (NSCoder *)coder
2207{
2208  if ([coder allowsKeyedCoding])
2209    {
2210      [coder encodeObject: imageName forKey: @"NSImageName"];
2211    }
2212  else
2213    {
2214      [NSException raise: NSInvalidArgumentException
2215                   format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
2216                   NSStringFromClass([coder class])];
2217    }
2218}
2219
2220/**
2221 * Initializes with image name.
2222 */
2223- (id) initWithImageNamed: (NSString *)name
2224{
2225  if ((self = [super init]) != nil)
2226    {
2227      ASSIGN(imageName,name);
2228    }
2229  return self;
2230}
2231
2232/**
2233 * Returns imageName.
2234 */
2235- (NSString *)imageName
2236{
2237  return imageName;
2238}
2239
2240- (void) dealloc
2241{
2242  RELEASE(imageName);
2243  [super dealloc];
2244}
2245@end
2246
2247@implementation NSIBHelpConnector
2248- (id) init
2249{
2250  if ((self = [super init]) != nil)
2251    {
2252      _file = nil;
2253      ASSIGN(_marker, @"NSToolTipHelpKey");
2254    }
2255  return self;
2256}
2257
2258- (void) dealloc
2259{
2260  RELEASE(_file);
2261  RELEASE(_marker);
2262  [super dealloc];
2263}
2264
2265- (id) initWithCoder: (NSCoder *)coder
2266{
2267  if ((self = [super initWithCoder: coder]) != nil)
2268    {
2269      if ([coder allowsKeyedCoding])
2270        {
2271          if ([coder containsValueForKey: @"NSFile"])
2272            {
2273              ASSIGN(_file, [coder decodeObjectForKey: @"NSFile"]);
2274            }
2275          if ([coder containsValueForKey: @"NSMarker"])
2276            {
2277              ASSIGN(_marker, [coder decodeObjectForKey: @"NSMarker"]);
2278            }
2279        }
2280      else
2281        {
2282          ASSIGN(_file, [coder decodeObject]);
2283          ASSIGN(_marker, [coder decodeObject]);
2284        }
2285    }
2286  return self;
2287}
2288
2289- (void) encodeWithCoder: (NSCoder *)coder
2290{
2291  [super encodeWithCoder: coder];
2292  if ([coder allowsKeyedCoding])
2293    {
2294      if (_file != nil)
2295        {
2296          [coder encodeObject: _file forKey: @"NSFile"];
2297        }
2298      if (_marker != nil)
2299        {
2300          [coder encodeObject: _marker forKey: @"NSMarker"];
2301        }
2302    }
2303  else
2304    {
2305      [coder encodeObject: _file];
2306      [coder encodeObject: _marker];
2307    }
2308}
2309
2310- (void) establishConnection
2311{
2312  if ([_dst respondsToSelector: @selector(setToolTip:)])
2313    {
2314      [_dst setToolTip: _marker];
2315    }
2316}
2317
2318- (void) setFile: (id)file
2319{
2320  ASSIGN(_file, file);
2321}
2322
2323- (id) file
2324{
2325  return _file;
2326}
2327
2328- (void) setMarker: (id)marker
2329{
2330  ASSIGN(_marker, marker);
2331}
2332
2333- (id) marker
2334{
2335  return _marker;
2336}
2337@end
2338
2339@implementation NSDecimalNumberPlaceholder
2340- (id) initWithCoder: (NSCoder *)coder
2341{
2342  NSDecimalNumber *dn = nil;
2343  if ([coder allowsKeyedCoding])
2344    {
2345      NSUInteger len = 0;
2346      short exponent = (short)[coder decodeIntForKey: @"NS.exponent"];
2347      NSByteOrder bo = [coder decodeIntForKey: @"NS.mantissa.bo"];
2348      BOOL negative = [coder decodeBoolForKey: @"NS.negative"];
2349      void *mantissaBytes = (void *)[coder decodeBytesForKey: @"NS.mantissa" returnedLength: &len];
2350      unsigned long long unswapped = 0;
2351      unsigned long long mantissa = 0;
2352
2353      // BOOL compact = [coder decodeBoolForKey: @"NS.compact"];
2354      // int length = [coder decodeIntForKey: @"NS.length"];
2355
2356      memcpy((void *)&unswapped, (void *)mantissaBytes, sizeof(unsigned long long));
2357
2358      switch(bo)
2359        {
2360        case NS_BigEndian:
2361          mantissa = NSSwapBigLongLongToHost(unswapped);
2362          break;
2363        case NS_LittleEndian:
2364          mantissa = NSSwapLittleLongLongToHost(unswapped);
2365          break;
2366        default:
2367          break;
2368        }
2369
2370      dn = [[NSDecimalNumber alloc] initWithMantissa: mantissa
2371                                    exponent: exponent
2372                                    isNegative: negative];
2373    }
2374
2375  RELEASE(self);
2376  return (id)dn;
2377}
2378
2379@end
2380
2381/**
2382 * NSCornerView
2383 *
2384 * Overridden in NSTableView to be GSTableCornerView,
2385 * but the class needs to be present to be overridden.
2386 *
2387 * Currently this is a place-holder class.
2388 */
2389@implementation _NSCornerView
2390@end
2391
2392/**
2393 * NSPSMatrix.
2394 *
2395 * This class is needed for nib encoding/decoding by transforms.
2396 * Currently it's only referenced in the NSProgressIndicator,
2397 * as far as I can tell.
2398 *
2399 * Place holder class.
2400 */
2401@implementation NSPSMatrix
2402- (void) encodeWithCoder: (NSCoder *)coder
2403{
2404  // do nothing... just encoding the presence of the class.
2405}
2406
2407- (id) initWithCoder: (NSCoder *)coder
2408{
2409  return self;
2410}
2411@end
2412
2413@implementation NSIBUserDefinedRuntimeAttributesConnector
2414- (void) setObject: (id)object
2415{
2416  ASSIGN(_object, object);
2417}
2418
2419- (id) object
2420{
2421  return _object;
2422}
2423
2424- (void) setValues: (id)values
2425{
2426  ASSIGN(_values, values);
2427}
2428
2429- (id) values
2430{
2431  return _values;
2432}
2433
2434- (void) setKeyPaths: (id)keyPaths
2435{
2436  ASSIGN(_keyPaths, keyPaths);
2437}
2438
2439- (id) keyPaths
2440{
2441  return _keyPaths;
2442}
2443
2444- (void) dealloc
2445{
2446  RELEASE(_object);
2447  RELEASE(_keyPaths);
2448  RELEASE(_values);
2449  [super dealloc];
2450}
2451
2452- (void) encodeWithCoder: (NSCoder *)coder
2453{
2454  if ([coder allowsKeyedCoding])
2455    {
2456      if (_object != nil)
2457        {
2458          [coder encodeObject: _object forKey: @"NSObject"];
2459        }
2460      if (_keyPaths != nil)
2461        {
2462          [coder encodeObject: _keyPaths forKey: @"NSKeyPaths"];
2463        }
2464      if (_values != nil)
2465        {
2466          [coder encodeObject: _values forKey: @"NSValues"];
2467        }
2468    }
2469  else
2470    {
2471      [coder encodeObject: _object];
2472      [coder encodeObject: _keyPaths];
2473      [coder encodeObject: _values];
2474    }
2475}
2476
2477- (id) initWithCoder: (NSCoder *)coder
2478{
2479  if ([coder allowsKeyedCoding])
2480    {
2481      if ([coder containsValueForKey: @"NSObject"])
2482        {
2483          ASSIGN(_object, [coder decodeObjectForKey: @"NSObject"]);
2484        }
2485      if ([coder containsValueForKey: @"NSKeyPaths"])
2486        {
2487          ASSIGN(_keyPaths, [coder decodeObjectForKey: @"NSKeyPaths"]);
2488        }
2489      if ([coder containsValueForKey: @"NSValues"])
2490        {
2491          ASSIGN(_values, [coder decodeObjectForKey: @"NSValues"]);
2492        }
2493    }
2494  else
2495    {
2496      ASSIGN(_object, [coder decodeObject]);
2497      ASSIGN(_keyPaths, [coder decodeObject]);
2498      ASSIGN(_values, [coder decodeObject]);
2499    }
2500
2501  return self;
2502}
2503
2504- (void) establishConnection
2505{
2506  // Loop over key paths and values and use KVC on object
2507  NSEnumerator *keyEn = [_keyPaths objectEnumerator];
2508  NSEnumerator *valEn = [_values objectEnumerator];
2509  id key;
2510
2511  while ((key = [keyEn nextObject]) != nil)
2512    {
2513      id val = [valEn nextObject];
2514
2515      [_object setValue: val forKeyPath: key];
2516    }
2517}
2518
2519- (void) instantiateWithObjectInstantiator: (id)instantiator
2520{
2521  [self setObject: [(id<GSInstantiator>)instantiator instantiateObject: _object]];
2522  // FIXME Should handle values too
2523}
2524
2525@end
2526