This commit is contained in:
Gregory Casamento 2025-04-11 17:49:34 -04:00 committed by GitHub
commit e015f92516
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 745 additions and 1027 deletions

View file

@ -48,6 +48,8 @@ APPKIT_EXPORT_CLASS
+ (BOOL) checkXib5: (NSData *)data;
+ (BOOL) checkStoryboard: (NSData *)data;
+ (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data;
- (void) _initCommon;

View file

@ -33,7 +33,9 @@
extern "C" {
#endif
@class NSString, NSBundle, NSMutableDictionary;
@class NSBundle;
@class NSMutableDictionary;
@class NSString;
typedef NSString *NSStoryboardName;
typedef NSString *NSStoryboardSceneIdentifier;
@ -43,7 +45,7 @@ DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id);
APPKIT_EXPORT_CLASS
@interface NSStoryboard : NSObject
{
id _transform;
NSMutableDictionary *_scenes;
}
#if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST)

View file

@ -309,7 +309,9 @@ GSDisplayServer.m \
GSHelpManagerPanel.m \
GSInfoPanel.m \
GSMemoryPanel.m \
GSScene.m \
GSSlideView.m \
GSStoryboardLoader.m \
GSTextStorage.m \
GSTrackingRect.m \
GSServicesManager.m \
@ -332,6 +334,7 @@ GSGormLoading.m \
GSIconManager.m \
GSImageMagickImageRep.m \
GSNibLoading.m \
GSScenes.m \
GSTheme.m \
GSThemeDrawing.m \
GSThemeInspector.m \
@ -346,7 +349,7 @@ GSToolTips.m \
GSToolbarView.m \
GSToolbarCustomizationPalette.m \
GSStandardWindowDecorationView.m \
GSStoryboardTransform.m \
GSStoryboardKeyedUnarchiver.m \
GSWindowDecorationView.m \
GSPrinting.m \
GSPrintOperation.m \

View file

@ -50,7 +50,7 @@
+ (float) priority
{
return 0.0;
return FLT_MAX;
}
- (BOOL) loadModelData: (NSData *)data

60
Source/GSScene.h Normal file
View file

@ -0,0 +1,60 @@
/* Interface of class GSScene
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 12-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#ifndef _GSScene_h_GNUSTEP_GUI_INCLUDE
#define _GSScene_h_GNUSTEP_GUI_INCLUDE
#import <Foundation/NSObject.h>
#import <Foundation/NSGeometry.h>
#if defined(__cplusplus)
extern "C" {
#endif
@class NSMutableArray;
@class NSString;
@interface GSScene : NSObject <NSCoding, NSCopying>
{
NSString *_sceneID;
NSMutableArray *_objects;
NSPoint _canvasLocation;
}
- (NSString *) sceneID;
- (void) setSceneID: (NSString *)sceneID;
- (NSMutableArray *) objects;
- (void) setObjects: (NSMutableArray *)objects;
- (NSPoint) canvasLocation;
- (void) setCanvasLocation: (NSPoint)point;
@end
#if defined(__cplusplus)
}
#endif
#endif /* _GSScene_h_GNUSTEP_GUI_INCLUDE */

123
Source/GSScene.m Normal file
View file

@ -0,0 +1,123 @@
/* Implementation of class GSScene
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 12-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import <Foundation/NSKeyedArchiver.h>
#import "GSScene.h"
@implementation GSScene
- (instancetype) init
{
self = [super init];
if (self != nil)
{
_sceneID = nil;
_objects = nil;
_canvasLocation = NSMakePoint(0.0, 0.0);
}
return self;
}
- (void) dealloc
{
RELEASE(_sceneID);
RELEASE(_objects);
[super dealloc];
}
- (NSString *) sceneID
{
return _sceneID;
}
- (void) setSceneID: (NSString *)sceneID
{
ASSIGN(_sceneID, sceneID);
}
- (NSMutableArray *) objects
{
return _objects;
}
- (void) setObjects: (NSMutableArray *)objects
{
ASSIGN(_objects, objects);
}
- (NSPoint) canvasLocation
{
return _canvasLocation;
}
- (void) setCanvasLocation: (NSPoint)point
{
_canvasLocation = point;
}
// NSCoding
- (instancetype) initWithCoder: (NSCoder *)coder
{
NSLog(@"Decoding GSScene");
if ([coder allowsKeyedCoding])
{
if ([coder containsValueForKey: @"NSSceneID"])
{
[self setSceneID: [coder decodeObjectForKey: @"NSSceneID"]];
}
if ([coder containsValueForKey: @"NSObjects"])
{
[self setObjects: [coder decodeObjectForKey: @"NSObjects"]];
}
if ([coder containsValueForKey: @"NSCanvasLocation"])
{
[self setCanvasLocation: [coder decodePointForKey: @"NSCanvasLocation"]];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
}
// NSCopying
- (id) copyWithZone: (NSZone *)zone
{
GSScene *scene = [[GSScene allocWithZone: zone] init];
[scene setSceneID: [self sceneID]];
[scene setObjects: [self objects]];
[scene setCanvasLocation: [self canvasLocation]];
return scene;
}
@end

50
Source/GSScenes.h Normal file
View file

@ -0,0 +1,50 @@
/* Interface of class GSScenes
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 18-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#ifndef _GSScenes_h_GNUSTEP_GUI_INCLUDE
#define _GSScenes_h_GNUSTEP_GUI_INCLUDE
#import <Foundation/NSObject.h>
#import <Foundation/NSKeyedArchiver.h>
#if defined(__cplusplus)
extern "C" {
#endif
@interface GSScenes : NSObject <NSCoding, NSCopying>
{
NSMutableArray *_scenes;
}
- (NSMutableArray *) scenes;
- (void) setScenes: (NSMutableArray *)scenes;
@end
#if defined(__cplusplus)
}
#endif
#endif /* _GSScenes_h_GNUSTEP_GUI_INCLUDE */

82
Source/GSScenes.m Normal file
View file

@ -0,0 +1,82 @@
/* Implementation of class GSScenes
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 18-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSScenes.h"
@implementation GSScenes
- (instancetype) init
{
self = [super init];
if (self != nil)
{
_scenes = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc
{
RELEASE(_scenes);
[super dealloc];
}
- (NSMutableArray *)scenes
{
return _scenes;
}
- (void) setScenes: (NSMutableArray *)scenes
{
ASSIGN(_scenes, scenes);
}
- (id) initWithCoder: (NSCoder *)coder
{
NSLog(@"GSScenes...");
if ([coder allowsKeyedCoding] == YES)
{
if ([coder containsValueForKey: @"GSScenes"])
{
[self setScenes: [coder decodeObjectForKey: @"GSScenes"]];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
}
- (id) copyWithZone: (NSZone *)zone
{
GSScenes *scenes = [[GSScenes allocWithZone: zone] init];
[scenes setScenes: [[self scenes] copyWithZone: zone]];
return scenes;
}
@end

View file

@ -0,0 +1,45 @@
/* Definition of class GSStoryboardKeyedUnarchiver
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 14-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#ifndef _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE
#define _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE
#import "GSXib5KeyedUnarchiver.h"
#if defined(__cplusplus)
extern "C" {
#endif
@interface GSStoryboardKeyedUnarchiver : GSXib5KeyedUnarchiver
{
GSXibElement *_scenes;
}
@end
#if defined(__cplusplus)
}
#endif
#endif /* _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE */

View file

@ -0,0 +1,44 @@
/* Implementation of class GSStoryboardKeyedUnarchiver
Copyright (C) 2024 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: 14-05-2024
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GNUstepGUI/GSXibElement.h"
#import "GNUstepGUI/GSNibLoading.h"
#import "GSStoryboardKeyedUnarchiver.h"
@implementation GSStoryboardKeyedUnarchiver
- (void) _initCommon
{
[super _initCommon];
_scenes = [[GSXibElement alloc] initWithType: @"array"
andAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
@"scenes", @"key",
nil]];
}
@end

253
Source/GSStoryboardLoader.m Normal file
View file

@ -0,0 +1,253 @@
/* <title>GSXibLoader</title>
<abstract>Xib (Cocoa XML) model loader</abstract>
Copyright (C) 2010, 2011 Free Software Foundation, Inc.
Written by: Fred Kiefer <FredKiefer@gmx.de>
Created: March 2010
This file is part of the GNUstep Base 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; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110 USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSKeyedArchiver.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import "AppKit/NSApplication.h"
#import "AppKit/NSMenu.h"
#import "AppKit/NSNib.h"
#import "GNUstepGUI/GSModelLoaderFactory.h"
#import "GNUstepGUI/GSNibLoading.h"
#import "GNUstepGUI/GSXibLoading.h"
#import "GNUstepGUI/GSXibKeyedUnarchiver.h"
#import <float.h>
@interface NSApplication (StorybardCompatibility)
- (void) _setMainMenu: (NSMenu*)aMenu;
@end
@interface NSMenu (StoryboardCompatibility)
- (BOOL) _isMainMenu;
@end
@implementation NSMenu (StoryboardCompatibility)
- (BOOL) _isMainMenu
{
if (_name)
return [_name isEqualToString:@"_NSMainMenu"];
return NO;
}
@end
@interface GSStoryboardLoader: GSModelLoader
{
}
@end
@implementation GSStoryboardLoader
+ (BOOL) canReadData: (NSData *)theData
{
char *header = calloc(1024, sizeof(char));
if (header != NULL)
{
[theData getBytes: header
length: 1024];
NSString *hdr = [[NSString alloc] initWithBytes: header
length: 1024
encoding: NSUTF8StringEncoding];
AUTORELEASE(hdr);
if ([hdr containsString: @"Cocoa.Storyboard.XIB"])
{
free(header);
return YES;
}
free(header);
}
return NO;
}
+ (NSString*) type
{
return @"storyboard";
}
+ (float) priority
{
return 5.0;
}
- (void) awake: (NSArray *)rootObjects
withContext: (NSDictionary *)context
{
NSMutableArray *topLevelObjects = [context objectForKey: NSNibTopLevelObjects];
id owner = [context objectForKey: NSNibOwner];
NSEnumerator *en;
id obj;
NSUInteger index = 0;
if ([rootObjects count] == 0)
{
NSWarnMLog(@"No root objects in XIB!");
return;
}
NSDebugLLog(@"XIB", @"First object %@", [rootObjects objectAtIndex: 0]);
NSDebugLLog(@"XIB", @"Second object %@", [rootObjects objectAtIndex: 1]);
NSDebugLLog(@"XIB", @"Third object %@", [rootObjects objectAtIndex: 2]);
// Use the owner as first root object
[(NSCustomObject*)[rootObjects objectAtIndex: 0] setRealObject: owner];
en = [rootObjects objectEnumerator];
while ((obj = [en nextObject]) != nil)
{
index++;
if ([obj respondsToSelector: @selector(nibInstantiate)])
{
obj = [obj nibInstantiate];
}
// IGNORE file's owner, first responder and NSApplication instances...
if ((obj != nil) && (index > 3))
{
[topLevelObjects addObject: obj];
// All top level objects must be released by the caller to avoid
// leaking, unless they are going to be released by other nib
// objects on behalf of the owner.
RETAIN(obj);
}
if (([obj isKindOfClass: [NSMenu class]]) &&
([obj _isMainMenu]))
{
// add the menu...
[NSApp _setMainMenu: obj];
}
}
}
- (void) awake: (NSArray *)rootObjects
inContainer: (id)objects
withContext: (NSDictionary *)context
{
[self awake: rootObjects withContext: context];
// Load connections and awaken objects
if ([objects respondsToSelector: @selector(nibInstantiate)])
{
[objects nibInstantiate];
}
}
- (BOOL) loadModelData: (NSData *)data
externalNameTable: (NSDictionary *)context
withZone: (NSZone *)zone
{
BOOL loaded = NO;
NS_DURING
{
if (data != nil)
{
NSKeyedUnarchiver *unarchiver = [GSXibKeyedUnarchiver unarchiverForReadingWithData: data];
if (unarchiver != nil)
{
NSArray *rootObjects;
IBObjectContainer *objects;
NSDebugLLog(@"XIB", @"Invoking unarchiver");
[unarchiver setObjectZone: zone];
rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"];
objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"];
// NSLog(@"root objects %@", rootObjects);
// NSLog(@"objects %@", objects);
/*
[self awake: rootObjects
inContainer: objects
withContext: context];
*/
loaded = YES;
}
else
{
NSLog(@"Could not instantiate Xib unarchiver/Unable to parse Storyboard.");
}
}
else
{
NSLog(@"Data passed to Storyboard loading method is nil.");
}
}
NS_HANDLER
{
NSLog(@"Exception occurred while loading model: %@",[localException reason]);
}
NS_ENDHANDLER
if (loaded == NO)
{
NSLog(@"Failed to load Storyboard\n");
}
return loaded;
}
- (NSData*) dataForFile: (NSString*)fileName
{
NSFileManager *mgr = [NSFileManager defaultManager];
BOOL isDir = NO;
NSDebugLLog(@"XIB", @"Loading Storyboard `%@'...\n", fileName);
if ([mgr fileExistsAtPath: fileName isDirectory: &isDir])
{
if (isDir == NO)
{
return [NSData dataWithContentsOfFile: fileName];
}
else
{
NSLog(@"Storyboard file specified %@, is directory.", fileName);
}
}
else
{
NSLog(@"Storyboard file specified %@, could not be found.", fileName);
}
return nil;
}
@end

