2020-01-20 20:58:19 +00:00
|
|
|
/* Implementation of class NSStoryboard
|
2020-07-06 00:42:35 +00:00
|
|
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
2020-01-20 20:58:19 +00:00
|
|
|
|
|
|
|
By: Gregory Casamento
|
|
|
|
Date: Mon Jan 20 15:57:37 EST 2020
|
|
|
|
|
|
|
|
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 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.
|
|
|
|
*/
|
|
|
|
|
2020-06-19 11:45:10 +00:00
|
|
|
#import <Foundation/NSBundle.h>
|
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSData.h>
|
2020-06-20 10:58:11 +00:00
|
|
|
#import <Foundation/NSXMLDocument.h>
|
2020-06-22 06:56:15 +00:00
|
|
|
#import <Foundation/NSXMLElement.h>
|
|
|
|
#import <Foundation/NSXMLNode.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSArray.h>
|
2020-07-02 17:24:48 +00:00
|
|
|
#import <Foundation/NSUUID.h>
|
2020-06-19 11:45:10 +00:00
|
|
|
|
2020-06-22 11:01:49 +00:00
|
|
|
#import "AppKit/NSApplication.h"
|
|
|
|
#import "AppKit/NSNib.h"
|
2020-06-19 11:45:10 +00:00
|
|
|
#import "AppKit/NSStoryboard.h"
|
2020-06-23 13:10:08 +00:00
|
|
|
#import "AppKit/NSWindowController.h"
|
|
|
|
#import "AppKit/NSViewController.h"
|
2020-06-23 19:15:09 +00:00
|
|
|
#import "AppKit/NSWindow.h"
|
2020-06-22 11:01:49 +00:00
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
#import "GNUstepGUI/GSModelLoaderFactory.h"
|
2020-07-06 01:12:02 +00:00
|
|
|
#import "GSFastEnumeration.h"
|
2020-01-20 20:58:19 +00:00
|
|
|
|
2020-07-04 21:30:43 +00:00
|
|
|
static NSStoryboard *__mainStoryboard = nil;
|
2020-06-19 09:15:37 +00:00
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
// The storyboard needs to set this information on controllers...
|
|
|
|
@interface NSWindowController (__StoryboardPrivate__)
|
|
|
|
- (void) _setOwner: (id)owner;
|
|
|
|
- (void) _setTopLevelObjects: (NSArray *)array;
|
|
|
|
- (void) _setSegueMap: (NSMapTable *)map;
|
2020-07-04 21:30:43 +00:00
|
|
|
- (void) _setStoryboard: (NSStoryboard *)storyboard;
|
2020-07-02 17:24:48 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@interface NSViewController (__StoryboardPrivate__)
|
|
|
|
- (void) _setTopLevelObjects: (NSArray *)array;
|
|
|
|
- (void) _setSegueMap: (NSMapTable *)map;
|
2020-07-04 21:30:43 +00:00
|
|
|
- (void) _setStoryboard: (NSStoryboard *)storyboard;
|
2020-07-02 17:24:48 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@interface NSStoryboardSegue (__StoryboardPrivate__)
|
|
|
|
- (void) _setKind: (NSString *)k;
|
|
|
|
- (void) _setRelationship: (NSString *)r;
|
2020-07-02 20:39:40 +00:00
|
|
|
- (NSString *) _kind;
|
|
|
|
- (NSString *) _relationship;
|
2020-07-02 17:24:48 +00:00
|
|
|
@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);
|
|
|
|
}
|
2020-07-02 20:39:40 +00:00
|
|
|
|
|
|
|
- (NSString *) _kind
|
|
|
|
{
|
|
|
|
return _kind;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _relationship
|
|
|
|
{
|
|
|
|
return _relationship;
|
|
|
|
}
|
2020-07-02 17:24:48 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSWindowController (__StoryboardPrivate__)
|
|
|
|
- (void) _setOwner: (id)owner
|
|
|
|
{
|
|
|
|
_owner = owner; // weak
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setTopLevelObjects: (NSArray *)array
|
|
|
|
{
|
|
|
|
_top_level_objects = array;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setSegueMap: (NSMapTable *)map
|
|
|
|
{
|
|
|
|
ASSIGN(_segueMap, map);
|
|
|
|
}
|
|
|
|
|
2020-07-04 21:30:43 +00:00
|
|
|
- (void) _setStoryboard: (NSStoryboard *)storyboard
|
|
|
|
{
|
|
|
|
_storyboard = storyboard;
|
|
|
|
}
|
2020-07-02 17:24:48 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSViewController (__StoryboardPrivate__)
|
|
|
|
- (void) _setTopLevelObjects: (NSArray *)array
|
|
|
|
{
|
|
|
|
_topLevelObjects = array;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setSegueMap: (NSMapTable *)map
|
|
|
|
{
|
|
|
|
ASSIGN(_segueMap, map);
|
|
|
|
}
|
2020-07-04 21:30:43 +00:00
|
|
|
|
|
|
|
- (void) _setStoryboard: (NSStoryboard *)storyboard
|
|
|
|
{
|
|
|
|
_storyboard = storyboard;
|
|
|
|
}
|
2020-07-02 17:24:48 +00:00
|
|
|
@end
|
|
|
|
// end private methods...
|
|
|
|
|
|
|
|
@interface NSStoryboardSeguePerformAction : NSObject <NSCoding, NSCopying>
|
|
|
|
{
|
|
|
|
id _target;
|
|
|
|
SEL _action;
|
|
|
|
id _sender;
|
|
|
|
NSString *_identifier;
|
2020-07-02 20:39:40 +00:00
|
|
|
NSString *_kind;
|
2020-07-02 17:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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;
|
2020-07-02 20:39:40 +00:00
|
|
|
|
|
|
|
- (NSString *) kind;
|
|
|
|
- (void) setKind: (NSString *)kind;
|
2020-07-02 17:24:48 +00:00
|
|
|
@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);
|
|
|
|
}
|
|
|
|
|
2020-07-02 20:39:40 +00:00
|
|
|
- (NSString *) kind
|
|
|
|
{
|
|
|
|
return _kind;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setKind: (NSString *)kind
|
|
|
|
{
|
|
|
|
ASSIGN(_kind, kind);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) nibInstantiate
|
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
- (IBAction) doAction: (id)sender
|
|
|
|
{
|
2020-07-04 17:01:26 +00:00
|
|
|
[_sender performSegueWithIdentifier: _identifier
|
|
|
|
sender: _sender];
|
2020-07-02 17:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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"]];
|
|
|
|
}
|
2020-07-02 20:39:40 +00:00
|
|
|
if ([coder containsValueForKey: @"NSKind"])
|
|
|
|
{
|
|
|
|
[self setKind: [coder decodeObjectForKey: @"NSKind"]];
|
|
|
|
}
|
2020-07-02 17:24:48 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
|
|
|
{
|
|
|
|
// this is never encoded directly...
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2020-07-04 21:30:43 +00:00
|
|
|
|
|
|
|
@interface NSControllerPlaceholder : NSObject <NSCoding, NSCopying> // , NSSeguePerforming>
|
|
|
|
{
|
|
|
|
NSString *_storyboardName;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) storyboardName;
|
|
|
|
- (void) setStoryboardName: (NSString *)name;
|
2020-07-06 00:42:35 +00:00
|
|
|
|
2020-07-05 16:39:34 +00:00
|
|
|
- (id) instantiate;
|
2020-07-04 21:30:43 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSControllerPlaceholder
|
|
|
|
|
|
|
|
- (instancetype) init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self != nil)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (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...
|
|
|
|
}
|
|
|
|
|
2020-07-05 16:39:34 +00:00
|
|
|
- (id) instantiate
|
2020-07-04 21:30:43 +00:00
|
|
|
{
|
2020-07-06 00:42:35 +00:00
|
|
|
NSStoryboard *sb = [NSStoryboard storyboardWithName: _storyboardName
|
|
|
|
bundle: [NSBundle mainBundle]];
|
|
|
|
return [sb instantiateInitialController];
|
2020-07-04 21:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2020-01-20 20:58:19 +00:00
|
|
|
@implementation NSStoryboard
|
|
|
|
|
2020-06-28 12:05:07 +00:00
|
|
|
- (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;
|
|
|
|
}
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
- (void) _processStoryboard: (NSXMLDocument *)storyboardXml
|
2020-06-20 10:58:11 +00:00
|
|
|
{
|
2020-06-22 06:56:15 +00:00
|
|
|
NSArray *docNodes = [storyboardXml nodesForXPath: @"document" error: NULL];
|
|
|
|
|
|
|
|
if ([docNodes count] > 0)
|
|
|
|
{
|
|
|
|
NSXMLElement *docNode = [docNodes objectAtIndex: 0];
|
|
|
|
NSArray *array = [docNode nodesForXPath: @"//scene" error: NULL];
|
2020-06-23 13:10:08 +00:00
|
|
|
NSString *customClassString = nil;
|
2020-06-22 06:56:15 +00:00
|
|
|
|
|
|
|
// Set initial view controller...
|
|
|
|
ASSIGN(_initialViewControllerId, [[docNode attributeForName: @"initialViewController"] stringValue]);
|
|
|
|
_scenesMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
2020-06-23 13:10:08 +00:00
|
|
|
_controllerMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
2020-07-04 18:55:08 +00:00
|
|
|
_documentsMap = [[NSMutableDictionary alloc] initWithCapacity: [array count]];
|
|
|
|
|
2020-07-06 00:42:35 +00:00
|
|
|
//while ((e = [en nextObject]) != nil)
|
|
|
|
FOR_IN(NSXMLElement*, e, array)
|
2020-06-22 06:56:15 +00:00
|
|
|
{
|
|
|
|
NSXMLElement *doc = [[NSXMLElement alloc] initWithName: @"document"];
|
|
|
|
NSArray *children = [e children];
|
|
|
|
NSXMLDocument *document = nil;
|
|
|
|
NSString *sceneId = [[e attributeForName: @"sceneID"] stringValue];
|
2020-06-23 13:10:08 +00:00
|
|
|
NSString *controllerId = nil;
|
2020-07-05 15:14:13 +00:00
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
// Copy children...
|
2020-07-06 02:31:59 +00:00
|
|
|
FOR_IN(NSXMLElement*, child, children)
|
2020-06-22 06:56:15 +00:00
|
|
|
{
|
|
|
|
if ([[child name] isEqualToString: @"point"] == YES)
|
|
|
|
continue; // go on if it's point, we don't use that in the app...
|
|
|
|
|
|
|
|
NSArray *subnodes = [child nodesForXPath: @"//application" error: NULL];
|
|
|
|
NSXMLNode *appNode = [subnodes objectAtIndex: 0];
|
2020-07-06 00:42:35 +00:00
|
|
|
if (appNode != nil)
|
2020-06-22 06:56:15 +00:00
|
|
|
{
|
2020-06-23 13:10:08 +00:00
|
|
|
NSXMLElement *objects = (NSXMLElement *)[appNode parent];
|
2020-06-22 11:01:49 +00:00
|
|
|
NSArray *appConsArr = [appNode nodesForXPath: @"connections" error: NULL];
|
|
|
|
NSXMLNode *appCons = [appConsArr objectAtIndex: 0];
|
|
|
|
if (appCons != nil)
|
|
|
|
{
|
|
|
|
[appCons detach];
|
|
|
|
}
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
NSArray *appChildren = [appNode children];
|
|
|
|
NSEnumerator *ace = [appChildren objectEnumerator];
|
|
|
|
NSXMLElement *ae = nil;
|
|
|
|
|
|
|
|
// Move all application children to objects...
|
|
|
|
while ((ae = [ace nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[ae detach];
|
|
|
|
[objects addChild: ae];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the appNode
|
|
|
|
[appNode detach];
|
|
|
|
|
|
|
|
// create a customObject entry for NSApplication reference...
|
2020-06-28 12:05:07 +00:00
|
|
|
NSXMLNode *appCustomClass = (NSXMLNode *)[(NSXMLElement *)appNode
|
|
|
|
attributeForName: @"customClass"];
|
2020-06-23 13:10:08 +00:00
|
|
|
customClassString = ([appCustomClass stringValue] == nil) ?
|
2020-06-28 12:05:07 +00:00
|
|
|
@"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];
|
2020-06-22 11:01:49 +00:00
|
|
|
if (appCons != nil)
|
|
|
|
{
|
|
|
|
[customObject addChild: appCons];
|
|
|
|
}
|
2020-06-28 12:05:07 +00:00
|
|
|
[child insertChild: customObject
|
|
|
|
atIndex: 0];
|
|
|
|
|
2020-06-22 11:01:49 +00:00
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
// Add it to the document
|
|
|
|
[objects detach];
|
|
|
|
[doc addChild: objects];
|
|
|
|
|
|
|
|
// Assign application scene...
|
|
|
|
ASSIGN(_applicationSceneId, sceneId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-28 12:05:07 +00:00
|
|
|
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];
|
2020-06-23 13:10:08 +00:00
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
[child detach];
|
|
|
|
[doc addChild: child];
|
|
|
|
}
|
2020-06-22 11:01:49 +00:00
|
|
|
|
2020-06-28 12:05:07 +00:00
|
|
|
// Add other custom objects...
|
|
|
|
|
2020-06-22 11:01:49 +00:00
|
|
|
// fix other custom objects
|
|
|
|
document = [[NSXMLDocument alloc] initWithRootElement: doc]; // put it into the document, so we can use Xpath.
|
2020-06-23 13:10:08 +00:00
|
|
|
NSArray *windowControllers = [document nodesForXPath: @"//windowController" error: NULL];
|
|
|
|
NSArray *viewControllers = [document nodesForXPath: @"//viewController" error: NULL];
|
2020-07-05 15:14:13 +00:00
|
|
|
NSArray *controllerPlaceholders = [document nodesForXPath: @"//controllerPlaceholder" error: NULL];
|
2020-07-05 18:02:20 +00:00
|
|
|
RELEASE(doc);
|
2020-07-05 15:14:13 +00:00
|
|
|
|
2020-06-23 13:10:08 +00:00
|
|
|
if ([windowControllers count] > 0)
|
|
|
|
{
|
|
|
|
NSXMLElement *ce = [windowControllers objectAtIndex: 0];
|
|
|
|
NSXMLNode *attr = [ce attributeForName: @"id"];
|
|
|
|
controllerId = [attr stringValue];
|
2020-06-23 19:15:09 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
2020-06-23 13:10:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ([viewControllers count] > 0)
|
|
|
|
{
|
|
|
|
NSXMLElement *ce = [viewControllers objectAtIndex: 0];
|
|
|
|
NSXMLNode *attr = [ce attributeForName: @"id"];
|
|
|
|
controllerId = [attr stringValue];
|
|
|
|
}
|
|
|
|
|
2020-07-05 15:14:13 +00:00
|
|
|
if ([controllerPlaceholders count] > 0)
|
|
|
|
{
|
|
|
|
NSXMLElement *ce = [controllerPlaceholders objectAtIndex: 0];
|
|
|
|
NSXMLNode *attr = [ce attributeForName: @"id"];
|
|
|
|
controllerId = [attr stringValue];
|
|
|
|
}
|
|
|
|
|
2020-06-22 11:01:49 +00:00
|
|
|
NSArray *customObjects = [document nodesForXPath: @"//objects/customObject" error: NULL];
|
|
|
|
NSEnumerator *coen = [customObjects objectEnumerator];
|
|
|
|
NSXMLElement *coel = nil;
|
|
|
|
while ((coel = [coen nextObject]) != nil)
|
|
|
|
{
|
2020-07-06 01:12:02 +00:00
|
|
|
NSXMLNode *attr = [coel attributeForName: @"sceneMemberID"];
|
2020-06-22 11:01:49 +00:00
|
|
|
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"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-05 15:14:13 +00:00
|
|
|
}
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
// Create document...
|
|
|
|
[_scenesMap setObject: document
|
|
|
|
forKey: sceneId];
|
2020-07-05 18:02:20 +00:00
|
|
|
|
2020-06-23 13:10:08 +00:00
|
|
|
// Map controllerId's to scenes...
|
|
|
|
if (controllerId != nil)
|
|
|
|
{
|
|
|
|
[_controllerMap setObject: sceneId
|
|
|
|
forKey: controllerId];
|
|
|
|
}
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
RELEASE(document);
|
|
|
|
}
|
2020-07-06 02:31:59 +00:00
|
|
|
END_FOR_IN(children);
|
2020-06-22 06:56:15 +00:00
|
|
|
}
|
2020-07-06 00:42:35 +00:00
|
|
|
END_FOR_IN(array);
|
2020-06-22 06:56:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"No document element in storyboard file");
|
|
|
|
}
|
2020-06-20 10:58:11 +00:00
|
|
|
}
|
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
- (NSMapTable *) _processSegues: (NSXMLDocument *)xmlIn
|
|
|
|
{
|
|
|
|
NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable];
|
|
|
|
NSArray *connectionsArray = [xmlIn nodesForXPath: @"//connections"
|
|
|
|
error: NULL];
|
2020-07-06 02:56:25 +00:00
|
|
|
NSArray *array = [xmlIn nodesForXPath: @"//objects[1]"
|
2020-07-02 17:24:48 +00:00
|
|
|
error: NULL];
|
|
|
|
NSXMLElement *objects = [array objectAtIndex: 0]; // get the "objects" section
|
|
|
|
NSArray *controllers = [objects nodesForXPath: @"windowController"
|
|
|
|
error: NULL];
|
2020-07-04 18:55:08 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
NSString *src = nil;
|
|
|
|
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)
|
|
|
|
{
|
2020-07-04 18:55:08 +00:00
|
|
|
NSEnumerator *connectionsEnum = [connectionsArray objectEnumerator];
|
|
|
|
id connObj = nil;
|
|
|
|
while ((connObj = [connectionsEnum nextObject]) != nil)
|
2020-07-02 17:24:48 +00:00
|
|
|
{
|
2020-07-04 18:55:08 +00:00
|
|
|
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)
|
2020-07-02 17:24:48 +00:00
|
|
|
{
|
2020-07-04 18:55:08 +00:00
|
|
|
if ([[obj name] isEqualToString: @"segue"])
|
2020-07-02 17:24:48 +00:00
|
|
|
{
|
2020-07-04 18:55:08 +00:00
|
|
|
// 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
|
2020-07-04 17:01:26 +00:00
|
|
|
= [NSXMLNode attributeWithName: @"selector"
|
|
|
|
stringValue: @"doAction:"];
|
2020-07-04 18:55:08 +00:00
|
|
|
NSXMLNode *ptarget
|
2020-07-04 17:01:26 +00:00
|
|
|
= [NSXMLNode attributeWithName: @"target"
|
2020-07-04 18:55:08 +00:00
|
|
|
stringValue: dst];
|
|
|
|
NSString *pident_value = [[NSUUID UUID] UUIDString];
|
|
|
|
NSXMLNode *pident
|
2020-07-04 17:01:26 +00:00
|
|
|
= [NSXMLNode attributeWithName: @"id"
|
2020-07-04 18:55:08 +00:00
|
|
|
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
|
2020-07-02 17:24:48 +00:00
|
|
|
return mapTable;
|
|
|
|
}
|
|
|
|
|
2020-06-19 11:45:10 +00:00
|
|
|
// Private instance methods...
|
|
|
|
- (id) initWithName: (NSStoryboardName)name
|
|
|
|
bundle: (NSBundle *)bundle
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self != nil)
|
|
|
|
{
|
|
|
|
NSString *path = [bundle pathForResource: name
|
|
|
|
ofType: @"storyboard"];
|
2020-06-20 10:58:11 +00:00
|
|
|
NSData *data = [NSData dataWithContentsOfFile: path];
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
NSXMLDocument *storyboardXml = [[NSXMLDocument alloc] initWithData: data
|
|
|
|
options: 0
|
|
|
|
error: NULL];
|
|
|
|
[self _processStoryboard: storyboardXml];
|
2020-06-22 11:01:49 +00:00
|
|
|
RELEASE(storyboardXml);
|
2020-06-19 11:45:10 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Class methods...
|
2020-07-04 21:30:43 +00:00
|
|
|
+ (void) _setMainStoryboard: (NSStoryboard *)storyboard // private, only called from NSApplicationMain()
|
2020-06-19 12:53:09 +00:00
|
|
|
{
|
2020-07-04 21:30:43 +00:00
|
|
|
if (__mainStoryboard == nil)
|
|
|
|
{
|
|
|
|
ASSIGN(__mainStoryboard, storyboard);
|
|
|
|
}
|
2020-06-19 12:53:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 09:15:37 +00:00
|
|
|
+ (NSStoryboard *) mainStoryboard // 10.13
|
|
|
|
{
|
2020-07-04 21:30:43 +00:00
|
|
|
return __mainStoryboard;
|
2020-06-19 09:15:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (instancetype) storyboardWithName: (NSStoryboardName)name
|
|
|
|
bundle: (NSBundle *)bundle
|
|
|
|
{
|
2020-06-19 11:45:10 +00:00
|
|
|
return AUTORELEASE([[NSStoryboard alloc] initWithName: name
|
|
|
|
bundle: bundle]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instance methods...
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
2020-06-22 06:56:15 +00:00
|
|
|
RELEASE(_initialViewControllerId);
|
|
|
|
RELEASE(_applicationSceneId);
|
|
|
|
RELEASE(_scenesMap);
|
2020-06-23 13:10:08 +00:00
|
|
|
RELEASE(_controllerMap);
|
2020-07-04 18:55:08 +00:00
|
|
|
RELEASE(_documentsMap);
|
2020-06-19 11:45:10 +00:00
|
|
|
[super dealloc];
|
2020-06-19 09:15:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
- (void) _instantiateApplicationScene
|
2020-06-19 09:15:37 +00:00
|
|
|
{
|
2020-06-22 11:01:49 +00:00
|
|
|
NSDictionary *table;
|
|
|
|
|
|
|
|
table = [NSDictionary dictionaryWithObject: NSApp
|
|
|
|
forKey: NSNibOwner];
|
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
NSXMLDocument *xml = [_scenesMap objectForKey: _applicationSceneId];
|
|
|
|
NSData *xmlData = [xml XMLData];
|
|
|
|
GSModelLoader *loader = [GSModelLoaderFactory modelLoaderForFileType: @"xib"];
|
|
|
|
BOOL success = [loader loadModelData: xmlData
|
2020-06-22 11:01:49 +00:00
|
|
|
externalNameTable: table
|
2020-06-22 06:56:15 +00:00
|
|
|
withZone: [self zone]];
|
2020-07-02 17:24:48 +00:00
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
NSLog(@"Unabled to load Application scene");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) instantiateInitialController
|
|
|
|
{
|
|
|
|
return [self instantiateControllerWithIdentifier: _initialViewControllerId];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block // 10.15
|
|
|
|
{
|
|
|
|
id controller = [self instantiateInitialController];
|
|
|
|
CALL_BLOCK(block, self);
|
|
|
|
return controller;
|
|
|
|
}
|
2020-06-22 06:56:15 +00:00
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
|
|
|
{
|
2020-07-05 16:07:28 +00:00
|
|
|
id result = nil;
|
2020-07-02 17:24:48 +00:00
|
|
|
NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5];
|
|
|
|
NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects,
|
|
|
|
NSNibTopLevelObjects,
|
|
|
|
NSApp,
|
|
|
|
NSNibOwner,
|
|
|
|
nil];
|
|
|
|
NSString *sceneId = [_controllerMap objectForKey: identifier];
|
2020-07-04 18:55:08 +00:00
|
|
|
NSXMLDocument *xml = [[_scenesMap objectForKey: sceneId] copy];
|
2020-07-02 17:24:48 +00:00
|
|
|
NSMapTable *segueMap = [self _processSegues: xml];
|
|
|
|
NSData *xmlData = [xml XMLData];
|
|
|
|
GSModelLoader *loader = [GSModelLoaderFactory modelLoaderForFileType: @"xib"];
|
|
|
|
BOOL success = [loader loadModelData: xmlData
|
|
|
|
externalNameTable: table
|
|
|
|
withZone: [self zone]];
|
2020-07-05 15:14:13 +00:00
|
|
|
|
2020-06-22 06:56:15 +00:00
|
|
|
if (success)
|
|
|
|
{
|
2020-07-02 20:39:40 +00:00
|
|
|
NSMutableArray *seguesToPerform = [NSMutableArray array];
|
2020-07-04 21:30:43 +00:00
|
|
|
NSMutableArray *placeholders = [NSMutableArray array];
|
2020-07-05 16:07:28 +00:00
|
|
|
NSWindowController *wc = nil;
|
|
|
|
NSViewController *vc = nil;
|
|
|
|
NSWindow *w = nil;
|
2020-07-02 17:24:48 +00:00
|
|
|
NSEnumerator *en = [topLevelObjects objectEnumerator];
|
|
|
|
id o = nil;
|
2020-07-05 16:07:28 +00:00
|
|
|
|
2020-07-02 17:24:48 +00:00
|
|
|
while ((o = [en nextObject]) != nil)
|
2020-06-23 13:10:08 +00:00
|
|
|
{
|
2020-07-05 16:07:28 +00:00
|
|
|
if ([o isKindOfClass: [NSWindowController class]])
|
2020-06-23 13:10:08 +00:00
|
|
|
{
|
2020-07-05 16:07:28 +00:00
|
|
|
wc = (NSWindowController *)o;
|
|
|
|
[wc _setSegueMap: segueMap];
|
|
|
|
[wc _setTopLevelObjects: topLevelObjects];
|
|
|
|
[wc _setStoryboard: self];
|
|
|
|
[wc _setOwner: NSApp];
|
|
|
|
result = o;
|
2020-07-02 17:24:48 +00:00
|
|
|
}
|
2020-07-05 16:07:28 +00:00
|
|
|
else if ([o isKindOfClass: [NSViewController class]])
|
2020-07-02 17:24:48 +00:00
|
|
|
{
|
2020-07-05 16:07:28 +00:00
|
|
|
vc = (NSViewController *)o;
|
|
|
|
[vc _setSegueMap: segueMap];
|
|
|
|
[vc _setTopLevelObjects: topLevelObjects];
|
|
|
|
[vc _setStoryboard: self];
|
|
|
|
result = o;
|
2020-07-05 15:14:13 +00:00
|
|
|
}
|
2020-07-05 16:07:28 +00:00
|
|
|
else if ([o isKindOfClass: [NSWindow class]])
|
2020-07-02 17:24:48 +00:00
|
|
|
{
|
2020-07-05 16:07:28 +00:00
|
|
|
w = (NSWindow *)o;
|
2020-06-23 13:10:08 +00:00
|
|
|
}
|
2020-07-05 16:07:28 +00:00
|
|
|
else if ([o isKindOfClass: [NSControllerPlaceholder class]])
|
|
|
|
{
|
|
|
|
[placeholders addObject: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process action proxies after so we know we have the windowController...
|
|
|
|
en = [topLevelObjects objectEnumerator];
|
|
|
|
o = nil;
|
|
|
|
while ((o = [en nextObject]) != nil)
|
|
|
|
{
|
2020-07-02 20:39:40 +00:00
|
|
|
if ([o isKindOfClass: [NSStoryboardSeguePerformAction class]])
|
|
|
|
{
|
|
|
|
NSStoryboardSeguePerformAction *ssa = (NSStoryboardSeguePerformAction *)o;
|
2020-07-05 16:07:28 +00:00
|
|
|
[ssa setSender: result]; // resolve controller here...
|
2020-07-04 17:01:26 +00:00
|
|
|
if ([[ssa kind] isEqualToString: @"relationship"]) // if it is a relationship, perform immediately
|
2020-07-02 20:39:40 +00:00
|
|
|
{
|
|
|
|
[seguesToPerform addObject: ssa];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-05 16:07:28 +00:00
|
|
|
// Depending on which kind of controller we have, do the correct thing....
|
|
|
|
if (w != nil && wc != nil)
|
|
|
|
{
|
|
|
|
[wc setWindow: w];
|
|
|
|
}
|
|
|
|
|
2020-07-02 20:39:40 +00:00
|
|
|
// perform segues after all is initialized.
|
|
|
|
en = [seguesToPerform objectEnumerator];
|
|
|
|
o = nil;
|
|
|
|
while ((o = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSStoryboardSeguePerformAction *ssa = (NSStoryboardSeguePerformAction *)o;
|
2020-07-05 16:07:28 +00:00
|
|
|
[ssa doAction: result]; // this will, as far as I know, only happen with window controllers, to set content.
|
2020-06-23 13:10:08 +00:00
|
|
|
}
|
2020-07-05 15:14:13 +00:00
|
|
|
|
|
|
|
en = [placeholders objectEnumerator];
|
|
|
|
o = nil;
|
|
|
|
while ((o = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSControllerPlaceholder *ph = (NSControllerPlaceholder *)o;
|
2020-07-05 16:39:34 +00:00
|
|
|
result = [ph instantiate];
|
2020-07-05 15:14:13 +00:00
|
|
|
}
|
2020-06-22 06:56:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-04 17:01:26 +00:00
|
|
|
NSLog(@"Couldn't load controller scene id = %@", sceneId);
|
2020-06-22 06:56:15 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 16:07:28 +00:00
|
|
|
return result;
|
2020-06-19 09:15:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
|
|
|
creator: (NSStoryboardControllerCreator)block // 10.15
|
|
|
|
{
|
2020-07-02 17:24:48 +00:00
|
|
|
id controller = [self instantiateControllerWithIdentifier: identifier];
|
|
|
|
CALL_BLOCK(block, self);
|
|
|
|
return controller;
|
2020-06-19 09:15:37 +00:00
|
|
|
}
|
2020-01-20 20:58:19 +00:00
|
|
|
@end
|
|
|
|
|