mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 03:11:18 +00:00
Refactor transform to a different class
This commit is contained in:
parent
a0afee8fb1
commit
59220e6beb
5 changed files with 886 additions and 696 deletions
|
@ -42,11 +42,7 @@ DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id);
|
|||
|
||||
@interface NSStoryboard : NSObject
|
||||
{
|
||||
NSMutableDictionary *_scenesMap;
|
||||
NSMutableDictionary *_controllerMap;
|
||||
NSMutableDictionary *_documentsMap;
|
||||
NSString *_initialViewControllerId;
|
||||
NSString *_applicationSceneId;
|
||||
id _transform;
|
||||
}
|
||||
|
||||
+ (NSStoryboard *) mainStoryboard;
|
||||
|
|
|
@ -323,6 +323,7 @@ GSToolTips.m \
|
|||
GSToolbarView.m \
|
||||
GSToolbarCustomizationPalette.m \
|
||||
GSStandardWindowDecorationView.m \
|
||||
GSStoryboardTransform.m \
|
||||
GSWindowDecorationView.m \
|
||||
GSPrinting.m \
|
||||
GSPrintOperation.m \
|
||||
|
|
118
Source/GSStoryboardTransform.h
Normal file
118
Source/GSStoryboardTransform.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* 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 *_documentsMap;
|
||||
NSMutableDictionary *_identifierToSegueMap;
|
||||
NSString *_initialViewControllerId;
|
||||
NSString *_applicationSceneId;
|
||||
}
|
||||
|
||||
- (instancetype) initWithData: (NSData *)data;
|
||||
|
||||
- (NSDictionary *) scenesMap;
|
||||
- (NSDictionary *) controllerMap;
|
||||
- (NSString *) initialViewControllerId;
|
||||
- (NSString *) applicationSceneId;
|
||||
- (NSDictionary *) identifierToSegueMap;
|
||||
|
||||
- (NSData *) dataForIdentifier: (NSString *)identifier;
|
||||
- (NSData *) dataForSceneId: (NSString *)sceneId;
|
||||
- (NSData *) dataForApplicationScene;
|
||||
- (NSMapTable *) segueMapForIdentifier: (NSString *)identifier;
|
||||
|
||||
- (void) processSegues: (NSXMLDocument *)xmlIn
|
||||
forId: (NSString *)identifier;
|
||||
- (void) processStoryboard: (NSXMLDocument *)storyboardXml;
|
||||
|
||||
@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) 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;
|
||||
|
||||
- (IBAction) doAction: (id)sender;
|
||||
@end
|
||||
|
||||
@interface NSControllerPlaceholder : NSObject <NSCoding, NSCopying> // , NSSeguePerforming>
|
||||
{
|
||||
NSString *_storyboardName;
|
||||
}
|
||||
|
||||
- (NSString *) storyboardName;
|
||||
- (void) setStoryboardName: (NSString *)name;
|
||||
|
||||
- (id) instantiate;
|
||||
|
||||
@end
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE */
|
||||
|
746
Source/GSStoryboardTransform.m
Normal file
746
Source/GSStoryboardTransform.m
Normal file
|
@ -0,0 +1,746 @@
|
|||
/* 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 "AppKit/NSSeguePerforming.h"
|
||||
#import "AppKit/NSStoryboard.h"
|
||||
#import "AppKit/NSStoryboardSegue.h"
|
||||
|
||||
#import "GSStoryboardTransform.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
|
||||
@interface NSStoryboardSegue (__StoryboardPrivate__)
|
||||
- (void) _setKind: (NSString *)k;
|
||||
- (void) _setRelationship: (NSString *)r;
|
||||
- (NSString *) _kind;
|
||||
- (NSString *) _relationship;
|
||||
@end
|
||||
|
||||
// this needs to be set on segues
|
||||
@implementation NSStoryboardSegue (__StoryboardPrivate__)
|
||||
- (void) _setKind: (NSString *)k
|
||||
{
|
||||
ASSIGN(_kind, k);
|
||||
}
|
||||
|
||||
- (void) _setRelationship: (NSString *)r
|
||||
{
|
||||
ASSIGN(_relationship, r);
|
||||
}
|
||||
|
||||
- (NSString *) _kind
|
||||
{
|
||||
return _kind;
|
||||
}
|
||||
|
||||
- (NSString *) _relationship
|
||||
{
|
||||
return _relationship;
|
||||
}
|
||||
@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);
|
||||
}
|
||||
|
||||
- (id) nibInstantiate
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IBAction) doAction: (id)sender
|
||||
{
|
||||
[_sender performSegueWithIdentifier: _identifier
|
||||
sender: _sender];
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *)z
|
||||
{
|
||||
NSStoryboardSeguePerformAction *pa = [[NSStoryboardSeguePerformAction allocWithZone: z] init];
|
||||
[pa setTarget: _target];
|
||||
[pa setSelector: [self selector]];
|
||||
[pa setSender: _sender];
|
||||
[pa setIdentifier: _identifier];
|
||||
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"]];
|
||||
}
|
||||
}
|
||||
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];
|
||||
_documentsMap = [[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(_documentsMap);
|
||||
RELEASE(_identifierToSegueMap);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *) initialViewControllerId
|
||||
{
|
||||
return _initialViewControllerId;
|
||||
}
|
||||
|
||||
- (NSString *) applicationSceneId
|
||||
{
|
||||
return _applicationSceneId;
|
||||
}
|
||||
|
||||
- (NSDictionary *) scenesMap
|
||||
{
|
||||
return _scenesMap;
|
||||
}
|
||||
|
||||
- (NSDictionary *) controllerMap
|
||||
{
|
||||
return _controllerMap;
|
||||
}
|
||||
|
||||
- (NSDictionary *) documentsMap
|
||||
{
|
||||
return _documentsMap;
|
||||
}
|
||||
|
||||
- (NSDictionary *) identifierToSegueMap
|
||||
{
|
||||
return _identifierToSegueMap;
|
||||
}
|
||||
|
||||
- (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];
|
||||
[self processSegues: xml
|
||||
forId: identifier];
|
||||
return [xml XMLData];
|
||||
}
|
||||
|
||||
- (NSData *) dataForSceneId: (NSString *)sceneId
|
||||
{
|
||||
NSXMLDocument *xml = [_scenesMap objectForKey: _applicationSceneId];
|
||||
NSData *xmlData = [xml XMLData];
|
||||
return xmlData;
|
||||
}
|
||||
|
||||
- (NSData *) dataForApplicationScene
|
||||
{
|
||||
return [self dataForSceneId: _applicationSceneId];
|
||||
}
|
||||
|
||||
- (void) processStoryboard: (NSXMLDocument *)storyboardXml
|
||||
{
|
||||
NSArray *docNodes = [storyboardXml nodesForXPath: @"document" error: NULL];
|
||||
|
||||
if ([docNodes count] > 0)
|
||||
{
|
||||
NSXMLElement *docNode = [docNodes objectAtIndex: 0];
|
||||
NSArray *array = [docNode nodesForXPath: @"//scene" error: NULL];
|
||||
NSString *customClassString = nil;
|
||||
|
||||
// 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];
|
||||
if (appNode != nil)
|
||||
{
|
||||
NSXMLElement *objects = (NSXMLElement *)[appNode parent];
|
||||
NSArray *appConsArr = [appNode nodesForXPath: @"connections" error: NULL];
|
||||
NSXMLNode *appCons = [appConsArr objectAtIndex: 0];
|
||||
if (appCons != nil)
|
||||
{
|
||||
[appCons detach];
|
||||
}
|
||||
|
||||
NSArray *appChildren = [appNode children];
|
||||
NSEnumerator *ace = [appChildren objectEnumerator];
|
||||
NSXMLElement *ae = nil;
|
||||
|
||||
// Assign application scene...
|
||||
ASSIGN(_applicationSceneId, sceneId);
|
||||
|
||||
// Move all application children to objects...
|
||||
while ((ae = [ace nextObject]) != nil)
|
||||
{
|
||||
[ae detach];
|
||||
[objects addChild: ae];
|
||||
}
|
||||
|
||||
// Remove the appNode
|
||||
[appNode detach];
|
||||
|
||||
// Add it to the document
|
||||
[objects detach];
|
||||
[doc addChild: objects];
|
||||
|
||||
// create a customObject entry for NSApplication reference...
|
||||
NSXMLNode *appCustomClass = (NSXMLNode *)[(NSXMLElement *)appNode
|
||||
attributeForName: @"customClass"];
|
||||
customClassString = ([appCustomClass stringValue] == nil) ?
|
||||
@"NSApplication" : [appCustomClass stringValue];
|
||||
NSXMLElement *customObject = nil;
|
||||
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-3"
|
||||
userLabel: @"Application"
|
||||
customClass: @"NSObject"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-1"
|
||||
userLabel: @"First Responder"
|
||||
customClass: @"FirstResponder"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-2"
|
||||
userLabel: @"File's Owner"
|
||||
customClass: customClassString];
|
||||
if (appCons != nil)
|
||||
{
|
||||
[customObject addChild: appCons];
|
||||
}
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSXMLElement *customObject = nil;
|
||||
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-3"
|
||||
userLabel: @"Application"
|
||||
customClass: @"NSObject"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-1"
|
||||
userLabel: @"First Responder"
|
||||
customClass: @"FirstResponder"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self createCustomObjectWithId: @"-2"
|
||||
userLabel: @"File's Owner"
|
||||
customClass: customClassString];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
|
||||
[child detach];
|
||||
[doc addChild: child];
|
||||
}
|
||||
|
||||
// Add other custom objects...
|
||||
|
||||
// fix other custom objects
|
||||
document = [[NSXMLDocument alloc] initWithRootElement: doc]; // put it into the document, so we can use Xpath.
|
||||
NSArray *windowControllers = [document nodesForXPath: @"//windowController" error: NULL];
|
||||
NSArray *viewControllers = [document nodesForXPath: @"//viewController" error: NULL];
|
||||
NSArray *controllerPlaceholders = [document nodesForXPath: @"//controllerPlaceholder" error: NULL];
|
||||
RELEASE(doc);
|
||||
|
||||
if ([windowControllers count] > 0)
|
||||
{
|
||||
NSXMLElement *ce = [windowControllers objectAtIndex: 0];
|
||||
NSXMLNode *attr = [ce attributeForName: @"id"];
|
||||
controllerId = [attr stringValue];
|
||||
|
||||
NSEnumerator *windowControllerEnum = [windowControllers objectEnumerator];
|
||||
NSXMLElement *o = nil;
|
||||
while ((o = [windowControllerEnum nextObject]) != nil)
|
||||
{
|
||||
NSXMLElement *objects = (NSXMLElement *)[o parent];
|
||||
NSArray *windows = [o nodesForXPath: @"//window" error: NULL];
|
||||
NSEnumerator *windowEn = [windows objectEnumerator];
|
||||
NSXMLNode *w = nil;
|
||||
while ((w = [windowEn nextObject]) != nil)
|
||||
{
|
||||
[w detach];
|
||||
[objects addChild: w];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
NSArray *customObjects = [document nodesForXPath: @"//objects/customObject" error: NULL];
|
||||
NSEnumerator *coen = [customObjects objectEnumerator];
|
||||
NSXMLElement *coel = nil;
|
||||
while ((coel = [coen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *attr = [coel attributeForName: @"sceneMemberID"];
|
||||
if ([[attr stringValue] isEqualToString: @"firstResponder"])
|
||||
{
|
||||
NSXMLNode *customClassAttr = [coel attributeForName: @"customClass"];
|
||||
NSXMLNode *idAttr = [coel attributeForName: @"id"];
|
||||
NSString *originalId = [idAttr stringValue];
|
||||
|
||||
[idAttr setStringValue: @"-1"]; // set to first responder id
|
||||
[customClassAttr setStringValue: @"FirstResponder"];
|
||||
|
||||
// Actions
|
||||
NSArray *cons = [document nodesForXPath: @"//action" error: NULL];
|
||||
NSEnumerator *consen = [cons objectEnumerator];
|
||||
NSXMLElement *celem = nil;
|
||||
|
||||
while ((celem = [consen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *targetAttr = [celem attributeForName: @"target"];
|
||||
NSString *val = [targetAttr stringValue];
|
||||
if ([val isEqualToString: originalId])
|
||||
{
|
||||
[targetAttr setStringValue: @"-1"];
|
||||
}
|
||||
}
|
||||
|
||||
// Outlets
|
||||
cons = [document nodesForXPath: @"//outlet" error: NULL];
|
||||
consen = [cons objectEnumerator];
|
||||
celem = nil;
|
||||
while ((celem = [consen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *attr = [celem attributeForName: @"destination"];
|
||||
NSString *val = [attr stringValue];
|
||||
if ([val isEqualToString: originalId])
|
||||
{
|
||||
[attr setStringValue: @"-1"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create document...
|
||||
[_scenesMap setObject: document
|
||||
forKey: sceneId];
|
||||
|
||||
// Map controllerId's to scenes...
|
||||
if (controllerId != nil)
|
||||
{
|
||||
[_controllerMap setObject: sceneId
|
||||
forKey: controllerId];
|
||||
}
|
||||
|
||||
RELEASE(document);
|
||||
}
|
||||
END_FOR_IN(children);
|
||||
}
|
||||
END_FOR_IN(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"No document element in storyboard file");
|
||||
}
|
||||
}
|
||||
|
||||
- (void) processSegues: (NSXMLDocument *)xmlIn
|
||||
forId: (NSString *)identifier
|
||||
{
|
||||
NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable];
|
||||
NSArray *connectionsArray = [xmlIn nodesForXPath: @"//connections"
|
||||
error: NULL];
|
||||
NSArray *array = [xmlIn nodesForXPath: @"//objects[1]"
|
||||
error: NULL];
|
||||
NSXMLElement *objects = [array objectAtIndex: 0]; // get the "objects" section
|
||||
NSString *uuidString = nil;
|
||||
NSArray *docArray = [xmlIn nodesForXPath: @"document" error: NULL];
|
||||
|
||||
if ([docArray count] > 0)
|
||||
{
|
||||
NSXMLElement *docElem = (NSXMLElement *)[docArray objectAtIndex: 0];
|
||||
NSXMLNode *a = [docElem attributeForName: @"uuid"];
|
||||
NSString *value = [a stringValue];
|
||||
if (value != nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
uuidString = [[NSUUID UUID] UUIDString];
|
||||
NSXMLNode *new_uuid_attr = [NSXMLNode attributeWithName: @"uuid"
|
||||
stringValue: uuidString];
|
||||
[docElem addAttribute: new_uuid_attr];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the controller...
|
||||
NSString *src = nil;
|
||||
NSArray *controllers = [objects nodesForXPath: @"windowController"
|
||||
error: NULL];
|
||||
if ([controllers count] > 0)
|
||||
{
|
||||
NSXMLElement *controller = (NSXMLElement *)[controllers objectAtIndex: 0];
|
||||
NSXMLNode *idAttr = [controller attributeForName: @"id"];
|
||||
src = [idAttr stringValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers = [objects nodesForXPath: @"viewController"
|
||||
error: NULL];
|
||||
if ([controllers count] > 0)
|
||||
{
|
||||
NSXMLElement *controller = (NSXMLElement *)[controllers objectAtIndex: 0];
|
||||
NSXMLNode *idAttr = [controller attributeForName: @"id"];
|
||||
src = [idAttr stringValue];
|
||||
}
|
||||
}
|
||||
|
||||
if ([connectionsArray count] > 0)
|
||||
{
|
||||
NSEnumerator *connectionsEnum = [connectionsArray objectEnumerator];
|
||||
id connObj = nil;
|
||||
while ((connObj = [connectionsEnum nextObject]) != nil)
|
||||
{
|
||||
NSXMLElement *connections = (NSXMLElement *)connObj;
|
||||
NSArray *children = [connections children]; // there should be only one per set.
|
||||
NSEnumerator *en = [children objectEnumerator];
|
||||
id obj = nil;
|
||||
|
||||
while ((obj = [en nextObject]) != nil)
|
||||
{
|
||||
if ([[obj name] isEqualToString: @"segue"])
|
||||
{
|
||||
// get the information from the segue.
|
||||
id segue_parent_parent = [[obj parent] parent];
|
||||
id segue_parent = [obj parent];
|
||||
NSString *segue_parent_parent_name = [segue_parent_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];
|
||||
[obj detach]; // segue can't be in the archive since it doesn't conform to NSCoding
|
||||
attr = [obj attributeForName: @"id"];
|
||||
NSString *uid = [attr stringValue];
|
||||
attr = [obj attributeForName: @"identifier"];
|
||||
NSString *identifier = [attr stringValue];
|
||||
if (identifier == nil)
|
||||
{
|
||||
identifier = [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
|
||||
// Create proxy object to invoke methods on the window controller
|
||||
NSXMLElement *sbproxy = [NSXMLElement elementWithName: @"storyboardSeguePerformAction"];
|
||||
NSXMLNode *pselector
|
||||
= [NSXMLNode attributeWithName: @"selector"
|
||||
stringValue: @"doAction:"];
|
||||
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: identifier];
|
||||
NSXMLNode *psender
|
||||
= [NSXMLNode attributeWithName: @"sender"
|
||||
stringValue: src];
|
||||
NSXMLNode *pkind
|
||||
= [NSXMLNode attributeWithName: @"kind"
|
||||
stringValue: kind];
|
||||
|
||||
[sbproxy addAttribute: pselector];
|
||||
[sbproxy addAttribute: ptarget];
|
||||
[sbproxy addAttribute: pident];
|
||||
[sbproxy addAttribute: psegueIdent];
|
||||
[sbproxy addAttribute: psender];
|
||||
[sbproxy addAttribute: pkind];
|
||||
NSUInteger count = [[objects children] count];
|
||||
[objects insertChild: sbproxy
|
||||
atIndex: count - 1];
|
||||
|
||||
// add action to parent ONLY if it is NOT a controller..
|
||||
if (![segue_parent_parent_name isEqualToString: @"windowController"] &&
|
||||
![segue_parent_parent_name isEqualToString: @"viewController"])
|
||||
{
|
||||
// Create action...
|
||||
NSXMLElement *action = [NSXMLElement elementWithName: @"action"];
|
||||
NSXMLNode *selector
|
||||
= [NSXMLNode attributeWithName: @"selector"
|
||||
stringValue: @"doAction:"];
|
||||
NSXMLNode *target
|
||||
= [NSXMLNode attributeWithName: @"target"
|
||||
stringValue: pident_value];
|
||||
NSXMLNode *ident
|
||||
= [NSXMLNode attributeWithName: @"id"
|
||||
stringValue: uid];
|
||||
[action addAttribute: selector];
|
||||
[action addAttribute: target];
|
||||
[action addAttribute: ident];
|
||||
[segue_parent addChild: action];
|
||||
}
|
||||
|
||||
// Create the segue...
|
||||
NSStoryboardSegue *ss = [[NSStoryboardSegue alloc] initWithIdentifier: identifier
|
||||
source: src
|
||||
destination: dst];
|
||||
[ss _setKind: kind];
|
||||
[ss _setRelationship: rel];
|
||||
|
||||
// Add to maptable...
|
||||
[mapTable setObject: ss
|
||||
forKey: identifier];
|
||||
|
||||
} // only process segue objects...
|
||||
} // iterate over objects in each set of connections
|
||||
} // iterate over connection objs
|
||||
|
||||
[_identifierToSegueMap setObject: mapTable
|
||||
forKey: identifier];
|
||||
|
||||
// Add to cache...
|
||||
[_documentsMap setObject: mapTable
|
||||
forKey: uuidString];
|
||||
|
||||
} // if connections > 0
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#import "AppKit/NSWindow.h"
|
||||
|
||||
#import "GNUstepGUI/GSModelLoaderFactory.h"
|
||||
#import "GSStoryboardTransform.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
|
||||
static NSStoryboard *__mainStoryboard = nil;
|
||||
|
@ -58,36 +59,6 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
- (void) _setStoryboard: (NSStoryboard *)storyboard;
|
||||
@end
|
||||
|
||||
@interface NSStoryboardSegue (__StoryboardPrivate__)
|
||||
- (void) _setKind: (NSString *)k;
|
||||
- (void) _setRelationship: (NSString *)r;
|
||||
- (NSString *) _kind;
|
||||
- (NSString *) _relationship;
|
||||
@end
|
||||
|
||||
// this needs to be set on segues
|
||||
@implementation NSStoryboardSegue (__StoryboardPrivate__)
|
||||
- (void) _setKind: (NSString *)k
|
||||
{
|
||||
ASSIGN(_kind, k);
|
||||
}
|
||||
|
||||
- (void) _setRelationship: (NSString *)r
|
||||
{
|
||||
ASSIGN(_relationship, r);
|
||||
}
|
||||
|
||||
- (NSString *) _kind
|
||||
{
|
||||
return _kind;
|
||||
}
|
||||
|
||||
- (NSString *) _relationship
|
||||
{
|
||||
return _relationship;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSWindowController (__StoryboardPrivate__)
|
||||
- (void) _setOwner: (id)owner
|
||||
{
|
||||
|
@ -128,633 +99,8 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
@end
|
||||
// end private methods...
|
||||
|
||||
@interface NSStoryboardSeguePerformAction : NSObject <NSCoding, NSCopying>
|
||||
{
|
||||
id _target;
|
||||
SEL _action;
|
||||
id _sender;
|
||||
NSString *_identifier;
|
||||
NSString *_kind;
|
||||
}
|
||||
|
||||
- (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;
|
||||
@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);
|
||||
}
|
||||
|
||||
- (id) nibInstantiate
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (IBAction) doAction: (id)sender
|
||||
{
|
||||
[_sender performSegueWithIdentifier: _identifier
|
||||
sender: _sender];
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *)z
|
||||
{
|
||||
NSStoryboardSeguePerformAction *pa = [[NSStoryboardSeguePerformAction allocWithZone: z] init];
|
||||
[pa setTarget: _target];
|
||||
[pa setSelector: [self selector]];
|
||||
[pa setSender: _sender];
|
||||
[pa setIdentifier: _identifier];
|
||||
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"]];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder: (NSCoder *)coder
|
||||
{
|
||||
// this is never encoded directly...
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface NSControllerPlaceholder : NSObject <NSCoding, NSCopying> // , NSSeguePerforming>
|
||||
{
|
||||
NSString *_storyboardName;
|
||||
}
|
||||
|
||||
- (NSString *) storyboardName;
|
||||
- (void) setStoryboardName: (NSString *)name;
|
||||
|
||||
- (id) instantiate;
|
||||
|
||||
@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 NSStoryboard
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (void) _processStoryboard: (NSXMLDocument *)storyboardXml
|
||||
{
|
||||
NSArray *docNodes = [storyboardXml nodesForXPath: @"document" error: NULL];
|
||||
|
||||
if ([docNodes count] > 0)
|
||||
{
|
||||
NSXMLElement *docNode = [docNodes objectAtIndex: 0];
|
||||
NSArray *array = [docNode nodesForXPath: @"//scene" error: NULL];
|
||||
NSString *customClassString = nil;
|
||||
|
||||
// Set initial view controller...
|
||||
ASSIGN(_initialViewControllerId, [[docNode attributeForName: @"initialViewController"] stringValue]);
|
||||
_scenesMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
||||
_controllerMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
||||
_documentsMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
||||
|
||||
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];
|
||||
if (appNode != nil)
|
||||
{
|
||||
NSXMLElement *objects = (NSXMLElement *)[appNode parent];
|
||||
NSArray *appConsArr = [appNode nodesForXPath: @"connections" error: NULL];
|
||||
NSXMLNode *appCons = [appConsArr objectAtIndex: 0];
|
||||
if (appCons != nil)
|
||||
{
|
||||
[appCons detach];
|
||||
}
|
||||
|
||||
NSArray *appChildren = [appNode children];
|
||||
NSEnumerator *ace = [appChildren objectEnumerator];
|
||||
NSXMLElement *ae = nil;
|
||||
|
||||
// Assign application scene...
|
||||
ASSIGN(_applicationSceneId, sceneId);
|
||||
|
||||
// Move all application children to objects...
|
||||
while ((ae = [ace nextObject]) != nil)
|
||||
{
|
||||
[ae detach];
|
||||
[objects addChild: ae];
|
||||
}
|
||||
|
||||
// Remove the appNode
|
||||
[appNode detach];
|
||||
|
||||
// Add it to the document
|
||||
[objects detach];
|
||||
[doc addChild: objects];
|
||||
|
||||
// create a customObject entry for NSApplication reference...
|
||||
NSXMLNode *appCustomClass = (NSXMLNode *)[(NSXMLElement *)appNode
|
||||
attributeForName: @"customClass"];
|
||||
customClassString = ([appCustomClass stringValue] == nil) ?
|
||||
@"NSApplication" : [appCustomClass stringValue];
|
||||
NSXMLElement *customObject = nil;
|
||||
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-3"
|
||||
userLabel: @"Application"
|
||||
customClass: @"NSObject"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-1"
|
||||
userLabel: @"First Responder"
|
||||
customClass: @"FirstResponder"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-2"
|
||||
userLabel: @"File's Owner"
|
||||
customClass: customClassString];
|
||||
if (appCons != nil)
|
||||
{
|
||||
[customObject addChild: appCons];
|
||||
}
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSXMLElement *customObject = nil;
|
||||
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-3"
|
||||
userLabel: @"Application"
|
||||
customClass: @"NSObject"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-1"
|
||||
userLabel: @"First Responder"
|
||||
customClass: @"FirstResponder"];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
customObject =
|
||||
[self _createCustomObjectWithId: @"-2"
|
||||
userLabel: @"File's Owner"
|
||||
customClass: customClassString];
|
||||
[child insertChild: customObject
|
||||
atIndex: 0];
|
||||
|
||||
[child detach];
|
||||
[doc addChild: child];
|
||||
}
|
||||
|
||||
// Add other custom objects...
|
||||
|
||||
// fix other custom objects
|
||||
document = [[NSXMLDocument alloc] initWithRootElement: doc]; // put it into the document, so we can use Xpath.
|
||||
NSArray *windowControllers = [document nodesForXPath: @"//windowController" error: NULL];
|
||||
NSArray *viewControllers = [document nodesForXPath: @"//viewController" error: NULL];
|
||||
NSArray *controllerPlaceholders = [document nodesForXPath: @"//controllerPlaceholder" error: NULL];
|
||||
RELEASE(doc);
|
||||
|
||||
if ([windowControllers count] > 0)
|
||||
{
|
||||
NSXMLElement *ce = [windowControllers objectAtIndex: 0];
|
||||
NSXMLNode *attr = [ce attributeForName: @"id"];
|
||||
controllerId = [attr stringValue];
|
||||
|
||||
NSEnumerator *windowControllerEnum = [windowControllers objectEnumerator];
|
||||
NSXMLElement *o = nil;
|
||||
while ((o = [windowControllerEnum nextObject]) != nil)
|
||||
{
|
||||
NSXMLElement *objects = (NSXMLElement *)[o parent];
|
||||
NSArray *windows = [o nodesForXPath: @"//window" error: NULL];
|
||||
NSEnumerator *windowEn = [windows objectEnumerator];
|
||||
NSXMLNode *w = nil;
|
||||
while ((w = [windowEn nextObject]) != nil)
|
||||
{
|
||||
[w detach];
|
||||
[objects addChild: w];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
NSArray *customObjects = [document nodesForXPath: @"//objects/customObject" error: NULL];
|
||||
NSEnumerator *coen = [customObjects objectEnumerator];
|
||||
NSXMLElement *coel = nil;
|
||||
while ((coel = [coen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *attr = [coel attributeForName: @"sceneMemberID"];
|
||||
if ([[attr stringValue] isEqualToString: @"firstResponder"])
|
||||
{
|
||||
NSXMLNode *customClassAttr = [coel attributeForName: @"customClass"];
|
||||
NSXMLNode *idAttr = [coel attributeForName: @"id"];
|
||||
NSString *originalId = [idAttr stringValue];
|
||||
|
||||
[idAttr setStringValue: @"-1"]; // set to first responder id
|
||||
[customClassAttr setStringValue: @"FirstResponder"];
|
||||
|
||||
// Actions
|
||||
NSArray *cons = [document nodesForXPath: @"//action" error: NULL];
|
||||
NSEnumerator *consen = [cons objectEnumerator];
|
||||
NSXMLElement *celem = nil;
|
||||
|
||||
while ((celem = [consen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *targetAttr = [celem attributeForName: @"target"];
|
||||
NSString *val = [targetAttr stringValue];
|
||||
if ([val isEqualToString: originalId])
|
||||
{
|
||||
[targetAttr setStringValue: @"-1"];
|
||||
}
|
||||
}
|
||||
|
||||
// Outlets
|
||||
cons = [document nodesForXPath: @"//outlet" error: NULL];
|
||||
consen = [cons objectEnumerator];
|
||||
celem = nil;
|
||||
while ((celem = [consen nextObject]) != nil)
|
||||
{
|
||||
NSXMLNode *attr = [celem attributeForName: @"destination"];
|
||||
NSString *val = [attr stringValue];
|
||||
if ([val isEqualToString: originalId])
|
||||
{
|
||||
[attr setStringValue: @"-1"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create document...
|
||||
[_scenesMap setObject: document
|
||||
forKey: sceneId];
|
||||
|
||||
// Map controllerId's to scenes...
|
||||
if (controllerId != nil)
|
||||
{
|
||||
[_controllerMap setObject: sceneId
|
||||
forKey: controllerId];
|
||||
}
|
||||
|
||||
RELEASE(document);
|
||||
}
|
||||
END_FOR_IN(children);
|
||||
}
|
||||
END_FOR_IN(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"No document element in storyboard file");
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMapTable *) _processSegues: (NSXMLDocument *)xmlIn
|
||||
{
|
||||
NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable];
|
||||
NSArray *connectionsArray = [xmlIn nodesForXPath: @"//connections"
|
||||
error: NULL];
|
||||
NSArray *array = [xmlIn nodesForXPath: @"//objects[1]"
|
||||
error: NULL];
|
||||
NSXMLElement *objects = [array objectAtIndex: 0]; // get the "objects" section
|
||||
NSString *uuidString = nil;
|
||||
NSArray *docArray = [xmlIn nodesForXPath: @"document" error: NULL];
|
||||
|
||||
if ([docArray count] > 0)
|
||||
{
|
||||
NSXMLElement *docElem = (NSXMLElement *)[docArray objectAtIndex: 0];
|
||||
NSXMLNode *a = [docElem attributeForName: @"uuid"];
|
||||
NSString *value = [a stringValue];
|
||||
if (value != nil)
|
||||
{
|
||||
return [_documentsMap objectForKey: value];
|
||||
}
|
||||
else
|
||||
{
|
||||
uuidString = [[NSUUID UUID] UUIDString];
|
||||
NSXMLNode *new_uuid_attr = [NSXMLNode attributeWithName: @"uuid"
|
||||
stringValue: uuidString];
|
||||
[docElem addAttribute: new_uuid_attr];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the controller...
|
||||
NSString *src = nil;
|
||||
NSArray *controllers = [objects nodesForXPath: @"windowController"
|
||||
error: NULL];
|
||||
if ([controllers count] > 0)
|
||||
{
|
||||
NSXMLElement *controller = (NSXMLElement *)[controllers objectAtIndex: 0];
|
||||
NSXMLNode *idAttr = [controller attributeForName: @"id"];
|
||||
src = [idAttr stringValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
controllers = [objects nodesForXPath: @"viewController"
|
||||
error: NULL];
|
||||
if ([controllers count] > 0)
|
||||
{
|
||||
NSXMLElement *controller = (NSXMLElement *)[controllers objectAtIndex: 0];
|
||||
NSXMLNode *idAttr = [controller attributeForName: @"id"];
|
||||
src = [idAttr stringValue];
|
||||
}
|
||||
}
|
||||
|
||||
if ([connectionsArray count] > 0)
|
||||
{
|
||||
NSEnumerator *connectionsEnum = [connectionsArray objectEnumerator];
|
||||
id connObj = nil;
|
||||
while ((connObj = [connectionsEnum nextObject]) != nil)
|
||||
{
|
||||
NSXMLElement *connections = (NSXMLElement *)connObj;
|
||||
NSArray *children = [connections children]; // there should be only one per set.
|
||||
NSEnumerator *en = [children objectEnumerator];
|
||||
id obj = nil;
|
||||
|
||||
while ((obj = [en nextObject]) != nil)
|
||||
{
|
||||
if ([[obj name] isEqualToString: @"segue"])
|
||||
{
|
||||
// get the information from the segue.
|
||||
id segue_parent_parent = [[obj parent] parent];
|
||||
id segue_parent = [obj parent];
|
||||
NSString *segue_parent_parent_name = [segue_parent_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];
|
||||
[obj detach]; // segue can't be in the archive since it doesn't conform to NSCoding
|
||||
attr = [obj attributeForName: @"id"];
|
||||
NSString *uid = [attr stringValue];
|
||||
attr = [obj attributeForName: @"identifier"];
|
||||
NSString *identifier = [attr stringValue];
|
||||
if (identifier == nil)
|
||||
{
|
||||
identifier = [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
|
||||
// Create proxy object to invoke methods on the window controller
|
||||
NSXMLElement *sbproxy = [NSXMLElement elementWithName: @"storyboardSeguePerformAction"];
|
||||
NSXMLNode *pselector
|
||||
= [NSXMLNode attributeWithName: @"selector"
|
||||
stringValue: @"doAction:"];
|
||||
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: identifier];
|
||||
NSXMLNode *psender
|
||||
= [NSXMLNode attributeWithName: @"sender"
|
||||
stringValue: src];
|
||||
NSXMLNode *pkind
|
||||
= [NSXMLNode attributeWithName: @"kind"
|
||||
stringValue: kind];
|
||||
|
||||
[sbproxy addAttribute: pselector];
|
||||
[sbproxy addAttribute: ptarget];
|
||||
[sbproxy addAttribute: pident];
|
||||
[sbproxy addAttribute: psegueIdent];
|
||||
[sbproxy addAttribute: psender];
|
||||
[sbproxy addAttribute: pkind];
|
||||
NSUInteger count = [[objects children] count];
|
||||
[objects insertChild: sbproxy
|
||||
atIndex: count - 1];
|
||||
|
||||
// add action to parent ONLY if it is NOT a controller..
|
||||
if (![segue_parent_parent_name isEqualToString: @"windowController"] &&
|
||||
![segue_parent_parent_name isEqualToString: @"viewController"])
|
||||
{
|
||||
// Create action...
|
||||
NSXMLElement *action = [NSXMLElement elementWithName: @"action"];
|
||||
NSXMLNode *selector
|
||||
= [NSXMLNode attributeWithName: @"selector"
|
||||
stringValue: @"doAction:"];
|
||||
NSXMLNode *target
|
||||
= [NSXMLNode attributeWithName: @"target"
|
||||
stringValue: pident_value];
|
||||
NSXMLNode *ident
|
||||
= [NSXMLNode attributeWithName: @"id"
|
||||
stringValue: uid];
|
||||
[action addAttribute: selector];
|
||||
[action addAttribute: target];
|
||||
[action addAttribute: ident];
|
||||
[segue_parent addChild: action];
|
||||
}
|
||||
|
||||
// Create the segue...
|
||||
NSStoryboardSegue *ss = [[NSStoryboardSegue alloc] initWithIdentifier: identifier
|
||||
source: src
|
||||
destination: dst];
|
||||
[ss _setKind: kind];
|
||||
[ss _setRelationship: rel];
|
||||
|
||||
// Add to maptable...
|
||||
[mapTable setObject: ss
|
||||
forKey: identifier];
|
||||
|
||||
} // only process segue objects...
|
||||
} // iterate over objects in each set of connections
|
||||
} // iterate over connection objs
|
||||
|
||||
// Add to cache...
|
||||
[_documentsMap setObject: mapTable
|
||||
forKey: uuidString];
|
||||
|
||||
} // if connections > 0
|
||||
return mapTable;
|
||||
}
|
||||
|
||||
// Private instance methods...
|
||||
- (id) initWithName: (NSStoryboardName)name
|
||||
bundle: (NSBundle *)bundle
|
||||
|
@ -765,12 +111,7 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
NSString *path = [bundle pathForResource: name
|
||||
ofType: @"storyboard"];
|
||||
NSData *data = [NSData dataWithContentsOfFile: path];
|
||||
|
||||
NSXMLDocument *storyboardXml = [[NSXMLDocument alloc] initWithData: data
|
||||
options: 0
|
||||
error: NULL];
|
||||
[self _processStoryboard: storyboardXml];
|
||||
RELEASE(storyboardXml);
|
||||
_transform = [[GSStoryboardTransform alloc] initWithData: data];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -799,11 +140,7 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
// Instance methods...
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_initialViewControllerId);
|
||||
RELEASE(_applicationSceneId);
|
||||
RELEASE(_scenesMap);
|
||||
RELEASE(_controllerMap);
|
||||
RELEASE(_documentsMap);
|
||||
RELEASE(_transform);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -814,10 +151,8 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
table = [NSDictionary dictionaryWithObject: NSApp
|
||||
forKey: NSNibOwner];
|
||||
|
||||
NSXMLDocument *xml = [_scenesMap objectForKey: _applicationSceneId];
|
||||
NSData *xmlData = [xml XMLData];
|
||||
GSModelLoader *loader = [GSModelLoaderFactory modelLoaderForFileType: @"xib"];
|
||||
BOOL success = [loader loadModelData: xmlData
|
||||
BOOL success = [loader loadModelData: [_transform dataForApplicationScene]
|
||||
externalNameTable: table
|
||||
withZone: [self zone]];
|
||||
if (!success)
|
||||
|
@ -833,7 +168,7 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
|
||||
- (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block
|
||||
{
|
||||
return [self instantiateControllerWithIdentifier: _initialViewControllerId
|
||||
return [self instantiateControllerWithIdentifier: [_transform initialViewControllerId]
|
||||
creator: block];
|
||||
}
|
||||
|
||||
|
@ -846,19 +181,15 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
||||
creator: (NSStoryboardControllerCreator)block
|
||||
{
|
||||
id result = nil;
|
||||
id result = nil;
|
||||
NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5];
|
||||
NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects,
|
||||
NSNibTopLevelObjects,
|
||||
NSApp,
|
||||
NSNibOwner,
|
||||
nil];
|
||||
NSString *sceneId = [_controllerMap objectForKey: identifier];
|
||||
NSXMLDocument *xml = [[_scenesMap objectForKey: sceneId] copy];
|
||||
NSMapTable *segueMap = [self _processSegues: xml];
|
||||
NSData *xmlData = [xml XMLData];
|
||||
GSModelLoader *loader = [GSModelLoaderFactory modelLoaderForFileType: @"xib"];
|
||||
BOOL success = [loader loadModelData: xmlData
|
||||
BOOL success = [loader loadModelData: [_transform dataForIdentifier: identifier]
|
||||
externalNameTable: table
|
||||
withZone: [self zone]];
|
||||
|
||||
|
@ -866,13 +197,12 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
{
|
||||
NSMutableArray *seguesToPerform = [NSMutableArray array];
|
||||
NSMutableArray *placeholders = [NSMutableArray array];
|
||||
NSMapTable *segueMap = [_transform segueMapForIdentifier: identifier];
|
||||
NSWindowController *wc = nil;
|
||||
NSViewController *vc = nil;
|
||||
NSWindow *w = nil;
|
||||
NSEnumerator *en = [topLevelObjects objectEnumerator];
|
||||
id o = nil;
|
||||
|
||||
while ((o = [en nextObject]) != nil)
|
||||
|
||||
FOR_IN(id, o, topLevelObjects)
|
||||
{
|
||||
if ([o isKindOfClass: [NSWindowController class]])
|
||||
{
|
||||
|
@ -900,11 +230,10 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
[placeholders addObject: o];
|
||||
}
|
||||
}
|
||||
|
||||
END_FOR_IN(topLevelObjects);
|
||||
|
||||
// Process action proxies after so we know we have the windowController...
|
||||
en = [topLevelObjects objectEnumerator];
|
||||
o = nil;
|
||||
while ((o = [en nextObject]) != nil)
|
||||
FOR_IN(id, o, topLevelObjects)
|
||||
{
|
||||
if ([o isKindOfClass: [NSStoryboardSeguePerformAction class]])
|
||||
{
|
||||
|
@ -916,6 +245,7 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
}
|
||||
}
|
||||
}
|
||||
END_FOR_IN(topLevelObjects);
|
||||
|
||||
// Depending on which kind of controller we have, do the correct thing....
|
||||
if (w != nil && wc != nil)
|
||||
|
@ -924,25 +254,24 @@ static NSStoryboard *__mainStoryboard = nil;
|
|||
}
|
||||
|
||||
// perform segues after all is initialized.
|
||||
en = [seguesToPerform objectEnumerator];
|
||||
o = nil;
|
||||
while ((o = [en nextObject]) != nil)
|
||||
FOR_IN(id, o, seguesToPerform)
|
||||
{
|
||||
NSStoryboardSeguePerformAction *ssa = (NSStoryboardSeguePerformAction *)o;
|
||||
[ssa doAction: result]; // this will, as far as I know, only happen with window controllers, to set content.
|
||||
}
|
||||
END_FOR_IN(seguesToPerform);
|
||||
|
||||
en = [placeholders objectEnumerator];
|
||||
o = nil;
|
||||
while ((o = [en nextObject]) != nil)
|
||||
// process placeholders...
|
||||
FOR_IN(id, o, placeholders)
|
||||
{
|
||||
NSControllerPlaceholder *ph = (NSControllerPlaceholder *)o;
|
||||
result = [ph instantiate];
|
||||
}
|
||||
END_FOR_IN(placeholders);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Couldn't load controller scene id = %@", sceneId);
|
||||
NSLog(@"Couldn't load controller scene identifier = %@", identifier);
|
||||
}
|
||||
|
||||
// Execute the block if it's set...
|
||||
|
|
Loading…
Reference in a new issue