View file

@ -1,121 +0,0 @@
/* Interface of class GSStoryboardTransform
Copyright (C) 2020 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Sat 04 Jul 2020 03:48:15 PM EDT
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#ifndef _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE
#define _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE
#import <Foundation/NSObject.h>
@class NSString;
@class NSMutableDictionary;
@class NSDictionary;
@class NSData;
@class NSMapTable;
@class NSXMLDocument;
#if defined(__cplusplus)
extern "C" {
#endif
@interface GSStoryboardTransform : NSObject
{
NSMutableDictionary *_scenesMap;
NSMutableDictionary *_controllerMap;
NSMutableDictionary *_identifierToSegueMap;
NSString *_initialViewControllerId;
NSString *_applicationSceneId;
}
- (instancetype) initWithData: (NSData *)data;
- (NSString *) initialViewControllerId;
- (NSString *) applicationSceneId;
- (NSData *) dataForIdentifier: (NSString *)identifier;
- (NSMapTable *) segueMapForIdentifier: (NSString *)identifier;
- (void) processStoryboard: (NSXMLDocument *)storyboardXml;
- (void) processSegues: (NSXMLDocument *)xml
forControllerId: (NSString *)identifier;
@end
// Private classes used when parsing the XIB generated by the transformer...
@interface NSStoryboardSeguePerformAction : NSObject <NSCoding, NSCopying>
{
id _target;
SEL _action;
id _sender;
NSString *_identifier;
NSString *_kind;
id _popoverAnchorView;
NSStoryboardSegue *_storyboardSegue;
NSStoryboard *_storyboard;
}
- (id) target;
- (void) setTarget: (id)target;
- (NSString *) selector;
- (void) setSelector: (NSString *)s;
- (SEL) action;
- (void) setAction: (SEL)action;
- (id) sender;
- (void) setSender: (id)sender;
- (NSString *) identifier;
- (void) setIdentifier: (NSString *)identifier;
- (NSString *) kind;
- (void) setKind: (NSString *)kind;
- (void) setPopoverAnchorView: (id)view;
- (id) popoverAnchorView;
- (NSStoryboard *) storyboard;
- (void) setStoryboard: (NSStoryboard *)storyboard;
- (NSStoryboardSegue *) storyboardSegue;
- (void) setStoryboardSegue: (NSStoryboardSegue *)ss;
- (IBAction) doAction: (id)sender;
@end
@interface NSControllerPlaceholder : NSObject <NSCoding, NSCopying>
{
NSString *_storyboardName;
}
- (NSString *) storyboardName;
- (void) setStoryboardName: (NSString *)name;
- (id) instantiate;
@end
#if defined(__cplusplus)
}
#endif
#endif /* _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE */

