Implemented nib support - No, not NeXTstep/OPENSTEP/MacOS-X compatible file

format, but a compatible API, and a fast, simple implementation.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3562 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 1999-01-15 10:14:28 +00:00
parent e132102ecb
commit 895e64b697
3 changed files with 290 additions and 20 deletions

View file

@ -1,3 +1,12 @@
Fri Jan 15 9:30:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Headers/AppKit/NSNibLoading.h: Added interface for new class -
GSNibContainer - to manage the contents of a nib.
* Source/NSBundleAdditions.m: Added implementation of GSNibContainer
and implemented the nib loading methods using it and NSArchiver.
This should give us a fast and simple alternative to gmodel files
where portability (and the ability to edit by hand) is not a issue.
Tue Jan 12 11:57:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSWindow.m: ([-sendEvent:]) fix cursor update code to set

View file

@ -3,10 +3,12 @@
Something to do with loading Nibs?
Copyright (C) 1997 Free Software Foundation, Inc.
Copyright (C) 1997, 1999 Free Software Foundation, Inc.
Author: Simon Frankau <sgf@frankau.demon.co.uk>
Date: 1997
Author: Richard Frith-Macdonald <richard@branstorm.co.uk>
Date: 1999
This file is part of the GNUstep GUI Library.
@ -28,28 +30,55 @@
#ifndef _GNUstep_H_NSNibLoading
#define _GNUstep_H_NSNibLoading
#include <Foundation/NSObject.h>
#include <Foundation/NSBundle.h>
#include <Foundation/NSDictionary.h>
@class NSString;
@class NSDictionary;
@class NSMutableDictionary;
@interface NSObject (NSNibAwaking)
//
// Notification of Loading
//
- (void)awakeFromNib;
- (void) awakeFromNib;
@end
@interface NSBundle (NSNibLoading)
+ (BOOL)loadNibFile:(NSString *)fileName
externalNameTable:(NSDictionary *)context
withZone:(NSZone *)zone;
+ (BOOL) loadNibFile: (NSString *)fileName
externalNameTable: (NSDictionary *)context
withZone: (NSZone *)zone;
+ (BOOL)loadNibNamed:(NSString *)aNibName
owner:(id)owner;
+ (BOOL) loadNibNamed: (NSString *)aNibName
owner: (id)owner;
@end
#ifndef NO_GNUSTEP
/*
* This is the class that manages objects within a nib - when a nib is
* loaded, the [-setAllOutlets] method is used to set up the objects
* and the GSNibContainer object is released.
*/
@interface GSNibContainer : NSObject
{
NSMutableDictionary *nameTable;
NSMutableDictionary *outletMap;
}
- (NSMutableDictionary*) nameTable;
- (NSMutableDictionary*) outletsFrom: (NSString*)instanceName;
- (void) setAllOutlets;
- (BOOL) setOutlet: (NSString*)outletName from: (id)source to: (id)target;
- (BOOL) setOutlet: (NSString*)outletName
fromName: (NSString*)sourceName
toName: (NSString*)targetName;
@end
#endif /* NO_GNUSTEP */
#endif // _GNUstep_H_NSNibLoading

View file

