libs-gui/Source/GSNibLoading.m
Gregory John Casamento 09955c2002 * Source/GSNibLoading.m: Check to make sure the menu has more than
0 entries in _setMain:.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@27206 72102866-910b-0410-8b05-ffd578937521
2008-12-04 03:33:02 +00:00

1794 lines
44 KiB
Objective-C

/** <title>GSNibLoading</title>
<abstract>
These are templates for use with OSX Nib files. These classes are the
templates and other things which are needed for reading/writing nib files.
</abstract>
Copyright (C) 1997, 1999 Free Software Foundation, Inc.
Author: Gregory John Casamento
Date: 2003, 2005
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSClassDescription.h>
#include <Foundation/NSArchiver.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSBundle.h>
#include <Foundation/NSByteOrder.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDecimalNumber.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSException.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSObjCRuntime.h>
#include <Foundation/NSPathUtilities.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSString.h>
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSKeyValueCoding.h>
#include <Foundation/NSKeyedArchiver.h>
#include "AppKit/AppKit.h"
#include <GNUstepBase/GSObjCRuntime.h>
/*
* Setup for inline operation of arrays.
*/
#define GSI_ARRAY_RETAIN(A, X) RETAIN((X).obj)
#define GSI_ARRAY_RELEASE(A, X) RELEASE((X).obj)
#define GSI_ARRAY_TYPES GSUNION_OBJ
#include <GNUstepBase/GSIArray.h>
#include <GNUstepGUI/GSNibLoading.h>
#include <GNUstepGUI/GSInstantiator.h>
static BOOL _isInInterfaceBuilder = NO;
@interface NSMenu (NibCompatibility)
- (void) _setGeometry;
- (void) _setMain: (BOOL)isMain;
@end
@implementation NSMenu (NibCompatibility)
- (void) _setMain: (BOOL)isMain
{
if (isMain)
{
NSMenuView *oldRep;
NSInterfaceStyle oldStyle;
NSInterfaceStyle newStyle;
NSMenuItem *appItem;
NSString *processName;
if([self numberOfItems] == 0)
return;
appItem = [self itemAtIndex: 0]; // Info item.
oldRep = [self menuRepresentation];
oldStyle = [oldRep interfaceStyle];
newStyle = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
processName = [[NSProcessInfo processInfo] processName];
/*
* If necessary, rebuild menu for (different) style
*/
if (oldStyle != newStyle)
{
NSMenuView *newRep;
newRep = [[NSMenuView alloc] initWithFrame: NSZeroRect];
if (newStyle == NSMacintoshInterfaceStyle ||
newStyle == NSWindows95InterfaceStyle)
{
[newRep setHorizontal: YES];
}
else
{
[newRep setHorizontal: NO];
}
[newRep setInterfaceStyle: newStyle];
[self setMenuRepresentation: newRep];
RELEASE(newRep);
}
[[self window] setTitle: processName];
[[self window] setLevel: NSMainMenuWindowLevel];
// if it's a standard menu, transform it to be more NeXT'ish/GNUstep-like
if(_menu.horizontal == NO)
{
NSString *infoString = NSLocalizedString (@"Info", @"Info");
NSString *quitString = [NSString stringWithFormat: @"%@ %@",
NSLocalizedString (@"Quit", @"Quit"), processName];
NSMenuItem *quitItem = [[NSMenuItem alloc] initWithTitle: quitString
action: @selector(terminate:)
keyEquivalent: @"q"];
[self addItem: quitItem];
[self setTitle: processName];
[appItem setTitle: infoString];
[[appItem submenu] setTitle: infoString];
}
[self _setGeometry];
[self sizeToFit];
if ([NSApp isActive])
{
[self display];
}
}
else
{
[self close];
[[self window] setLevel: NSSubmenuWindowLevel];
}
}
@end
@interface NSApplication (NibCompatibility)
- (void) _setMainMenu: (NSMenu*)aMenu;
@end
@implementation NSApplication (NibCompatibility)
- (void) _setMainMenu: (NSMenu*)aMenu
{
if (_main_menu == aMenu)
{
return;
}
if (_main_menu != nil)
{
[_main_menu setMain: NO];
}
ASSIGN(_main_menu, aMenu);
if (_main_menu != nil)
{
[_main_menu _setMain: YES];
}
}
@end
@interface NSView (NibCompatibility)
- (void) _fixSubviews;
@end
@implementation NSView (NibCompatibility)
- (void) _setWindow: (id) w
{
ASSIGN(_window,w);
}
- (void) _fixSubviews
{
NSEnumerator *en = [[self subviews] objectEnumerator];
id v = nil;
while ((v = [en nextObject]) != nil)
{
if ([v window] != [self window] ||
[v superview] != self)
{
[v _setWindow: [self window]];
RETAIN(v);
[_sub_views removeObject: v];
[self addSubview: v];
RELEASE(v);
}
[v _fixSubviews];
}
}
@end
@implementation NSWindowTemplate
+ (void) initialize
{
if (self == [NSWindowTemplate class])
{
[self setVersion: 0];
}
}
- (void) dealloc
{
RELEASE(_title);
RELEASE(_viewClass);
RELEASE(_windowClass);
RELEASE(_view);
RELEASE(_autosaveName);
[super dealloc];
}
- (id) initWithWindow: (NSWindow *)window
className: (NSString *)windowClass
isDeferred: (BOOL) deferred
isOneShot: (BOOL) oneShot
isVisible: (BOOL) visible
wantsToBeColor: (BOOL) wantsToBeColor
autoPositionMask: (int) autoPositionMask
{
if ((self = [super init]) != nil)
{
if (window != nil)
{
// object members
ASSIGN(_title, [window title]);
ASSIGN(_viewClass, NSStringFromClass([[window contentView] class]));
ASSIGN(_windowClass, windowClass);
ASSIGN(_view, [window contentView]);
ASSIGN(_autosaveName, [window frameAutosaveName]);
// style & size
_windowStyle = [window styleMask];
_backingStoreType = [window backingType];
_maxSize = [window maxSize];
_minSize = [window minSize];
_windowRect = [window frame];
_screenRect = [[NSScreen mainScreen] frame];
// flags
_flags.isHiddenOnDeactivate = [window hidesOnDeactivate];
_flags.isNotReleasedOnClose = (![window isReleasedWhenClosed]);
_flags.isDeferred = deferred;
_flags.isOneShot = oneShot;
_flags.isVisible = visible;
_flags.wantsToBeColor = wantsToBeColor;
_flags.dynamicDepthLimit = [window hasDynamicDepthLimit];
_flags.autoPositionMask = autoPositionMask;
_flags.savePosition = YES; // not yet implemented.
}
}
return self;
}
- (id) initWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
if ([coder containsValueForKey: @"NSViewClass"])
{
ASSIGN(_viewClass, [coder decodeObjectForKey: @"NSViewClass"]);
}
if ([coder containsValueForKey: @"NSWindowClass"])
{
ASSIGN(_windowClass, [coder decodeObjectForKey: @"NSWindowClass"]);
}
if ([coder containsValueForKey: @"NSWindowStyleMask"])
{
_windowStyle = [coder decodeIntForKey: @"NSWindowStyleMask"];
}
if ([coder containsValueForKey: @"NSWindowBacking"])
{
_backingStoreType = [coder decodeIntForKey: @"NSWindowBacking"];
}
if ([coder containsValueForKey: @"NSWindowView"])
{
ASSIGN(_view, [coder decodeObjectForKey: @"NSWindowView"]);
}
if ([coder containsValueForKey: @"NSWTFlags"])
{
unsigned long flags = [coder decodeIntForKey: @"NSWTFlags"];
memcpy((void *)&_flags,(void *)&flags,sizeof(struct _GSWindowTemplateFlags));
}
if ([coder containsValueForKey: @"NSMinSize"])
{
_minSize = [coder decodeSizeForKey: @"NSMinSize"];
}
if ([coder containsValueForKey: @"NSMaxSize"])
{
_maxSize = [coder decodeSizeForKey: @"NSMaxSize"];
}
else
{
_maxSize = NSMakeSize (10e4, 10e4);
}
if ([coder containsValueForKey: @"NSWindowRect"])
{
_windowRect = [coder decodeRectForKey: @"NSWindowRect"];
}
if ([coder containsValueForKey: @"NSFrameAutosaveName"])
{
ASSIGN(_autosaveName, [coder decodeObjectForKey: @"NSFrameAutosaveName"]);
}
if ([coder containsValueForKey: @"NSWindowTitle"])
{
ASSIGN(_title, [coder decodeObjectForKey: @"NSWindowTitle"]);
_windowStyle |= NSTitledWindowMask;
}
_baseWindowClass = [NSWindow class];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)aCoder
{
if ([aCoder allowsKeyedCoding])
{
unsigned long flags = 0;
NSRect rect = [NSWindow contentRectForFrameRect: _windowRect
styleMask: _windowStyle];
memcpy((void *)&flags,(void *)&_flags,sizeof(unsigned long));
[aCoder encodeObject: _viewClass forKey: @"NSViewClass"];
[aCoder encodeObject: _windowClass forKey: @"NSWindowClass"];
[aCoder encodeInt: _windowStyle forKey: @"NSWindowStyleMask"];
[aCoder encodeInt: _backingStoreType forKey: @"NSWindowBacking"];
[aCoder encodeObject: _view forKey: @"NSWindowView"];
[aCoder encodeInt: flags forKey: @"NSWTFlags"];
[aCoder encodeSize: _minSize forKey: @"NSMinSize"];
[aCoder encodeSize: _maxSize forKey: @"NSMaxSize"];
[aCoder encodeRect: rect forKey: @"NSWindowRect"];
[aCoder encodeObject: _title forKey: @"NSWindowTitle"];
[aCoder encodeObject: _autosaveName forKey: @"NSFrameAutosaveName"];
}
}
- (id) nibInstantiate
{
if (_realObject == nil)
{
Class aClass;
NSEnumerator *en;
id v = nil;
if ([NSClassSwapper isInInterfaceBuilder])
{
aClass = [self baseWindowClass];
}
else
{
aClass = NSClassFromString(_windowClass);
}
if (aClass == nil)
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to find class '%@'", _windowClass];
}
_realObject = [[aClass allocWithZone: NSDefaultMallocZone()]
initWithContentRect: _windowRect
styleMask: _windowStyle
backing: _backingStoreType
defer: _flags.isDeferred
screen: nil];
// set flags...
[_realObject setHidesOnDeactivate: _flags.isHiddenOnDeactivate];
[_realObject setReleasedWhenClosed: !(_flags.isNotReleasedOnClose)];
[_realObject setOneShot: _flags.isOneShot];
// [_realObject setVisible: _flags.isVisible]; // this is determined by whether it's in the visible windows array...
// [_realObject setWantsToBeColor: _flags.wantsToBeColor]; // not applicable on GNUstep.
[_realObject setAutodisplay: YES];
[_realObject setDynamicDepthLimit: _flags.dynamicDepthLimit];
// [_realObject setAutoPositionMask: _flags.autoPositionMask]; // currently not implemented for nibs
// [_realObject setAutoPosition: _flags.autoPosition];
[_realObject setDynamicDepthLimit: _flags.dynamicDepthLimit];
[_realObject setFrameAutosaveName: _autosaveName];
// reset attributes...
[_realObject setContentView: _view];
[_realObject setMinSize: _minSize];
[_realObject setMaxSize: _maxSize];
[_realObject setTitle: _title];
[_view _fixSubviews];
// resize the window...
[_realObject setFrame: [NSWindow frameRectForContentRect: [self windowRect]
styleMask: [self windowStyle]]
display: NO];
// swap out any views which need to be swapped...
en = [[[_realObject contentView] subviews] objectEnumerator];
while ((v = [en nextObject]) != nil)
{
if ([v respondsToSelector: @selector(nibInstantiate)])
{
[v nibInstantiate];
}
}
}
return _realObject;
}
// setters and getters
- (void) setBackingStoreType: (NSBackingStoreType)type
{
_backingStoreType = type;
}
- (NSBackingStoreType) backingStoreType
{
return _backingStoreType;
}
- (void) setDeferred: (BOOL)flag
{
_flags.isDeferred = flag;
}
- (BOOL) isDeferred
{
return _flags.isDeferred;
}
- (void) setMaxSize: (NSSize)maxSize
{
_maxSize = maxSize;
}
- (NSSize) maxSize
{
return _maxSize;
}
- (void) setMinSize: (NSSize)minSize
{
_minSize = minSize;
}
- (NSSize) minSize
{
return _minSize;
}
- (void) setWindowStyle: (unsigned)style
{
_windowStyle = style;
}
- (unsigned) windowStyle
{
return _windowStyle;
}
- (void) setTitle: (NSString *) title
{
ASSIGN(_title, title);
}
- (NSString *)title;
{
return _title;
}
- (void) setViewClass: (NSString *)viewClass
{
ASSIGN(_viewClass,viewClass);
}
- (NSString *)viewClass
{
return _viewClass;
}
- (void) setWindowRect: (NSRect)rect
{
_windowRect = rect;
}
- (NSRect)windowRect
{
return _windowRect;
}
- (void) setScreenRect: (NSRect)rect
{
_screenRect = rect;
}
- (NSRect) screenRect
{
return _screenRect;
}
- (id) realObject
{
return _realObject;
}
- (void) setView: (id)view
{
ASSIGN(_view,view);
}
- (id) view
{
return _view;
}
- (void) setClassName: (NSString *)name
{
ASSIGN(_windowClass, name);
}
- (NSString *)className
{
return _windowClass;
}
- (Class) baseWindowClass
{
return _baseWindowClass;
}
@end
// Template for any classes which derive from NSView
@implementation NSViewTemplate
+ (void) initialize
{
if (self == [NSViewTemplate class])
{
[self setVersion: 0];
}
}
- (id) initWithCoder: (NSCoder *)coder
{
self = [super initWithCoder: coder];
if (self != nil)
{
if ([coder allowsKeyedCoding])
{
_className = [coder decodeObjectForKey: @"NSClassName"];
}
if (_realObject == nil)
{
Class aClass = NSClassFromString(_className);
if (aClass == nil)
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to find class '%@'", _className];
}
else
{
_realObject = [[aClass allocWithZone: NSDefaultMallocZone()] initWithCoder: coder];
[[self superview] replaceSubview: self with: _realObject]; // replace the old view...
}
}
return _realObject;
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return nil;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: (id)_className forKey: @"NSClassName"];
}
}
- (id) nibInstantiate
{
return _realObject;
}
// setters and getters
- (void) setClassName: (NSString *)name
{
ASSIGN(_className, name);
}
- (NSString *)className
{
return _className;
}
- (id) realObject
{
return _realObject;
}
@end
// Template for any classes which derive from NSText
@implementation NSTextTemplate
+ (void) initialize
{
if (self == [NSTextTemplate class])
{
[self setVersion: 0];
}
}
@end
// Template for any classes which derive from NSTextView
@implementation NSTextViewTemplate
+ (void) initialize
{
if (self == [NSTextViewTemplate class])
{
[self setVersion: 0];
}
}
@end
// Template for any classes which derive from NSMenu.
@implementation NSMenuTemplate
+ (void) initialize
{
if (self == [NSMenuTemplate class])
{
[self setVersion: 0];
}
}
- (id) initWithCoder: (NSCoder *)aCoder
{
return nil;
}
- (void) encodeWithCoder: (NSCoder *)aCoder
{
}
- (id) nibInstantiate
{
return nil;
}
- (void) setClassName: (NSString *)className
{
ASSIGN(_menuClass, className);
}
- (NSString *)className
{
return _menuClass;
}
- (id) realObject
{
return _realObject;
}
@end
@implementation NSCustomObject
- (void) setClassName: (NSString *)name
{
ASSIGNCOPY(_className, name);
}
- (NSString *)className
{
return _className;
}
- (void) setExtension: (NSString *)name
{
ASSIGNCOPY(_extension, name);
}
- (NSString *)extension
{
return _extension;
}
- (void) setObject: (id)obj
{
ASSIGN(_object, obj);
}
- (id) object
{
return _object;
}
- (id) initWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
ASSIGN(_extension, [coder decodeObjectForKey: @"NSExtension"]);
ASSIGN(_object, [coder decodeObjectForKey: @"NSObject"]);
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: (id)_className forKey: @"NSClassName"];
[coder encodeConditionalObject: (id)_extension forKey: @"NSExtension"];
[coder encodeConditionalObject: (id)_object forKey: @"NSObject"];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Keyed coding not implemented for %@.",
NSStringFromClass([self class])];
}
}
- (id) nibInstantiate
{
if (_object == nil)
{
Class aClass;
if ([NSClassSwapper isInInterfaceBuilder])
{
aClass = [self class];
}
else
{
aClass = NSClassFromString(_className);
}
if (aClass == nil)
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to find class '%@'", _className];
}
if(GSObjCIsKindOf(aClass, [NSApplication class]))
{
_object = [aClass sharedApplication];
}
else
{
_object = [[aClass allocWithZone: NSDefaultMallocZone()] init];
}
}
return _object;
}
- (void) awakeFromNib
{
if ([_object respondsToSelector: @selector(awakeFromNib)])
{
[_object awakeFromNib];
}
}
- (void) dealloc
{
RELEASE(_className);
RELEASE(_extension);
[super dealloc];
}
@end
@implementation NSCustomView
- (void) setClassName: (NSString *)name
{
ASSIGNCOPY(_className, name);
}
- (NSString *)className
{
return _className;
}
- (void) setExtension: (NSString *)ext;
{
ASSIGNCOPY(_extension, ext);
}
- (NSString *)extension
{
return _extension;
}
- (id) nibInstantiate
{
if (_view == nil)
{
Class aClass;
if ([NSClassSwapper isInInterfaceBuilder])
{
aClass = [self class];
}
else
{
aClass = NSClassFromString(_className);
}
if (aClass == nil)
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to find class '%@'", _className];
}
else
{
_view = [[aClass allocWithZone: NSDefaultMallocZone()] initWithFrame: [self frame]];
[_view setAutoresizingMask: [self autoresizingMask]];
[_view setAutoresizesSubviews: [self autoresizesSubviews]];
[_view setHidden: [self isHidden]];
[_view setNextResponder: [self nextResponder]];
// [[self superview] replaceSubview: self with: _view]; // replace the old view...
if (_rFlags.has_subviews)
{
NSArray *subviews = [self subviews];
int i;
for (i = 0; i < [subviews count]; i++)
{
[_view addSubview: [subviews objectAtIndex: i]];
}
}
// FIXME: Need to transfer all other settings as well
}
}
return _view;
}
- (id) initWithCoder: (NSCoder *)coder
{
self = [super initWithCoder: coder];
if (self != nil)
{
if ([coder allowsKeyedCoding])
{
ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
ASSIGN(_extension, [coder decodeObjectForKey: @"NSExtension"]);
AUTORELEASE(self);
self = [self nibInstantiate];
RETAIN(self);
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[super encodeWithCoder: coder];
if ([coder allowsKeyedCoding])
{
[coder encodeObject: _className forKey: @"NSClassName"];
[coder encodeObject: _extension forKey: @"NSExtension"];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
}
@end
@implementation NSCustomResource
- (void) setClassName: (NSString *)className
{
ASSIGNCOPY(_className, className);
}
- (NSString *)className
{
return _className;
}
- (void) setResourceName: (NSString *)resourceName
{
ASSIGNCOPY(_resourceName, resourceName);
}
- (NSString *)resourceName
{
return _resourceName;
}
- (id)nibInstantiate
{
return self;
}
- (id) initWithCoder: (NSCoder *)coder
{
id realObject = nil;
if ([coder allowsKeyedCoding])
{
ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
ASSIGN(_resourceName, [coder decodeObjectForKey: @"NSResourceName"]);
// this is a hack, but for now it should do.
if ([_className isEqual: @"NSSound"])
{
realObject = RETAIN([NSSound soundNamed: _resourceName]);
}
else if ([_className isEqual: @"NSImage"])
{
realObject = RETAIN([NSImage imageNamed: _resourceName]);
}
// if an object has been substituted, then release the placeholder.
if (realObject != nil)
{
RELEASE(self);
}
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return realObject;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: (id)_className forKey: @"NSClassName"];
[coder encodeObject: (id)_resourceName forKey: @"NSResourceName"];
}
}
@end
@interface NSKeyedUnarchiver (NSClassSwapperPrivate)
- (BOOL) replaceObject: (id)oldObj withObject: (id)newObj;
- (NSDictionary *)keyMap;
- (Class) replacementClassForClassName: (NSString *)className;
@end
@implementation NSKeyedUnarchiver (NSClassSwapperPrivate)
- (BOOL) replaceObject: (id)oldObj withObject: (id)newObj
{
unsigned int i = 0;
unsigned int count = GSIArrayCount(_objMap);
for (i = 0; i < count; i++)
{
id obj = GSIArrayItemAtIndex(_objMap, i).obj;
if (obj == oldObj)
break;
}
if (i < count)
{
GSIArraySetItemAtIndex(_objMap, (GSIArrayItem)newObj, i);
return YES;
}
return NO;
}
- (NSDictionary *)keyMap
{
return _keyMap;
}
- (Class) replacementClassForClassName: (NSString *)className
{
Class aClass;
if ((aClass = [self classForClassName: className]) == nil)
{
aClass = NSClassFromString(className);
}
if (aClass == nil)
{
[NSException raise: NSInternalInconsistencyException
format: @"NSClassSwapper unable to find class '%@'", className];
}
return aClass;
}
@end
@implementation NSClassSwapper
- (id) initWithObject: (id)object
withClassName: (NSString *)className
originalClassName: (NSString *)origClassName
{
if ((self = [super init]) != nil)
{
[self setTemplate: object];
[self setClassName: className];
[self setOriginalClassName: origClassName];
}
return self;
}
+ (void) setIsInInterfaceBuilder: (BOOL)flag
{
_isInInterfaceBuilder = flag;
}
+ (BOOL) isInInterfaceBuilder
{
return _isInInterfaceBuilder;
}
- (void) setTemplate: (id)temp
{
ASSIGN(_template, temp);
}
- (id) template
{
return _template;
}
- (void) setClassName: (NSString *)className
{
ASSIGNCOPY(_className, className);
}
- (NSString *)className
{
return _className;
}
- (void) setOriginalClassName: (NSString *)className
{
ASSIGNCOPY(_originalClassName, className);
}
- (NSString *)originalClassName
{
return _originalClassName;
}
- (void) instantiateRealObject: (NSCoder *)coder withClassName: (NSString *)className
{
Class newClass = nil;
id object = nil;
NSKeyedUnarchiver *decoder = (NSKeyedUnarchiver *)coder;
if([NSClassSwapper isInInterfaceBuilder] == YES)
{
newClass = [decoder replacementClassForClassName: _originalClassName];
}
else
{
newClass = [decoder replacementClassForClassName: className];
}
// swap the class...
object = [newClass allocWithZone: NSDefaultMallocZone()];
[decoder setDelegate: self]; // set the delegate...
[decoder replaceObject: self withObject: object];
[self setTemplate: [object initWithCoder: decoder]];
if (object != _template)
{
[decoder replaceObject: object withObject: _template];
}
[decoder setDelegate: nil]; // unset the delegate...
}
// Delegate method...
- (id) unarchiver: (NSKeyedUnarchiver *)coder
didDecodeObject: (id)obj
{
Class newClass = nil;
id result = obj;
// if we are in an interface builder, then return the original object.
if ([NSClassSwapper isInInterfaceBuilder] == YES)
{
newClass = [coder replacementClassForClassName: _originalClassName];
}
else
{
newClass = [coder replacementClassForClassName: _className];
}
// if this is a class which uses cells, override with the new cellClass, if the
// subclass responds to cellClass.
if ([obj isKindOfClass: [NSCell class]] &&
[newClass respondsToSelector: @selector(cellClass)] &&
[_className isEqualToString: _originalClassName] == NO)
{
Class newCellClass = [newClass cellClass];
if(newCellClass != [NSCell class])
{
result = [[newCellClass alloc] initWithCoder: coder];
}
}
return result;
}
- (id) initWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
ASSIGN(_className, [coder decodeObjectForKey: @"NSClassName"]);
ASSIGN(_originalClassName, [coder decodeObjectForKey: @"NSOriginalClassName"]);
// build the real object...
if ([NSClassSwapper isInInterfaceBuilder] == YES)
{
[self instantiateRealObject: coder withClassName: _originalClassName];
}
else
{
[self instantiateRealObject: coder withClassName: _className];
}
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return _template;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: _originalClassName forKey: @"NSOriginalClassName"];
[coder encodeObject: _className forKey: @"NSClassName"];
[_template encodeWithCoder: coder]; // encode the actual object;
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
}
- (void) dealloc
{
RELEASE(_className);
RELEASE(_originalClassName);
RELEASE(_template);
[super dealloc];
}
@end
/* Correct some instances where the ":" is missing from the method name in the label */
@interface NSNibControlConnector (NibCompatibility)
- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator;
@end
@implementation NSNibControlConnector (NibCompatibility)
- (void) instantiateWithInstantiator: (id<GSInstantiator>)instantiator
{
NSRange colonRange = [_tag rangeOfString: @":"];
unsigned int location = colonRange.location;
if (location == NSNotFound)
{
NSString *newTag = [NSString stringWithFormat: @"%@:",_tag];
[self setLabel: (id)newTag];
}
[super instantiateWithInstantiator: instantiator];
}
@end
@implementation NSIBObjectData
- (id)instantiateObject: (id)obj
{
id newObject = obj;
if ([obj respondsToSelector: @selector(nibInstantiate)])
{
newObject = [obj nibInstantiate];
}
return newObject;
}
- (void) nibInstantiateWithOwner: (id)owner
{
[self nibInstantiateWithOwner: owner topLevelObjects: nil];
}
- (void) nibInstantiateWithOwner: (id)owner topLevelObjects: (NSMutableArray *)topLevelObjects
{
NSEnumerator *en = [_connections objectEnumerator];
NSArray *objs = NSAllMapTableKeys([self names]);
id obj = nil;
id menu = nil;
// replace the owner with the actual instance provided.
[_root setObject: owner];
// iterate over connections, instantiate, and then establish them.
while ((obj = [en nextObject]) != nil)
{
if ([obj respondsToSelector: @selector(instantiateWithInstantiator:)])
{
[obj instantiateWithInstantiator: self];
[obj establishConnection];
}
}
// iterate over all objects instantiate windows, awaken objects and fill
// in top level array.
en = [objs objectEnumerator];
while ((obj = [en nextObject]) != nil)
{
// instantiate all windows and fill in the top level array.
if ([obj isKindOfClass: [NSWindowTemplate class]])
{
if ([obj realObject] == nil)
{
obj = [self instantiateObject: obj];
[topLevelObjects addObject: obj];
}
}
else
{
id v = NSMapGet(_objects, obj);
if (v == nil || v == owner)
{
[topLevelObjects addObject: obj];
}
}
// awaken the object.
if ([obj respondsToSelector: @selector(awakeFromNib)])
{
[obj awakeFromNib];
}
}
// bring visible windows to front...
en = [_visibleWindows objectEnumerator];
while ((obj = [en nextObject]) != nil)
{
id w = [obj realObject];
[w orderFront: self];
}
// add the menu...
menu = [self objectForName: @"MainMenu"];
if (menu != nil)
{
menu = [self instantiateObject: menu];
[NSApp _setMainMenu: menu];
}
}
- (void) awakeWithContext: (NSDictionary *)context
{
NSMutableArray *tlo = [context objectForKey: @"NSTopLevelObjects"];
id owner = [context objectForKey: @"NSOwner"];
[self nibInstantiateWithOwner: owner topLevelObjects: tlo];
}
- (NSMutableArray *) connections
{
return _connections;
}
- (NSMutableSet *) topLevelObjects
{
return _topLevelObjects;
}
- (NSMutableDictionary *) nameTable
{
return nil;
}
- (NSMutableArray *) visibleWindows
{
return _visibleWindows;
}
- (NSMapTable *) objects
{
return _objects;
}
- (NSMapTable *) names
{
return _names;
}
- (NSMapTable *) classes
{
return _classes;
}
- (NSMapTable *) oids
{
return _oids;
}
- (id) objectForName: (NSString *)name
{
NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
NSArray *nameValues = (NSArray *)NSAllMapTableValues(_names);
int i = [nameValues indexOfObject: name];
id result = nil;
if (i != NSNotFound)
{
result = [nameKeys objectAtIndex: i];
}
return result;
}
- (NSString *) nameForObject: (id)obj
{
NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
NSArray *nameValues = (NSArray *)NSAllMapTableValues(_names);
int i = [nameKeys indexOfObject: obj];
NSString *result = [nameValues objectAtIndex: i];
return result;
}
/**
* Get the values from the map in the same order as the keys.
*/
- (NSArray *) _valuesForKeys: (NSArray *)keys inMap: (NSMapTable *)map
{
NSMutableArray *result = [NSMutableArray array];
NSEnumerator *en = [keys objectEnumerator];
id key = nil;
while ((key = [en nextObject]) != nil)
{
id value = (id)NSMapGet(map,key);
[result addObject: value];
}
return result;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
NSArray *accessibilityOidsKeys = (NSArray *)NSAllMapTableKeys(_accessibilityOids);
NSArray *accessibilityOidsValues = [self _valuesForKeys: accessibilityOidsKeys inMap: _accessibilityOids];
NSArray *classKeys = (NSArray *)NSAllMapTableKeys(_classes);
NSArray *classValues = [self _valuesForKeys: classKeys inMap: _classes];
NSArray *nameKeys = (NSArray *)NSAllMapTableKeys(_names);
NSArray *nameValues = [self _valuesForKeys: nameKeys inMap: _names];
NSArray *objectsKeys = (NSArray *)NSAllMapTableKeys(_objects);
NSArray *objectsValues = [self _valuesForKeys: objectsKeys inMap: _objects];
NSArray *oidsKeys = (NSArray *)NSAllMapTableKeys(_oids);
NSArray *oidsValues = [self _valuesForKeys: oidsKeys inMap: _oids];
[(NSKeyedArchiver *)coder setClassName: @"_NSCornerView" forClass: NSClassFromString(@"GSTableCornerView")];
[coder encodeObject: (id)_accessibilityConnectors forKey: @"NSAccessibilityConnectors"];
[coder encodeObject: (id) accessibilityOidsKeys forKey: @"NSAccessibilityOidsKeys"];
[coder encodeObject: (id) accessibilityOidsValues forKey: @"NSAccessibilityOidsValues"];
[coder encodeObject: (id) classKeys forKey: @"NSClassesKeys"];
[coder encodeObject: (id) classValues forKey: @"NSClassesValues"];
[coder encodeObject: (id) nameKeys forKey: @"NSNamesKeys"];
[coder encodeObject: (id) nameValues forKey: @"NSNamesValues"];
[coder encodeObject: (id) objectsKeys forKey: @"NSObjectsKeys"];
[coder encodeObject: (id) objectsValues forKey: @"NSObjectsValues"];
[coder encodeObject: (id) oidsKeys forKey: @"NSOidsKeys"];
[coder encodeObject: (id) oidsValues forKey: @"NSOidsValues"];
[coder encodeObject: (id) _connections forKey: @"NSConnections"];
[coder encodeObject: (id) _fontManager forKey: @"NSFontManager"];
[coder encodeObject: (id) _framework forKey: @"NSFramework"];
[coder encodeObject: (id) _visibleWindows forKey: @"NSVisibleWindows"];
[coder encodeInt: _nextOid forKey: @"NSNextOid"];
[coder encodeConditionalObject: (id) _root forKey: @"NSRoot"];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
}
- (void) _buildMap: (NSMapTable *)mapTable
withKeys: (NSArray *)keys
andValues: (NSArray *)values
{
NSEnumerator *ken = [keys objectEnumerator];
NSEnumerator *ven = [values objectEnumerator];
id key = nil;
id value = nil;
while ((key = [ken nextObject]) != nil && (value = [ven nextObject]) != nil)
{
NSMapInsert(mapTable, key, value);
if(value == nil)
{
NSLog(@"==> WARNING: Value for key %@ is %@",key , value);
}
}
}
- (id) initWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
ASSIGN(_root, [coder decodeObjectForKey: @"NSRoot"]);
ASSIGN(_visibleWindows, (NSMutableArray *)[coder decodeObjectForKey: @"NSVisibleWindows"]);
ASSIGN(_accessibilityConnectors, (NSMutableArray *)[coder decodeObjectForKey: @"NSAccessibilityConnectors"]);
ASSIGN(_fontManager, [coder decodeObjectForKey: @"NSFontManager"]);
ASSIGN(_framework, [coder decodeObjectForKey: @"NSFramework"]);
_nextOid = [coder decodeIntForKey: @"NSNextOid"];
{
NSArray *objectsKeys = (NSArray *)
[coder decodeObjectForKey: @"NSObjectsKeys"];
NSArray *objectsValues = (NSArray *)
[coder decodeObjectForKey: @"NSObjectsValues"];
NSArray *nameKeys = (NSArray *)
[coder decodeObjectForKey: @"NSNamesKeys"];
NSArray *nameValues = (NSArray *)
[coder decodeObjectForKey: @"NSNamesValues"];
NSArray *oidsKeys = (NSArray *)
[coder decodeObjectForKey: @"NSOidsKeys"];
NSArray *oidsValues = (NSArray *)
[coder decodeObjectForKey: @"NSOidsValues"];
NSArray *classKeys = (NSArray *)
[coder decodeObjectForKey: @"NSClassesKeys"];
NSArray *classValues = (NSArray *)
[coder decodeObjectForKey: @"NSClassesValues"];
NSArray *accessibilityOidsKeys = (NSArray *)
[coder decodeObjectForKey: @"NSAccessibilityOidsKeys"];
NSArray *accessibilityOidsValues = (NSArray *)
[coder decodeObjectForKey: @"NSAccessibilityOidsValues"];
// instantiate the maps..
_objects = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_names = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_oids = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_classes = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_accessibilityOids = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
// fill in the maps...
[self _buildMap: _accessibilityOids
withKeys: accessibilityOidsKeys
andValues: accessibilityOidsValues];
[self _buildMap: _classes
withKeys: classKeys
andValues: classValues];
[self _buildMap: _names
withKeys: nameKeys
andValues: nameValues];
[self _buildMap: _objects
withKeys: objectsKeys
andValues: objectsValues];
[self _buildMap: _oids
withKeys: oidsKeys
andValues: oidsValues];
ASSIGN(_connections, [[coder decodeObjectForKey: @"NSConnections"] mutableCopy]);
// instantiate...
_topLevelObjects = [[NSMutableSet alloc] init];
}
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
return self;
}
- (id) init
{
if ((self = [super init]) != nil)
{
// instantiate the maps..
_objects = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_names = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_oids = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_classes = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
_accessibilityOids = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 2);
// initialize the objects...
_accessibilityConnectors = [[NSMutableArray alloc] init];
_connections = [[NSMutableArray alloc] init];
_visibleWindows = [[NSMutableArray alloc] init];
_framework = nil;
_fontManager = nil;
_root = nil;
_nextOid = 0;
}
return self;
}
- (void) dealloc
{
// free the maps.
NSFreeMapTable(_objects);
NSFreeMapTable(_names);
NSFreeMapTable(_oids);
NSFreeMapTable(_classes);
NSFreeMapTable(_accessibilityOids);
// free other objects.
RELEASE(_accessibilityConnectors);
RELEASE(_connections);
RELEASE(_fontManager);
RELEASE(_framework);
RELEASE(_visibleWindows);
RELEASE(_root);
RELEASE(_topLevelObjects);
[super dealloc];
}
- (void) setRoot: (id) root
{
ASSIGN(_root, root);
}
- (id) root
{
return _root;
}
- (void) setNextOid: (int)noid
{
_nextOid = noid;
}
- (int) nextOid
{
return _nextOid;
}
@end
@implementation NSButtonImageSource
- (id) initWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
ASSIGN(imageName, [coder decodeObjectForKey: @"NSImageName"]);
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't decode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
RELEASE(self);
return [NSImage imageNamed: imageName];
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: imageName forKey: @"NSImageName"];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Can't encode %@ with %@.",NSStringFromClass([self class]),
NSStringFromClass([coder class])];
}
}
- (id) initWithImageNamed: (NSString *)name
{
if ((self = [super init]) != nil)
{
ASSIGN(imageName,name);
}
return self;
}
- (NSString *)imageName
{
return imageName;
}
- (void) dealloc
{
RELEASE(imageName);
[super dealloc];
}
@end
@implementation NSIBHelpConnector
- (id) init
{
if ((self = [super init]) != nil)
{
_file = nil;
_marker = @"NSToolTipHelpKey";
}
return self;
}
- (id) initWithCoder: (NSCoder *)coder
{
if ((self = [super initWithCoder: coder]) != nil)
{
if ([coder allowsKeyedCoding])
{
if ([coder containsValueForKey: @"NSFile"])
{
_file = RETAIN([coder decodeObjectForKey: @"NSFile"]);
}
if ([coder containsValueForKey: @"NSMarker"])
{
_marker = RETAIN([coder decodeObjectForKey: @"NSMarker"]);
}
}
else
{
_file = RETAIN([coder decodeObject]);
_marker = RETAIN([coder decodeObject]);
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[super encodeWithCoder: coder];
if ([coder allowsKeyedCoding])
{
if (_file != nil)
{
[coder encodeObject: _file forKey: @"NSFile"];
}
if (_marker != nil)
{
[coder encodeObject: _file forKey: @"NSMarker"];
}
}
else
{
[coder encodeObject: _file];
[coder encodeObject: _marker];
}
}
- (void) establishConnection
{
if([_dst respondsToSelector: @selector(setToolTip:)])
{
[_dst setToolTip: _marker];
}
}
- (void) setFile: (id)file
{
ASSIGN(_file, file);
}
- (id) file
{
return _file;
}
- (void) setMarker: (id)marker
{
ASSIGN(_marker, marker);
}
- (id) marker
{
return _marker;
}
@end
@interface NSDecimalNumberPlaceholder : NSObject
@end
@implementation NSDecimalNumberPlaceholder
- (id) initWithCoder: (NSCoder *)coder
{
NSDecimalNumber *dn = nil;
if ([coder allowsKeyedCoding])
{
unsigned int len = 0;
short exponent = (short)[coder decodeIntForKey: @"NS.exponent"];
NSByteOrder bo = [coder decodeIntForKey: @"NS.mantissa.bo"];
BOOL negative = [coder decodeBoolForKey: @"NS.negative"];
void *mantissaBytes = (void *)[coder decodeBytesForKey: @"NS.mantissa" returnedLength: &len];
unsigned long long unswapped = 0;
unsigned long long mantissa = 0;
// BOOL compact = [coder decodeBoolForKey: @"NS.compact"];
// int length = [coder decodeIntForKey: @"NS.length"];
memcpy((void *)&unswapped, (void *)mantissaBytes, sizeof(unsigned long long));
switch(bo)
{
case NS_BigEndian:
mantissa = NSSwapBigLongLongToHost(unswapped);
break;
case NS_LittleEndian:
mantissa = NSSwapLittleLongLongToHost(unswapped);
break;
default:
break;
}
dn = [[NSDecimalNumber alloc] initWithMantissa: mantissa
exponent: exponent
isNegative: negative];
}
return dn;
}
@end
// ...dummy/placeholder classes...
// overridden in NSTableView to be GSTableCornerView,
// but the class needs to be present to be overridden.
@interface _NSCornerView : NSView
@end
@implementation _NSCornerView
@end
// class needed for nib encoding/decoding by
@implementation NSPSMatrix
- (void) encodeWithCoder: (NSCoder *)coder
{
// do nothing... just encoding the presence of the class.
}
- (id) initWithCoder: (NSCoder *)coder
{
// what's NSPSMatix all about?
// NSLog(@"NSPSMatrix = %@",[(NSKeyedUnarchiver *)coder keyMap]);
return self;
}
@end