View file

@ -1,888 +0,0 @@
/* Implementation of class GSStoryboardTransform
Copyright (C) 2020 Free Software Foundation, Inc.
By: Gregory John Casamento
Date: Sat 04 Jul 2020 03:48:15 PM EDT
This file is part of the GNUstep 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.1 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; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSMapTable.h>
#import <Foundation/NSXMLDocument.h>
#import <Foundation/NSXMLNode.h>
#import <Foundation/NSXMLElement.h>
#import <Foundation/NSUUID.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSKeyedArchiver.h>
#import <Foundation/NSException.h>
#import "AppKit/NSSeguePerforming.h"
#import "AppKit/NSStoryboard.h"
#import "AppKit/NSStoryboardSegue.h"
#import "AppKit/NSNibDeclarations.h"
#import "AppKit/NSViewController.h"
#import "AppKit/NSWindowController.h"
#import "GSStoryboardTransform.h"
#import "GSFastEnumeration.h"
#define APPLICATION @"application"
@interface NSStoryboardSegue (__private__)
- (void) _setDestinationController: (id)controller;
- (void) _setSourceController: (id)controller;
@end
@interface NSStoryboardSegue (__StoryboardPrivate__)
// Private to this class...
- (void) _setKind: (NSString *)k;
- (NSString *) _kind;
- (void) _setRelationship: (NSString *)r;
- (NSString *) _relationship;
- (void) _setPopoverAnchorView: (id)view;
- (id) _popoverAnchorView;
- (void) _setPopoverBehavior: (NSPopoverBehavior)behavior;
- (NSPopoverBehavior) _popoverBehavior;
- (void) _setPreferredEdge: (NSRectEdge)edge;
- (NSRectEdge) _preferredEdge;
@end
// this needs to be set on segues
@implementation NSStoryboardSegue (__StoryboardPrivate__)
- (void) _setKind: (NSString *)k
{
ASSIGN(_kind, k);
}
- (NSString *) _kind
{
return _kind;
}
- (void) _setRelationship: (NSString *)r
{
ASSIGN(_relationship, r);
}
- (NSString *) _relationship
{
return _relationship;
}
- (void) _setPopoverAnchorView: (id)view
{
ASSIGN(_popoverAnchorView, view);
}
- (id) _popoverAnchorView
{
return _popoverAnchorView;
}
- (void) _setPopoverBehavior: (NSPopoverBehavior)behavior
{
_popoverBehavior = behavior;
}
- (NSPopoverBehavior) _popoverBehavior
{
return _popoverBehavior;
}
- (void) _setPreferredEdge: (NSRectEdge)edge
{
_preferredEdge = edge;
}
- (NSRectEdge) _preferredEdge
{
return _preferredEdge;
}
@end
@implementation NSStoryboardSeguePerformAction
- (id) target
{
return _target;
}
- (void) setTarget: (id)target
{
ASSIGN(_target, target);
}
- (SEL) action
{
return _action;
}
- (void) setAction: (SEL)action
{
_action = action;
}
- (NSString *) selector
{
return NSStringFromSelector(_action);
}
- (void) setSelector: (NSString *)s
{
_action = NSSelectorFromString(s);
}
- (id) sender
{
return _sender;
}
- (void) setSender: (id)sender
{
ASSIGN(_sender, sender);
}
- (NSString *) identifier
{
return _identifier;
}
- (void) setIdentifier: (NSString *)identifier
{
ASSIGN(_identifier, identifier);
}
- (NSString *) kind
{
return _kind;
}
- (void) setKind: (NSString *)kind
{
ASSIGN(_kind, kind);
}
- (void) setPopoverAnchorView: (id)view
{
ASSIGN(_popoverAnchorView, view);
}
- (id) popoverAnchorView
{
return _popoverAnchorView;
}
- (NSStoryboard *) storyboard
{
return _storyboard;
}
- (void) setStoryboard: (NSStoryboard *)storyboard
{
ASSIGN(_storyboard, storyboard);
}
- (NSStoryboardSegue *) storyboardSegue
{
return _storyboardSegue;
}
- (void) setStoryboardSegue: (NSStoryboardSegue *)ss
{
ASSIGN(_storyboardSegue, ss);
}
- (void) dealloc
{
RELEASE(_storyboard);
RELEASE(_kind);
RELEASE(_identifier);
RELEASE(_popoverAnchorView);
RELEASE(_sender);
RELEASE(_storyboardSegue);
[super dealloc];
}
- (IBAction) doAction: (id)sender
{
BOOL should = YES;
// If the instance we are testing is a controller, then the value of should is set by this method....
// if it is not, as it is possible to initiate a segue from an NSMenuItem, then we don't, but should
// remains set to YES so that the logic to replace the destination controller is still called.
if ([_sender respondsToSelector: @selector(shouldPerformSegueWithIdentifier:sender:)])
{
should = [_sender shouldPerformSegueWithIdentifier: _identifier
sender: _sender];
}
if (should)
{
id destCon = [_storyboardSegue destinationController];
if ([destCon isKindOfClass: [NSString class]])
{
// resolve the destination controller
destCon = [_storyboard instantiateControllerWithIdentifier: destCon];
[_storyboardSegue _setDestinationController: destCon]; // replace with actual controller...
}
[_storyboardSegue _setSourceController: _sender];
if (_sender != nil &&
[_sender respondsToSelector: @selector(performSegueWithIdentifier:sender:)])
{
[_sender performSegueWithIdentifier: _identifier
sender: _sender];
}
else
{
[_storyboardSegue perform];
}
}
}
- (id) copyWithZone: (NSZone *)z
{
NSStoryboardSeguePerformAction *pa = [[NSStoryboardSeguePerformAction allocWithZone: z] init];
[pa setTarget: _target];
[pa setSelector: [self selector]];
[pa setSender: _sender];
[pa setIdentifier: _identifier];
[pa setPopoverAnchorView: _popoverAnchorView];
[pa setStoryboardSegue: _storyboardSegue];
[pa setStoryboard: _storyboard];
return pa;
}
- (instancetype) initWithCoder: (NSCoder *)coder
{
self = [super init];
if ([coder allowsKeyedCoding])
{
if ([coder containsValueForKey: @"NSTarget"])
{
[self setTarget: [coder decodeObjectForKey: @"NSTarget"]];
}
if ([coder containsValueForKey: @"NSSelector"])
{
[self setSelector: [coder decodeObjectForKey: @"NSSelector"]];
}
if ([coder containsValueForKey: @"NSSender"])
{
[self setSender: [coder decodeObjectForKey: @"NSSender"]];
}
if ([coder containsValueForKey: @"NSIdentifier"])
{
[self setIdentifier: [coder decodeObjectForKey: @"NSIdentifier"]];
}
if ([coder containsValueForKey: @"NSKind"])
{
[self setKind: [coder decodeObjectForKey: @"NSKind"]];
}
if ([coder containsValueForKey: @"NSPopoverAnchorView"])
{
[self setPopoverAnchorView: [coder decodeObjectForKey: @"NSPopoverAnchorView"]];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
// this is never encoded directly...
}
@end
@implementation NSControllerPlaceholder
- (NSString *) storyboardName
{
return _storyboardName;
}
- (void) setStoryboardName: (NSString *)name
{
ASSIGNCOPY(_storyboardName, name);
}
- (id) copyWithZone: (NSZone *)z
{
NSControllerPlaceholder *c = [[NSControllerPlaceholder allocWithZone: z] init];
[c setStoryboardName: _storyboardName];
return c;
}
- (instancetype) initWithCoder: (NSCoder *)coder
{
self = [super init];
if ([coder allowsKeyedCoding])
{
if ([coder containsValueForKey: @"NSStoryboardName"])
{
[self setStoryboardName: [coder decodeObjectForKey: @"NSStoryboardName"]];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
// this is never encoded directly...
}
- (id) instantiate
{
NSStoryboard *sb = [NSStoryboard storyboardWithName: _storyboardName
bundle: [NSBundle mainBundle]];
return [sb instantiateInitialController];
}
@end
@implementation GSStoryboardTransform
- (instancetype) initWithData: (NSData *)data
{
self = [super init];
if (self != nil)
{
NSXMLDocument *xml = [[NSXMLDocument alloc] initWithData: data
options: 0
error: NULL];
_scenesMap = [[NSMutableDictionary alloc] initWithCapacity: 10];
_controllerMap = [[NSMutableDictionary alloc] initWithCapacity: 10];
_identifierToSegueMap = [[NSMutableDictionary alloc] initWithCapacity: 10];
[self processStoryboard: xml];
RELEASE(xml);
}
return self;
}
- (void) dealloc
{
RELEASE(_initialViewControllerId);
RELEASE(_applicationSceneId);
RELEASE(_scenesMap);
RELEASE(_controllerMap);
RELEASE(_identifierToSegueMap);
[super dealloc];
}
- (NSString *) initialViewControllerId
{
return _initialViewControllerId;
}
- (NSString *) applicationSceneId
{
return _applicationSceneId;
}
- (NSMapTable *) segueMapForIdentifier: (NSString *)identifier
{
return [_identifierToSegueMap objectForKey: identifier];
}
- (NSXMLElement *) createCustomObjectWithId: (NSString *)ident
userLabel: (NSString *)userLabel
customClass: (NSString *)className
{
NSXMLElement *customObject =
[[NSXMLElement alloc] initWithName: @"customObject"];
NSXMLNode *idValue =
[NSXMLNode attributeWithName: @"id"
stringValue: ident];
NSXMLNode *usrLabel =
[NSXMLNode attributeWithName: @"userLabel"
stringValue: userLabel];
NSXMLNode *customCls =
[NSXMLNode attributeWithName: @"customClass"
stringValue: className];
[customObject addAttribute: idValue];
[customObject addAttribute: usrLabel];
[customObject addAttribute: customCls];
AUTORELEASE(customObject);
return customObject;
}
- (NSData *) dataForIdentifier: (NSString *)identifier
{
NSString *sceneId = [_controllerMap objectForKey: identifier];
NSXMLDocument *xml = [_scenesMap objectForKey: sceneId];
return [xml XMLData];
}
- (void) addStandardObjects: (NSXMLElement *)objects
classString: (NSString *) customClassString
connections: (NSXMLNode *)appCons
firstResponderId: (NSString *)firstResponderId
{
NSXMLElement *customObject = nil;
customObject =
[self createCustomObjectWithId: @"-3"
userLabel: @"Application"
customClass: @"NSObject"];
[objects insertChild: customObject
atIndex: 0];
customObject =
[self createCustomObjectWithId: firstResponderId
userLabel: @"First Responder"
customClass: @"FirstResponder"];
[objects insertChild: customObject
atIndex: 0];
customObject =
[self createCustomObjectWithId: @"-2"
userLabel: @"File's Owner"
customClass: customClassString];
if (appCons != nil)
{
[customObject addChild: appCons];
}
[objects insertChild: customObject
atIndex: 0];
}
- (void) processChild: (NSXMLElement *)objects
withDoc: (NSXMLElement *)doc
withAppNode: (NSXMLNode *)appNode
sceneId: (NSString *)sceneId
firstResponderId: (NSString *)firstResponderId
{
NSString *customClassString = nil;
NSXMLNode *appCons = nil;
if (appNode != nil)
{
NSArray *appConsArr = [appNode nodesForXPath: @"connections" error: NULL];
appCons = [appConsArr objectAtIndex: 0];
if (appCons != nil)
{
[appCons detach];
}
// Assign application scene...
ASSIGN(_applicationSceneId, sceneId);
[_controllerMap setObject: _applicationSceneId
forKey: APPLICATION];
// Move all application children to objects...
NSArray *appChildren = [appNode children];
FOR_IN(NSXMLElement*, ae, appChildren)
[ae detach];
[objects addChild: ae];
END_FOR_IN(appChildren);
// Remove the appNode
[appNode detach];
// create a customObject entry for NSApplication reference...
NSXMLNode *appCustomClass = [(NSXMLElement *)appNode
attributeForName: @"customClass"];
customClassString = ([appCustomClass stringValue] == nil) ?
@"NSApplication" : [appCustomClass stringValue];
}
[self addStandardObjects: objects
classString: customClassString
connections: appCons
firstResponderId: firstResponderId];
// Add it to the document
[objects detach];
[doc addChild: objects];
}
- (NSArray *) subclassesOfClass: (Class)clz
{
NSMutableArray *subclasses = [GSObjCAllSubclassesOfClass(clz) mutableCopy];
NSMutableArray *result = [NSMutableArray arrayWithCapacity: [subclasses count]];
[subclasses insertObject: clz atIndex: 0];
FOR_IN(Class, cls, subclasses)
{
NSString *className = NSStringFromClass(cls);
NSString *classNameNoNamespace = [className substringFromIndex: 2];
NSString *xmlClassName = [NSString stringWithFormat: @"%@%@",
[[classNameNoNamespace substringToIndex: 1] lowercaseString],
[classNameNoNamespace substringFromIndex: 1]];
NSString *lowerCaseName = [xmlClassName lowercaseString];
[result addObject: xmlClassName];
[result addObject: lowerCaseName];
}
END_FOR_IN(subclasses);
return result;
}
- (NSArray *) findSubclassesOf: (Class)clz
inDocument: (NSXMLDocument *)document
{
NSArray *result = nil;
NSArray *xmlClassNames = [self subclassesOfClass: clz];
FOR_IN(NSString*, xmlClassName, xmlClassNames)
{
NSString *xpath = [NSString stringWithFormat: @"//%@",xmlClassName];
result = [document nodesForXPath: xpath error: NULL];
if ([result count] > 0)
{
break;
}
}
END_FOR_IN(xmlClassNames);
return result;
}
- (NSString *) controllerIdWithDocument: (NSXMLDocument *)document
{
NSString *controllerId = nil;
NSArray *windowControllers = [self findSubclassesOf: [NSWindowController class]
inDocument: document];
NSArray *viewControllers = [self findSubclassesOf: [NSViewController class]
inDocument: document];
NSArray *controllerPlaceholders = [document nodesForXPath: @"//controllerPlaceholder"
error: NULL];
if ([windowControllers count] > 0)
{
NSXMLElement *ce = [windowControllers objectAtIndex: 0];
NSXMLNode *attr = [ce attributeForName: @"id"];
controllerId = [attr stringValue];
FOR_IN(NSXMLElement*, o, windowControllers)
{
NSXMLElement *objects = (NSXMLElement *)[o parent];
NSArray *windows = [o nodesForXPath: @"//window" error: NULL];
FOR_IN(NSXMLNode*, w, windows)
{
[w detach];
[objects addChild: w];
}
END_FOR_IN(windows);
}
END_FOR_IN(windowControllers);
}
if ([viewControllers count] > 0)
{
NSXMLElement *ce = [viewControllers objectAtIndex: 0];
NSXMLNode *attr = [ce attributeForName: @"id"];
controllerId = [attr stringValue];
}
if ([controllerPlaceholders count] > 0)
{
NSXMLElement *ce = [controllerPlaceholders objectAtIndex: 0];
NSXMLNode *attr = [ce attributeForName: @"id"];
controllerId = [attr stringValue];
}
return controllerId;
}
- (void) processStoryboard: (NSXMLDocument *)xml
{
NSArray *docNodes = [xml nodesForXPath: @"document" error: NULL];
if ([docNodes count] > 0)
{
NSXMLElement *docNode = [docNodes objectAtIndex: 0];
NSArray *array = [docNode nodesForXPath: @"//scene" error: NULL];
NSArray *firstResponderIdNodes = [docNode nodesForXPath: @"//objects/customObject[@sceneMemberID =\"firstResponder\"]/@id"
error: NULL];
NSString *firstResponderId = @"-1";
if([firstResponderIdNodes count] > 0)
{
firstResponderId = [[firstResponderIdNodes objectAtIndex: 0] stringValue];
}
// Set initial view controller...
ASSIGN(_initialViewControllerId, [[docNode attributeForName: @"initialViewController"] stringValue]);
FOR_IN(NSXMLElement*, e, array)
{
NSXMLElement *doc = [[NSXMLElement alloc] initWithName: @"document"];
NSArray *children = [e children];
NSXMLDocument *document = nil;
NSString *sceneId = [[e attributeForName: @"sceneID"] stringValue];
NSString *controllerId = nil;
// Move children...
FOR_IN(NSXMLElement*, child, children)
{
if ([[child name] isEqualToString: @"point"] == YES)
continue; // go on if it's a point element, we don't use that in the app...
NSArray *subnodes = [child nodesForXPath: @"//application" error: NULL];
NSXMLNode *appNode = [subnodes objectAtIndex: 0];
[self processChild: child
withDoc: doc
withAppNode: appNode
sceneId: sceneId
firstResponderId: firstResponderId];
// fix other custom objects
document = [[NSXMLDocument alloc] initWithRootElement: doc];
controllerId = [self controllerIdWithDocument: document];
controllerId = (controllerId != nil) ? controllerId : APPLICATION;
RELEASE(doc);
// Create document...
[_scenesMap setObject: document
forKey: sceneId];
// Map controllerId's to scenes...
if (controllerId != nil)
{
[_controllerMap setObject: sceneId
forKey: controllerId];
[self processSegues: document
forControllerId: controllerId];
}
RELEASE(document);
}
END_FOR_IN(children);
}
END_FOR_IN(array);
}
else
{
[NSException raise: NSInternalInconsistencyException
format: @"No document element found in storyboard file"];
}
}
- (BOOL) isProcessedDocument: (NSXMLDocument *)xmlIn
{
NSArray *docArray = [xmlIn nodesForXPath: @"document" error: NULL];
if ([docArray count] > 0)
{
NSXMLElement *docElem = (NSXMLElement *)[docArray objectAtIndex: 0];
NSXMLNode *a = [docElem attributeForName: @"processed"];
NSString *value = [a stringValue];
if (value != nil)
{
return YES;
}
else
{
NSXMLNode *new_attr = [NSXMLNode attributeWithName: @"processed"
stringValue: @"true"];
[docElem addAttribute: new_attr];
}
}
return NO;
}
- (NSXMLElement *) createStoryboardProxyElementWithSelector: (NSString *)selector
target: (NSString *)dst
segueIdentifier: (NSString *)ident
sender: (NSString *)src
kind: (NSString *)kind
anchorView: (NSString *)anchorView
{
NSXMLElement *sbproxy = [NSXMLElement elementWithName: @"storyboardSeguePerformAction"];
NSXMLNode *pselector
= [NSXMLNode attributeWithName: @"selector"
stringValue: selector];
NSXMLNode *ptarget
= [NSXMLNode attributeWithName: @"target"
stringValue: dst];
NSString *pident_value = [[NSUUID UUID] UUIDString];
NSXMLNode *pident
= [NSXMLNode attributeWithName: @"id"
stringValue: pident_value];
NSXMLNode *psegueIdent
= [NSXMLNode attributeWithName: @"identifier"
stringValue: ident];
NSXMLNode *psender
= [NSXMLNode attributeWithName: @"sender"
stringValue: src];
NSXMLNode *pkind
= [NSXMLNode attributeWithName: @"kind"
stringValue: kind];
NSXMLNode *panchorview
= [NSXMLNode attributeWithName: @"popoverAnchorView"
stringValue: anchorView];
[sbproxy addAttribute: pselector];
[sbproxy addAttribute: ptarget];
[sbproxy addAttribute: pident];
[sbproxy addAttribute: psegueIdent];
[sbproxy addAttribute: psender];
[sbproxy addAttribute: pkind];
[sbproxy addAttribute: panchorview];
return sbproxy;
}
- (NSMapTable *) processConnections: (NSArray *)connectionsArray
withObjects: (NSXMLElement *)objects
controllerId: (NSString *)src
{
NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable];
FOR_IN (NSXMLElement*, connections, connectionsArray)
{
NSArray *children = [connections children]; // there should be only one per set.
FOR_IN (NSXMLElement*, obj, children)
if ([[obj name] isEqualToString: @"segue"])
{
// get the information from the segue.
id connections_parent = [[obj parent] parent];
id segue_parent = connections; // [obj parent];
NSString *connections_parent_name = [connections_parent name];
NSXMLNode *attr = [obj attributeForName: @"destination"];
NSString *dst = [attr stringValue];
attr = [obj attributeForName: @"kind"];
NSString *kind = [attr stringValue];
attr = [obj attributeForName: @"relationship"];
NSString *rel = [attr stringValue];
attr = [obj attributeForName: @"id"];
NSString *uid = [attr stringValue];
attr = [obj attributeForName: @"identifier"];
NSString *ident = [attr stringValue];
if (ident == nil)
{
ident = [[NSUUID UUID] UUIDString];
}
attr = [obj attributeForName: @"popoverAnchorView"];
NSString *av = [attr stringValue];
attr = [obj attributeForName: @"popoverBehavior"];
NSString *pb = [attr stringValue];
NSPopoverBehavior behavior = NSPopoverBehaviorApplicationDefined;
if ([pb isEqualToString: @"a"])
{
behavior = NSPopoverBehaviorApplicationDefined;
}
else if ([pb isEqualToString: @"t"])
{
behavior = NSPopoverBehaviorTransient;
}
else if ([pb isEqualToString: @"s"])
{
behavior = NSPopoverBehaviorSemitransient;
}
attr = [obj attributeForName: @"preferredEdge"];
NSString *pe = [attr stringValue];
NSRectEdge edge = NSMinXEdge;
if ([pe isEqualToString: @"maxY"])
{
edge = NSMaxYEdge;
}
else if ([pe isEqualToString: @"minY"])
{
edge = NSMinYEdge;
}
else if ([pe isEqualToString: @"maxX"])
{
edge = NSMaxXEdge;
}
else if ([pe isEqualToString: @"minX"])
{
edge = NSMinXEdge;
}
[obj detach]; // segue can't be in the archive since it doesn't conform to NSCoding
// Create proxy object to invoke methods on the window controller
NSXMLElement *sbproxy = [self createStoryboardProxyElementWithSelector: @"doAction:"
target: dst
segueIdentifier: ident
sender: src
kind: kind
anchorView: av];
NSUInteger count = [[objects children] count];
[objects insertChild: sbproxy
atIndex: count - 1];
// add action to parent ONLY if it is NOT a controller..
if (![[self subclassesOfClass: [NSWindowController class]] containsObject: connections_parent_name] &&
![[self subclassesOfClass: [NSViewController class]] containsObject: connections_parent_name])
{
// Create action...
NSXMLElement *action = [NSXMLElement elementWithName: @"action"];
NSXMLNode *selector
= [NSXMLNode attributeWithName: @"selector"
stringValue: @"doAction:"];
NSXMLNode *target
= [NSXMLNode attributeWithName: @"target"
stringValue: [[sbproxy attributeForName: @"id"] stringValue]];
NSXMLNode *controller_ident
= [NSXMLNode attributeWithName: @"id"
stringValue: uid];
[action addAttribute: selector];
[action addAttribute: target];
[action addAttribute: controller_ident];
[segue_parent addChild: action];
}
// Create the segue...
NSStoryboardSegue *ss = [[NSStoryboardSegue alloc] initWithIdentifier: ident
source: src
destination: dst];
[ss _setKind: kind];
[ss _setRelationship: rel];
[ss _setPopoverBehavior: behavior];
[ss _setPreferredEdge: edge];
// Add to maptable...
[mapTable setObject: ss
forKey: ident];
} // only process segue objects...
END_FOR_IN(children);
} // iterate over connection objs
END_FOR_IN(connectionsArray);
return mapTable;
}
- (void) processSegues: (NSXMLDocument *)xml
forControllerId: (NSString *)identifier
{
BOOL processed = [self isProcessedDocument: xml];
if (!processed)
{
NSArray *array = [xml nodesForXPath: @"//objects[1]"
error: NULL];
NSXMLElement *objects = [array objectAtIndex: 0]; // get the "objects" section
NSArray *connectionsArray = [xml nodesForXPath: @"//connections"
error: NULL];
NSMapTable *mapTable = [self processConnections: connectionsArray
withObjects: objects
controllerId: identifier];
[_identifierToSegueMap setObject: mapTable
forKey: identifier];
}
}
@end

View file

@ -68,7 +68,10 @@
#import "AppKit/NSTabView.h"
#import "AppKit/NSToolbarItem.h"
#import "AppKit/NSView.h"
#import "GSCodingFlags.h"
#import "GSScenes.h"
#import "GSScene.h"
#define DEBUG_XIB5 0
@ -229,6 +232,8 @@ static NSArray *XmlBoolDefaultYes = nil;
@"NSStackViewContainer", @"beginningViews",
@"NSStackViewContainer", @"middleViews",
@"NSStackViewContainer", @"endViews",
// @"GSScene", @"scene",
// @"NSMutableArray", @"scenes",
nil];
RETAIN(XmlTagToObjectClassMap);
@ -238,7 +243,7 @@ static NSArray *XmlBoolDefaultYes = nil;
XmlTagsToSkip = [NSArray arrayWithObject: @"dependencies"];
RETAIN(XmlTagsToSkip);
ClassNamePrefixes = [NSArray arrayWithObjects: @"NS", @"IB", nil];
ClassNamePrefixes = [NSArray arrayWithObjects: @"NS", @"IB", @"GS", nil];
RETAIN(ClassNamePrefixes);
XmlReferenceAttributes = [NSArray arrayWithObjects: @"headerView", @"initialItem",

View file

@ -35,10 +35,13 @@
*/
#import <Foundation/NSXMLDocument.h>
#import "GNUstepGUI/GSXibKeyedUnarchiver.h"
#import "GNUstepGUI/GSXibElement.h"
#import "GNUstepGUI/GSNibLoading.h"
#import "GSXib5KeyedUnarchiver.h"
#import "GSStoryboardKeyedUnarchiver.h"
@implementation GSXibKeyedUnarchiver
@ -49,11 +52,8 @@
NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data
options: 0
error: NULL];
if (document == nil)
{
return NO;
}
else
if (document)
{
// Test to see if this is an Xcode 5 XIB...
NSArray *documentNodes = [document nodesForXPath: @"/document" error: NULL];
@ -62,17 +62,47 @@
// specific to check here...
return [documentNodes count] != 0;
}
return NO;
#else
// We now default to checking XIB 5 versions
return YES;
#endif
}
+ (BOOL) checkStoryboard: (NSData *)data
{
#if GNUSTEP_BASE_HAVE_LIBXML
// Ensure we have a storyboard...first see if we can parse the XML...
NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data
options: 0
error: NULL];
if (document)
{
// Test to see if this is an Xcode 5 XIB...
NSArray *nodes = [document nodesForXPath: @"/scenes" error: NULL];
// Need at LEAST ONE scene node...we should find something a bit more
// specific to check here...
return [nodes count] != 0;
}
#endif
// We now default to checking XIB 5 versions
return NO;
}
+ (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data
{
NSKeyedUnarchiver *unarchiver = nil;
if ([self checkXib5: data])
if ([self checkStoryboard: data])
{
unarchiver = [[GSStoryboardKeyedUnarchiver alloc] initForReadingWithData: data];
}
else if ([self checkXib5: data])
{
unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data];
}
@ -80,6 +110,7 @@
{
unarchiver = [[GSXibKeyedUnarchiver alloc] initForReadingWithData: data];
}
return AUTORELEASE(unarchiver);
}