@ -3,10 +3,12 @@
Implementation of NSBundle Additions
Copyright (C) 1997 Free Software Foundation, Inc.
Copyright (C) 1997, 1999 Free Software Foundation, Inc.
Author: Simon Frankau <sgf@frankau.demon.co.uk>
Date: 1997
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: 1999
This file is part of the GNUstep GUI Library.
@ -26,7 +28,14 @@
*/
#include <gnustep/gui/config.h>
#include <Foundation/NSArchiver.h>
#include <Foundation/NSBundle.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSObjCRuntime.h>
#include <Foundation/NSString.h>
#include <AppKit/NSNibLoading.h>
@implementation NSBundle (NSBundleAdditions)
@ -36,24 +45,247 @@
return nil;
}
+ (BOOL)loadNibFile:(NSString *)fileName
externalNameTable:(NSDictionary *)context
withZone:(NSZone *)zone
+ (BOOL) loadNibFile: (NSString *)fileName
externalNameTable: (NSDictionary *)context
withZone: (NSZone *)zone
{
return NO;
NSData *data;
BOOL loaded = NO;
data = [NSData dataWithContentsOfFile: fileName];
if (data)
{
NSUnarchiver *unarchiver;
unarchiver = [[NSUnarchiver alloc] initWithData: data];
if (unarchiver)
{
id obj;
[unarchiver setObjectZone: zone];
obj = [unarchiver decodeObject];
if (obj)
{
if ([obj isKindOfClass: [GSNibContainer class]])
{
GSNibContainer *container = obj;
NSMutableDictionary *nameTable;
NSEnumerator *enumerator;
NSString *key;
nameTable = [container nameTable];
/*
* Go through the table of objects in the nib and
* retain each one (except ones that are overridden
* by values from the 'context table' and retain them
* so they will persist after the container is gone.
*/
enumerator = [nameTable keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
if ([context objectForKey: key] == nil)
{
[[nameTable objectForKey: key] retain];
}
}
/*
* Now add local context to the name table, replacing
* objects in the nib where the local version have the
* same names. Get the container to set up the
* outlets from all the objects. Finally tell the
* unarchived objects to wake up.
*/
[nameTable addEntriesFromDictionary: context];
[container setAllOutlets];
enumerator = [nameTable keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
if ([context objectForKey: key] == nil)
{
id o;
o = [nameTable objectForKey: key];
if ([o respondsToSelector: @selector(awakeFromNib)])
{
[o awakeFromNib];
}
}
}
/*
* Ok - it's all done now - the nib container will
* be released when the unarchiver is released, so
* we will just be left with the real nib contents.
*/
loaded = YES;
}
else
{
NSLog(@"Nib '%@' without container object!", fileName);
}
}
[unarchiver release];
}
[data release];
}
return loaded;
}
+ (BOOL)loadNibNamed:(NSString *)aNibName
owner:(id)owner
+ (BOOL) loadNibNamed: (NSString *)aNibName
owner: (id)owner
{
return NO;
NSDictionary *table;
NSBundle *bundle;
NSString *file;
NSString *ext;
NSString *path;
if (owner == nil || aNibName == nil)
return NO;
table = [NSDictionary dictionaryWithObject: owner forKey: @"NSOwner"];
file = [aNibName stringByDeletingPathExtension];
ext = [aNibName pathExtension];
if ([ext isEqualToString: @""])
{
ext = @".nib";
}
bundle = [self bundleForClass: [owner class]];
path = [bundle pathForResource: file ofType: ext];
if (path == nil)
return NO;
return [self loadNibFile: aNibName
externalNameTable: table
withZone: [owner zone]];
}
@end
@interface __dummy_class_in_NSBundle
@end
@implementation __dummy_class_in_NSBundle
/*
* The GSNibContainer class manages the internals os a nib file.
*/
@implementation GSNibContainer
- (void) dealloc
{
[nameTable release];
[outletMap release];
[super dealloc];
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
[super encodeWithCoder: aCoder];
[aCoder encodeObject: nameTable];
[aCoder encodeObject: outletMap];
}
- (id) init
{
if ((self = [super init]) != nil)
{
nameTable = [[NSMutableDictionary alloc] initWithCapacity: 8];
outletMap = [[NSMutableDictionary alloc] initWithCapacity: 8];
}
return self;
}
- (id) initWithCoder: (NSCoder*)aCoder
{
self = [super initWithCoder: aCoder];
[aCoder decodeValueOfObjCType: @encode(id) at: &nameTable];
[aCoder decodeValueOfObjCType: @encode(id) at: &outletMap];
return self;
}
- (NSMutableDictionary*) nameTable
{
return nameTable;
}
- (NSMutableDictionary*) outletsFrom: (NSString*)instanceName
{
return [outletMap objectForKey: instanceName];
}
- (void) setAllOutlets
{
NSString *instanceName;
NSEnumerator *instanceEnumerator;
instanceEnumerator = [outletMap keyEnumerator];
while ((instanceName = [instanceEnumerator nextObject]) != nil)
{
NSDictionary *outletMappings;
NSEnumerator *outletEnumerator;
NSString *outletName;
id source;
source = [nameTable objectForKey: instanceName];
outletMappings = [outletMap objectForKey: instanceName];
outletEnumerator = [outletMappings keyEnumerator];
while ((outletName = [outletEnumerator nextObject]) != nil)
{
id target;
target = [outletMappings objectForKey: outletName];
[self setOutlet: outletName from: source to: target];
}
}
}
- (BOOL) setOutlet: (NSString*)outletName from: (id)source to: (id)target
{
NSString *selName;
SEL sel;
selName = [NSString stringWithFormat: @"set%@:",
[outletName capitalizedString]];
sel = NSSelectorFromString(selName);
if ([source respondsToSelector: sel])
{
[source performSelector: sel withObject: target];
return YES;
}
else
{
// Set source ivar to
NSLog(@"Direct setting of ivars not yet implemented");
}
return NO;
}
- (BOOL) setOutlet: (NSString*)outletName
fromName: (NSString*)sourceName
toName: (NSString*)targetName
{
NSMutableDictionary *outletMappings;
id source;
id target;
/*
* Get the mappings for the source object (create mappings if needed)
* and set the mapping for the outlet (replaces any old mapping).
*/
outletMappings = [outletMap objectForKey: sourceName];
if (outletMappings == nil)
{
outletMappings = [NSMutableDictionary dictionaryWithCapacity: 1];
[outletMap setObject: outletMappings forKey: sourceName];
}
[outletMappings setObject: targetName forKey: outletName];
/*
* Now make the connection in the objects themselves.
*/
source = [nameTable objectForKey: sourceName];
target = [nameTable objectForKey: targetName];
return [self setOutlet: outletName from: source to: target];
}
@end