mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 02:10:48 +00:00
Merge pull request #65 from gnustep/NSStoryboard_branch2
NSStoryboard branch merging to master. Subsequent changes will be made in branches implementing additional view controllers, but this functionality is stable enough. Fred approved, and I have addressed all subsequent concerns.
This commit is contained in:
commit
0ccdb278d4
18 changed files with 1705 additions and 10 deletions
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
|||
2020-07-19 Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Headers/AppKit/AppKit.h: Add include files for NSSegue* and other
|
||||
classes.
|
||||
* Headers/AppKit/NSSeguePerforming.h: Protocol for segue performing
|
||||
so that classes that conform can be queried to determine if the
|
||||
segue should be performed in the first place.
|
||||
* Headers/AppKit/NSStoryboard.h: Class which loads the storyboard and
|
||||
loads the individual scenes and controllers.
|
||||
* Headers/AppKit/NSStoryboardSegue.h: This class handles the transition
|
||||
between controllers/scenes.
|
||||
* Headers/AppKit/NSViewController.h: Modifications to handle segues.
|
||||
* Headers/AppKit/NSWindowController.h: Modifications to handle segues.
|
||||
* Headers/AppKit/NSWindow.h: New method to create window controller for
|
||||
view controllers.
|
||||
* MISSING: Remove the classes implemented here from the missing list.
|
||||
* Source/Functions.m: Enhance NSApplicationMain() function to handle the
|
||||
loading of a storyboard.
|
||||
* Source/GNUmakefile: Add the new classes to the build and copy the headers.
|
||||
* Source/GSStoryboardTransform.[hm]: Class to handle the transformation of
|
||||
the storyboard file into "XIB" files for loading. Also handles the intermediate
|
||||
processes of instantiation of the destination controller.
|
||||
* Source/NSStoryboard.m: Implementation of the above described class.
|
||||
* Source/NSStoryboardSegue.m: Implementation of the above described class.
|
||||
* Source/NSViewController.m: Implementation of private methods to handle transitions.
|
||||
* Source/NSWindowController.m: Implementation of private methods to handle transitions.
|
||||
* Source/NSWindow.m: Implementation of method to create window controller for
|
||||
view controllers.
|
||||
|
||||
2020-07-10 Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Headers/AppKit/NSOutlineView.h: Formalize protocols for
|
||||
|
|
|
@ -225,6 +225,9 @@
|
|||
#import <AppKit/NSStepperTouchBarItem.h>
|
||||
#import <AppKit/NSStepper.h>
|
||||
#import <AppKit/NSStepperCell.h>
|
||||
#import <AppKit/NSStoryboard.h>
|
||||
#import <AppKit/NSStoryboardSegue.h>
|
||||
#import <AppKit/NSSeguePerforming.h>
|
||||
#import <AppKit/NSSwitch.h>
|
||||
#import <AppKit/NSTableColumn.h>
|
||||
#import <AppKit/NSTableHeaderCell.h>
|
||||
|
|
55
Headers/AppKit/NSSeguePerforming.h
Normal file
55
Headers/AppKit/NSSeguePerforming.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* Definition of class NSSeguePerforming
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory Casamento
|
||||
Date: Mon Jan 20 16:53:17 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.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
|
||||
Library 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 _NSSeguePerforming_h_GNUSTEP_GUI_INCLUDE
|
||||
#define _NSSeguePerforming_h_GNUSTEP_GUI_INCLUDE
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <AppKit/NSStoryboardSegue.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@protocol NSSeguePerforming
|
||||
- (void)performSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender;
|
||||
|
||||
- (void)prepareForSegue: (NSStoryboardSegue *)segue
|
||||
sender: (id)sender;
|
||||
|
||||
- (BOOL)shouldPerformSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender;
|
||||
@end
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GS_API_MACOSX */
|
||||
|
||||
#endif /* _NSSeguePerforming_h_GNUSTEP_GUI_INCLUDE */
|
||||
|
77
Headers/AppKit/NSStoryboard.h
Normal file
77
Headers/AppKit/NSStoryboard.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* Definition of class NSStoryboard
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
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.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
|
||||
Library 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 _NSStoryboard_h_GNUSTEP_GUI_INCLUDE
|
||||
#define _NSStoryboard_h_GNUSTEP_GUI_INCLUDE
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@class NSString, NSBundle, NSMutableDictionary;
|
||||
|
||||
typedef NSString *NSStoryboardName;
|
||||
typedef NSString *NSStoryboardSceneIdentifier;
|
||||
|
||||
DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id);
|
||||
|
||||
@interface NSStoryboard : NSObject
|
||||
{
|
||||
id _transform;
|
||||
}
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST)
|
||||
+ (NSStoryboard *) mainStoryboard;
|
||||
#endif
|
||||
|
||||
+ (instancetype) storyboardWithName: (NSStoryboardName)name
|
||||
bundle: (NSBundle *)bundle;
|
||||
|
||||
- (id) instantiateInitialController;
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_15, GS_API_LATEST)
|
||||
- (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block;
|
||||
#endif
|
||||
|
||||
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier;
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_15, GS_API_LATEST)
|
||||
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
||||
creator: (NSStoryboardControllerCreator)block;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GS_API_MACOSX */
|
||||
|
||||
#endif /* _NSStoryboard_h_GNUSTEP_GUI_INCLUDE */
|
||||
|
74
Headers/AppKit/NSStoryboardSegue.h
Normal file
74
Headers/AppKit/NSStoryboardSegue.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* Definition of class NSStoryboardSegue
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory Casamento
|
||||
Date: Mon Jan 20 15:57:31 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.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
|
||||
Library 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 _NSStoryboardSegue_h_GNUSTEP_GUI_INCLUDE
|
||||
#define _NSStoryboardSegue_h_GNUSTEP_GUI_INCLUDE
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef NSString *NSStoryboardSegueIdentifier;
|
||||
|
||||
DEFINE_BLOCK_TYPE_NO_ARGS(GSStoryboardSeguePerformHandler, void);
|
||||
|
||||
@interface NSStoryboardSegue : NSObject
|
||||
{
|
||||
id _sourceController;
|
||||
id _destinationController;
|
||||
NSStoryboardSegueIdentifier _identifier;
|
||||
NSString *_kind;
|
||||
NSString *_relationship;
|
||||
GSStoryboardSeguePerformHandler _handler;
|
||||
}
|
||||
|
||||
- (id) sourceController;
|
||||
- (id) destinationController;
|
||||
- (NSStoryboardSegueIdentifier) identifier;
|
||||
|
||||
+ (instancetype) segueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
source: (id)sourceController
|
||||
destination: (id)destinationController
|
||||
performHandler: (GSStoryboardSeguePerformHandler)performHandler;
|
||||
|
||||
- (instancetype) initWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
source: (id)sourceController
|
||||
destination: (id)destinationController;
|
||||
|
||||
- (void) perform;
|
||||
|
||||
@end
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GS_API_MACOSX */
|
||||
|
||||
#endif /* _NSStoryboardSegue_h_GNUSTEP_GUI_INCLUDE */
|
||||
|
|
@ -28,12 +28,13 @@ Boston, MA 02110-1301, USA.
|
|||
|
||||
#import <AppKit/NSNibDeclarations.h>
|
||||
#import <AppKit/NSResponder.h>
|
||||
#import <AppKit/NSSeguePerforming.h>
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
|
||||
|
||||
@class NSArray, NSBundle, NSPointerArray, NSView;
|
||||
@class NSArray, NSBundle, NSPointerArray, NSView, NSMapTable, NSStoryboard;
|
||||
|
||||
@interface NSViewController : NSResponder
|
||||
@interface NSViewController : NSResponder <NSSeguePerforming>
|
||||
{
|
||||
@private
|
||||
NSString *_nibName;
|
||||
|
@ -45,6 +46,8 @@ Boston, MA 02110-1301, USA.
|
|||
NSPointerArray *_editors;
|
||||
id _autounbinder;
|
||||
NSString *_designNibBundleIdentifier;
|
||||
NSMapTable *_segueMap;
|
||||
NSStoryboard *_storyboard; // a weak reference to the origin storyboard.
|
||||
struct ___vcFlags
|
||||
{
|
||||
unsigned int nib_is_loaded:1;
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
@class NSView;
|
||||
@class NSWindowController;
|
||||
@class NSCachedImageRep;
|
||||
@class NSViewController;
|
||||
|
||||
@class GSWindowDecorationView;
|
||||
|
||||
|
@ -336,6 +337,14 @@ PACKAGE_SCOPE
|
|||
* Computing frame and content rectangles
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a window with the view of the specified viewController as it's
|
||||
* content view. The window is resizable, titled, closable, and miniaturizable.
|
||||
*/
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST)
|
||||
+ (instancetype) windowWithContentViewController: (NSViewController *)viewController;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the rectangle which would be used for the content view of
|
||||
* a window whose on-screen size and position is specified by aRect
|
||||
|
|
|
@ -29,13 +29,16 @@
|
|||
|
||||
#import <AppKit/NSNibDeclarations.h>
|
||||
#import <AppKit/NSResponder.h>
|
||||
#import <AppKit/NSSeguePerforming.h>
|
||||
|
||||
@class NSString;
|
||||
@class NSArray;
|
||||
@class NSWindow;
|
||||
@class NSDocument;
|
||||
@class NSMapTable;
|
||||
@class NSStoryboard;
|
||||
|
||||
@interface NSWindowController : NSResponder <NSCoding>
|
||||
@interface NSWindowController : NSResponder <NSCoding, NSSeguePerforming>
|
||||
{
|
||||
@private
|
||||
NSWindow *_window;
|
||||
|
@ -45,6 +48,8 @@
|
|||
NSDocument *_document;
|
||||
NSArray *_top_level_objects;
|
||||
id _owner;
|
||||
NSMapTable *_segueMap;
|
||||
NSStoryboard *_storyboard; // a weak reference to the origin storyboard
|
||||
struct ___wcFlags
|
||||
{
|
||||
unsigned int should_close_document:1;
|
||||
|
|
2
MISSING
2
MISSING
|
@ -27,8 +27,6 @@ MISSING HEADERS
|
|||
> NSSplitViewItem.h
|
||||
> NSStackView.h
|
||||
> NSStatusBarButton.h
|
||||
> NSStoryboard.h
|
||||
> NSStoryboardSegue.h
|
||||
> NSTabViewController.h
|
||||
> NSTableCellView.h
|
||||
> NSTableRowView.h
|
||||
|
|
|
@ -44,9 +44,18 @@
|
|||
#import "AppKit/NSView.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
#import "AppKit/DPSOperators.h"
|
||||
#import "AppKit/NSStoryboard.h"
|
||||
|
||||
char **NSArgv = NULL;
|
||||
|
||||
@interface NSStoryboard (Private)
|
||||
|
||||
+ (void) _setMainStoryboard: (NSStoryboard *)storyboard;
|
||||
- (void) _instantiateApplicationScene;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*
|
||||
* Main initialization routine for the GNUstep GUI Library Apps
|
||||
*/
|
||||
|
@ -85,6 +94,29 @@ NSApplicationMain(int argc, const char **argv)
|
|||
NSLog (_(@"Cannot load the main model file '%@'"), mainModelFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mainModelFile = [infoDict objectForKey: @"NSMainStoryboardFile"];
|
||||
if (mainModelFile != nil && [mainModelFile isEqual: @""] == NO)
|
||||
{
|
||||
NSStoryboard *storyboard = [NSStoryboard storyboardWithName: mainModelFile
|
||||
bundle: [NSBundle mainBundle]];
|
||||
if (storyboard == nil)
|
||||
{
|
||||
NSLog (_(@"Cannot load the main storyboard file '%@'"), mainModelFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSStoryboard _setMainStoryboard: storyboard];
|
||||
[storyboard _instantiateApplicationScene];
|
||||
[storyboard instantiateInitialController];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Storyboard is blank or nil, unable to load.");
|
||||
}
|
||||
}
|
||||
|
||||
RECREATE_AUTORELEASE_POOL(pool);
|
||||
|
||||
|
|
|
@ -162,6 +162,8 @@ NSSharingServicePickerToolbarItem.m \
|
|||
NSSharingServicePickerTouchBarItem.m \
|
||||
NSSliderTouchBarItem.m \
|
||||
NSStepperTouchBarItem.m \
|
||||
NSStoryboard.m \
|
||||
NSStoryboardSegue.m \
|
||||
NSMagnificationGestureRecognizer.m \
|
||||
NSMatrix.m \
|
||||
NSMenu.m \
|
||||
|
@ -321,6 +323,7 @@ GSToolTips.m \
|
|||
GSToolbarView.m \
|
||||
GSToolbarCustomizationPalette.m \
|
||||
GSStandardWindowDecorationView.m \
|
||||
GSStoryboardTransform.m \
|
||||
GSWindowDecorationView.m \
|
||||
GSPrinting.m \
|
||||
GSPrintOperation.m \
|
||||
|
@ -521,6 +524,9 @@ NSSplitView.h \
|
|||
NSStepper.h \
|
||||
NSStepperCell.h \
|
||||
NSStepperTouchBarItem.h \
|
||||
NSStoryboard.h \
|
||||
NSStoryboardSegue.h \
|
||||
NSSeguePerforming.h \
|
||||
NSStringDrawing.h \
|
||||
NSStatusBar.h \
|
||||
NSStatusItem.h \
|
||||
|
|
115
Source/GSStoryboardTransform.h
Normal file
115
Source/GSStoryboardTransform.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* 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;
|
||||
@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;
|
||||
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;
|
||||
|
||||
- (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 */
|
793
Source/GSStoryboardTransform.m
Normal file
793
Source/GSStoryboardTransform.m
Normal file
|
@ -0,0 +1,793 @@
|
|||
/* 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;
|
||||
- (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);
|
||||
}
|
||||
|
||||
- (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(_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 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"]];
|
||||
}
|
||||
}
|
||||
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]];
|
||||
|
||||
[result addObject: xmlClassName];
|
||||
}
|
||||
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
|
||||
{
|
||||
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];
|
||||
|
||||
[sbproxy addAttribute: pselector];
|
||||
[sbproxy addAttribute: ptarget];
|
||||
[sbproxy addAttribute: pident];
|
||||
[sbproxy addAttribute: psegueIdent];
|
||||
[sbproxy addAttribute: psender];
|
||||
[sbproxy addAttribute: pkind];
|
||||
|
||||
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];
|
||||
[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 *ident = [attr stringValue];
|
||||
if (ident == nil)
|
||||
{
|
||||
ident = [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
|
||||
// Create proxy object to invoke methods on the window controller
|
||||
NSXMLElement *sbproxy = [self createStoryboardProxyElementWithSelector: @"doAction:"
|
||||
target: dst
|
||||
segueIdentifier: ident
|
||||
sender: src
|
||||
kind: kind];
|
||||
|
||||
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];
|
||||
|
||||
// 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)
|
||||
{
|
||||
return; // don't processed the document again
|
||||
}
|
||||
else // Get the controller... there is only one per scene.
|
||||
{
|
||||
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
|
265
Source/NSStoryboard.m
Normal file
265
Source/NSStoryboard.m
Normal file
|
@ -0,0 +1,265 @@
|
|||
/* Implementation of class NSStoryboard
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSBundle.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSXMLDocument.h>
|
||||
#import <Foundation/NSXMLElement.h>
|
||||
#import <Foundation/NSXMLNode.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSUUID.h>
|
||||
#import <Foundation/NSException.h>
|
||||
|
||||
#import "AppKit/NSApplication.h"
|
||||
#import "AppKit/NSNib.h"
|
||||
#import "AppKit/NSStoryboard.h"
|
||||
#import "AppKit/NSWindowController.h"
|
||||
#import "AppKit/NSViewController.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
#import "AppKit/NSNibDeclarations.h"
|
||||
|
||||
#import "GNUstepGUI/GSModelLoaderFactory.h"
|
||||
#import "GSStoryboardTransform.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
|
||||
static NSStoryboard *__mainStoryboard = nil;
|
||||
|
||||
// The storyboard needs to set this information on controllers...
|
||||
@interface NSWindowController (__StoryboardPrivate__)
|
||||
- (void) _setOwner: (id)owner;
|
||||
- (void) _setTopLevelObjects: (NSArray *)array;
|
||||
- (void) _setSegueMap: (NSMapTable *)map;
|
||||
- (void) _setStoryboard: (NSStoryboard *)storyboard;
|
||||
@end
|
||||
|
||||
@interface NSViewController (__StoryboardPrivate__)
|
||||
- (void) _setTopLevelObjects: (NSArray *)array;
|
||||
- (void) _setSegueMap: (NSMapTable *)map;
|
||||
- (void) _setStoryboard: (NSStoryboard *)storyboard;
|
||||
@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);
|
||||
}
|
||||
|
||||
- (void) _setStoryboard: (NSStoryboard *)storyboard
|
||||
{
|
||||
_storyboard = storyboard;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSViewController (__StoryboardPrivate__)
|
||||
- (void) _setTopLevelObjects: (NSArray *)array
|
||||
{
|
||||
_topLevelObjects = array;
|
||||
}
|
||||
|
||||
- (void) _setSegueMap: (NSMapTable *)map
|
||||
{
|
||||
ASSIGN(_segueMap, map);
|
||||
}
|
||||
|
||||
- (void) _setStoryboard: (NSStoryboard *)storyboard
|
||||
{
|
||||
_storyboard = storyboard;
|
||||
}
|
||||
@end
|
||||
// end private methods...
|
||||
|
||||
@implementation NSStoryboard
|
||||
|
||||
// Private instance methods...
|
||||
- (id) initWithName: (NSStoryboardName)name
|
||||
bundle: (NSBundle *)bundle
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
NSString *path = [bundle pathForResource: name
|
||||
ofType: @"storyboard"];
|
||||
NSData *data = [NSData dataWithContentsOfFile: path];
|
||||
_transform = [[GSStoryboardTransform alloc] initWithData: data];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Class methods...
|
||||
+ (void) _setMainStoryboard: (NSStoryboard *)storyboard // private, only called from NSApplicationMain()
|
||||
{
|
||||
if (__mainStoryboard == nil)
|
||||
{
|
||||
ASSIGN(__mainStoryboard, storyboard);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSStoryboard *) mainStoryboard
|
||||
{
|
||||
return __mainStoryboard;
|
||||
}
|
||||
|
||||
+ (instancetype) storyboardWithName: (NSStoryboardName)name
|
||||
bundle: (NSBundle *)bundle
|
||||
{
|
||||
return AUTORELEASE([[NSStoryboard alloc] initWithName: name
|
||||
bundle: bundle]);
|
||||
}
|
||||
|
||||
// Instance methods...
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_transform);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) _instantiateApplicationScene
|
||||
{
|
||||
[self instantiateControllerWithIdentifier: @"application"];
|
||||
}
|
||||
|
||||
- (id) instantiateInitialController
|
||||
{
|
||||
return [self instantiateInitialControllerWithCreator: nil];
|
||||
}
|
||||
|
||||
- (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block
|
||||
{
|
||||
return [self instantiateControllerWithIdentifier: [_transform initialViewControllerId]
|
||||
creator: block];
|
||||
}
|
||||
|
||||
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
||||
{
|
||||
return [self instantiateControllerWithIdentifier: identifier
|
||||
creator: nil];
|
||||
}
|
||||
|
||||
- (id) instantiateControllerWithIdentifier: (NSStoryboardSceneIdentifier)identifier
|
||||
creator: (NSStoryboardControllerCreator)block
|
||||
{
|
||||
id result = nil;
|
||||
NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5];
|
||||
NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects,
|
||||
NSNibTopLevelObjects,
|
||||
NSApp,
|
||||
NSNibOwner,
|
||||
nil];
|
||||
GSModelLoader *loader = [GSModelLoaderFactory modelLoaderForFileType: @"xib"];
|
||||
BOOL success = [loader loadModelData: [_transform dataForIdentifier: identifier]
|
||||
externalNameTable: table
|
||||
withZone: [self zone]];
|
||||
|
||||
if (success)
|
||||
{
|
||||
NSMutableArray *seguesToPerform = [NSMutableArray array];
|
||||
NSMapTable *segueMap = [_transform segueMapForIdentifier: identifier];
|
||||
NSWindowController *wc = nil;
|
||||
NSViewController *vc = nil;
|
||||
NSWindow *w = nil;
|
||||
|
||||
FOR_IN(id, o, topLevelObjects)
|
||||
if ([o isKindOfClass: [NSWindowController class]])
|
||||
{
|
||||
wc = (NSWindowController *)o;
|
||||
[wc _setSegueMap: segueMap];
|
||||
[wc _setTopLevelObjects: topLevelObjects];
|
||||
[wc _setStoryboard: self];
|
||||
[wc _setOwner: NSApp];
|
||||
result = o;
|
||||
}
|
||||
else if ([o isKindOfClass: [NSViewController class]])
|
||||
{
|
||||
vc = (NSViewController *)o;
|
||||
[vc _setSegueMap: segueMap];
|
||||
[vc _setTopLevelObjects: topLevelObjects];
|
||||
[vc _setStoryboard: self];
|
||||
result = o;
|
||||
}
|
||||
else if ([o isKindOfClass: [NSWindow class]])
|
||||
{
|
||||
w = (NSWindow *)o;
|
||||
}
|
||||
else if ([o isKindOfClass: [NSControllerPlaceholder class]])
|
||||
{
|
||||
NSControllerPlaceholder *ph = (NSControllerPlaceholder *)o;
|
||||
result = [ph instantiate];
|
||||
}
|
||||
END_FOR_IN(topLevelObjects);
|
||||
|
||||
// Process action proxies after so we know we have the windowController...
|
||||
FOR_IN(id, o, topLevelObjects)
|
||||
if ([o isKindOfClass: [NSStoryboardSeguePerformAction class]])
|
||||
{
|
||||
NSStoryboardSeguePerformAction *ssa = (NSStoryboardSeguePerformAction *)o;
|
||||
NSMapTable *mapTable = [_transform segueMapForIdentifier: identifier];
|
||||
NSStoryboardSegue *ss = [mapTable objectForKey: [ssa identifier]];
|
||||
|
||||
[ssa setSender: result]; // resolve controller here...
|
||||
[ssa setStoryboardSegue: ss];
|
||||
[ssa setStoryboard: self];
|
||||
if ([[ssa kind] isEqualToString: @"relationship"]) // if it is a relationship, perform immediately
|
||||
{
|
||||
[seguesToPerform addObject: ssa];
|
||||
}
|
||||
}
|
||||
END_FOR_IN(topLevelObjects);
|
||||
|
||||
// Depending on which kind of controller we have, do the correct thing....
|
||||
if (w != nil && wc != nil)
|
||||
{
|
||||
[wc setWindow: w];
|
||||
}
|
||||
|
||||
// perform segues after all is initialized.
|
||||
FOR_IN(NSStoryboardSeguePerformAction*, ssa, seguesToPerform)
|
||||
[ssa doAction: result]; // this will, as far as I know, only happen with window controllers, to set content.
|
||||
END_FOR_IN(seguesToPerform);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Couldn't load controller scene identifier = %@", identifier];
|
||||
}
|
||||
|
||||
// Execute the block if it's set...
|
||||
if (block != nil)
|
||||
{
|
||||
CALL_BLOCK(block, self);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@end
|
153
Source/NSStoryboardSegue.m
Normal file
153
Source/NSStoryboardSegue.m
Normal file
|
@ -0,0 +1,153 @@
|
|||
/* Implementation of class NSStoryboardSegue
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
By: Gregory Casamento
|
||||
Date: Mon Jan 20 15:57:31 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import "AppKit/NSStoryboardSegue.h"
|
||||
#import "AppKit/NSWindowController.h"
|
||||
#import "AppKit/NSViewController.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
#import "AppKit/NSApplication.h"
|
||||
|
||||
@implementation NSStoryboardSegue
|
||||
|
||||
- (id) sourceController
|
||||
{
|
||||
return _sourceController;
|
||||
}
|
||||
|
||||
- (id) destinationController
|
||||
{
|
||||
return _destinationController;
|
||||
}
|
||||
|
||||
- (NSStoryboardSegueIdentifier)identifier
|
||||
{
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
- (void) _setHandler: (GSStoryboardSeguePerformHandler)handler
|
||||
{
|
||||
ASSIGN(_handler, handler);
|
||||
}
|
||||
|
||||
- (void) _setDestinationController: (id)controller
|
||||
{
|
||||
_destinationController = controller;
|
||||
}
|
||||
|
||||
- (void) _setSourceController: (id)controller
|
||||
{
|
||||
_sourceController = controller;
|
||||
}
|
||||
|
||||
+ (instancetype) segueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
source: (id)sourceController
|
||||
destination: (id)destinationController
|
||||
performHandler: (GSStoryboardSeguePerformHandler)performHandler
|
||||
{
|
||||
NSStoryboardSegue *segue = [[NSStoryboardSegue alloc] initWithIdentifier: identifier
|
||||
source: sourceController
|
||||
destination: destinationController];
|
||||
AUTORELEASE(segue);
|
||||
[segue _setHandler: performHandler];
|
||||
|
||||
return segue;
|
||||
}
|
||||
|
||||
- (instancetype) initWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
source: (id)sourceController
|
||||
destination: (id)destinationController
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
ASSIGN(_sourceController, sourceController);
|
||||
ASSIGN(_destinationController, destinationController);
|
||||
ASSIGN(_identifier, identifier);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_sourceController);
|
||||
RELEASE(_destinationController);
|
||||
RELEASE(_identifier);
|
||||
RELEASE(_kind);
|
||||
RELEASE(_relationship);
|
||||
RELEASE(_handler);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) perform
|
||||
{
|
||||
// Perform segue based on it's kind...
|
||||
if ([_kind isEqualToString: @"relationship"])
|
||||
{
|
||||
NSWindow *w = [_sourceController window];
|
||||
NSView *v = [_destinationController view];
|
||||
[w setContentView: v];
|
||||
[w setTitle: [_destinationController title]];
|
||||
[_sourceController showWindow: self];
|
||||
}
|
||||
else if ([_kind isEqualToString: @"modal"])
|
||||
{
|
||||
NSWindow *w = nil;
|
||||
if ([_destinationController isKindOfClass: [NSWindowController class]])
|
||||
{
|
||||
w = [_destinationController window];
|
||||
}
|
||||
else
|
||||
{
|
||||
w = [NSWindow windowWithContentViewController: _destinationController];
|
||||
[w setTitle: [_destinationController title]];
|
||||
}
|
||||
RETAIN(w);
|
||||
[w center];
|
||||
[NSApp runModalForWindow: w];
|
||||
}
|
||||
else if ([_kind isEqualToString: @"show"])
|
||||
{
|
||||
if ([_destinationController isKindOfClass: [NSWindowController class]])
|
||||
{
|
||||
[_destinationController showWindow: _sourceController];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSWindow *w = [NSWindow windowWithContentViewController: _destinationController];
|
||||
[w setTitle: [_destinationController title]];
|
||||
[w center];
|
||||
[w orderFrontRegardless];
|
||||
RETAIN(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (_handler != nil)
|
||||
{
|
||||
CALL_BLOCK_NO_ARGS(_handler);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -29,11 +29,15 @@
|
|||
#import <Foundation/NSBundle.h>
|
||||
#import <Foundation/NSKeyedArchiver.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSMapTable.h>
|
||||
|
||||
#import "AppKit/NSKeyValueBinding.h"
|
||||
#import "AppKit/NSNib.h"
|
||||
#import "AppKit/NSView.h"
|
||||
#import "AppKit/NSViewController.h"
|
||||
|
||||
#import "AppKit/NSStoryboardSegue.h"
|
||||
#import "AppKit/NSStoryboard.h"
|
||||
#import "AppKit/NSWindowController.h"
|
||||
|
||||
@implementation NSViewController
|
||||
|
||||
|
@ -46,7 +50,7 @@
|
|||
|
||||
ASSIGN(_nibName, nibNameOrNil);
|
||||
ASSIGN(_nibBundle, nibBundleOrNil);
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -63,7 +67,8 @@
|
|||
DESTROY(_autounbinder);
|
||||
DESTROY(_designNibBundleIdentifier);
|
||||
DESTROY(view);
|
||||
|
||||
DESTROY(_segueMap);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -151,6 +156,7 @@
|
|||
return nil;
|
||||
}
|
||||
|
||||
_segueMap = RETAIN([NSMapTable strongToWeakObjectsMapTable]);
|
||||
if ([aDecoder allowsKeyedCoding])
|
||||
{
|
||||
NSView *aView = [aDecoder decodeObjectForKey: @"NSView"];
|
||||
|
@ -179,6 +185,29 @@
|
|||
[aCoder encodeObject: [self view]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NSSeguePerforming methods...
|
||||
- (void)performSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender
|
||||
{
|
||||
NSStoryboardSegue *segue = [_segueMap objectForKey: identifier];
|
||||
[self prepareForSegue: segue
|
||||
sender: sender];
|
||||
[segue perform];
|
||||
}
|
||||
|
||||
- (void)prepareForSegue: (NSStoryboardSegue *)segue
|
||||
sender: (id)sender
|
||||
{
|
||||
// do nothing in base class method...
|
||||
}
|
||||
|
||||
- (BOOL)shouldPerformSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSViewController (NSEditorRegistration)
|
||||
|
@ -227,5 +256,5 @@
|
|||
// Loop over all elements of _editors
|
||||
[self notImplemented: _cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#import "AppKit/NSTextField.h"
|
||||
#import "AppKit/NSTextFieldCell.h"
|
||||
#import "AppKit/NSView.h"
|
||||
#import "AppKit/NSViewController.h"
|
||||
#import "AppKit/NSWindow.h"
|
||||
#import "AppKit/NSWindowController.h"
|
||||
#import "AppKit/PSOperators.h"
|
||||
|
@ -723,6 +724,25 @@ static NSNotificationCenter *nc = nil;
|
|||
}
|
||||
}
|
||||
|
||||
+ (instancetype) windowWithContentViewController: (NSViewController *)viewController
|
||||
{
|
||||
NSView *view = [viewController view];
|
||||
NSRect frame = [view frame];
|
||||
NSString *title = [viewController title];
|
||||
NSUInteger style = NSTitledWindowMask |
|
||||
NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask |
|
||||
NSResizableWindowMask;
|
||||
NSWindow *window = [[self alloc] initWithContentRect: frame
|
||||
styleMask: style
|
||||
backing: NSBackingStoreBuffered
|
||||
defer: NO];
|
||||
[window setTitle: title];
|
||||
[window setContentView: view];
|
||||
AUTORELEASE(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
+ (void) removeFrameUsingName: (NSString*)name
|
||||
{
|
||||
if (name != nil)
|
||||
|
|
|
@ -33,11 +33,16 @@
|
|||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSNotification.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSMapTable.h>
|
||||
|
||||
#import "AppKit/NSNib.h"
|
||||
#import "AppKit/NSNibLoading.h"
|
||||
#import "AppKit/NSPanel.h"
|
||||
#import "AppKit/NSWindowController.h"
|
||||
#import "AppKit/NSStoryboardSegue.h"
|
||||
#import "AppKit/NSStoryboard.h"
|
||||
#import "AppKit/NSViewController.h"
|
||||
|
||||
#import "NSDocumentFrameworkPrivate.h"
|
||||
|
||||
@implementation NSWindowController
|
||||
|
@ -137,6 +142,7 @@
|
|||
RELEASE(_window_nib_path);
|
||||
RELEASE(_window_frame_autosave_name);
|
||||
RELEASE(_top_level_objects);
|
||||
RELEASE(_segueMap);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -319,7 +325,7 @@
|
|||
return _window;
|
||||
}
|
||||
|
||||
/** Sets the window that this controller managers to aWindow. The old
|
||||
/** Sets the window that this controller manages to aWindow. The old
|
||||
window is released. */
|
||||
- (void) setWindow: (NSWindow *)aWindow
|
||||
{
|
||||
|
@ -527,6 +533,7 @@
|
|||
if (!self)
|
||||
return nil;
|
||||
|
||||
_segueMap = nil;
|
||||
ASSIGN(_window_frame_autosave_name, @"");
|
||||
_wcFlags.should_cascade = YES;
|
||||
//_wcFlags.should_close_document = NO;
|
||||
|
@ -550,4 +557,26 @@
|
|||
[super encodeWithCoder: coder];
|
||||
}
|
||||
|
||||
// NSSeguePerforming methods...
|
||||
- (void)performSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender
|
||||
{
|
||||
NSStoryboardSegue *segue = [_segueMap objectForKey: identifier];
|
||||
[self prepareForSegue: segue
|
||||
sender: sender];
|
||||
[segue perform];
|
||||
}
|
||||
|
||||
- (void)prepareForSegue: (NSStoryboardSegue *)segue
|
||||
sender: (id)sender
|
||||
{
|
||||
// do nothing in base class method...
|
||||
}
|
||||
|
||||
- (BOOL)shouldPerformSegueWithIdentifier: (NSStoryboardSegueIdentifier)identifier
|
||||
sender: (id)sender
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in a new issue