View file

@ -35,6 +35,7 @@
#import "AppKit/NSApplication.h"
#import "AppKit/NSNib.h"
#import "AppKit/NSNibLoading.h"
#import "AppKit/NSStoryboard.h"
#import "AppKit/NSWindowController.h"
#import "AppKit/NSViewController.h"
@ -42,7 +43,7 @@
#import "AppKit/NSNibDeclarations.h"
#import "GNUstepGUI/GSModelLoaderFactory.h"
#import "GSStoryboardTransform.h"
#import "GNUstepGUI/GSXibKeyedUnarchiver.h"
#import "GSFastEnumeration.h"
static NSStoryboard *__mainStoryboard = nil;
@ -110,10 +111,32 @@ static NSStoryboard *__mainStoryboard = nil;
self = [super init];
if (self != nil)
{
NSString *path = [bundle pathForResource: name
ofType: @"storyboard"];
NSData *data = [NSData dataWithContentsOfFile: path];
_transform = [[GSStoryboardTransform alloc] initWithData: data];
BOOL success = NO;
success = [bundle loadNibFile: name
externalNameTable: nil
withZone: NSDefaultMallocZone()];
if (success)
{
}
/*
if (unarchiver != nil)
{
NSArray *rootObjects;
IBObjectContainer *objects;
NSDebugLLog(@"XIB", @"Invoking unarchiver");
[unarchiver setObjectZone: zone];
rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"];
objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"];
NSDebugLLog(@"XIB", @"rootObjects %@", rootObjects);
[self awake: rootObjects
inContainer: objects
withContext: context];
loaded = YES;
}
*/
}
return self;
}
@ -142,7 +165,7 @@ static NSStoryboard *__mainStoryboard = nil;
// Instance methods...
- (void) dealloc
{
RELEASE(_transform);
RELEASE(_scenes);
[super dealloc];
}
@ -158,7 +181,7 @@ static NSStoryboard *__mainStoryboard = nil;
- (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block
{
return [self instantiateControllerWithIdentifier: [_transform initialViewControllerId]
return [self instantiateControllerWithIdentifier: @"" // [_transform initialViewControllerId]
creator: block];
}
@ -172,6 +195,8 @@ static NSStoryboard *__mainStoryboard = nil;
creator: (NSStoryboardControllerCreator)block
{
id result = nil;
/*
NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5];
NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects,
NSNibTopLevelObjects,
@ -260,6 +285,8 @@ static NSStoryboard *__mainStoryboard = nil;
{
CALL_BLOCK(block, self);
}
*/
return result;
}
@end