diff --git a/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h b/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h index d5fa04985..4c9e3c78e 100644 --- a/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h +++ b/Headers/Additions/GNUstepGUI/GSXibKeyedUnarchiver.h @@ -48,6 +48,8 @@ APPKIT_EXPORT_CLASS + (BOOL) checkXib5: (NSData *)data; ++ (BOOL) checkStoryboard: (NSData *)data; + + (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data; - (void) _initCommon; diff --git a/Headers/Additions/GNUstepGUI/GSXibLoading.h b/Headers/Additions/GNUstepGUI/GSXibLoading.h index 346b929c5..3d8da3e5c 100644 --- a/Headers/Additions/GNUstepGUI/GSXibLoading.h +++ b/Headers/Additions/GNUstepGUI/GSXibLoading.h @@ -33,6 +33,7 @@ #import #import + #import "GNUstepGUI/GSXibKeyedUnarchiver.h" @class NSString, NSDictionary, NSArray, NSMutableDictionary, NSMutableArray; @@ -42,11 +43,13 @@ // Hack: This allows the class name FirstResponder in NSCustomObject and // correctly returns nil as the corresponding object. +APPKIT_EXPORT_CLASS @interface FirstResponder: NSObject { } @end +APPKIT_EXPORT_CLASS @interface IBClassDescriptionSource: NSObject { NSString *majorKey; @@ -54,6 +57,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBPartialClassDescription: NSObject { NSString *className; @@ -64,12 +68,14 @@ } @end +APPKIT_EXPORT_CLASS @interface IBClassDescriber: NSObject { NSMutableArray *referencedPartialClassDescriptions; } @end +APPKIT_EXPORT_CLASS @interface IBConnection: NSObject { NSString *label; @@ -84,23 +90,27 @@ - (void) establishConnection; @end +APPKIT_EXPORT_CLASS @interface IBActionConnection: IBConnection { NSString *trigger; } @end +APPKIT_EXPORT_CLASS @interface IBOutletConnection: IBConnection { } @end +APPKIT_EXPORT_CLASS @interface IBBindingConnection: IBConnection { NSNibBindingConnector *connector; } @end +APPKIT_EXPORT_CLASS @interface IBConnectionRecord: NSObject { IBConnection *connection; @@ -109,6 +119,7 @@ - (IBConnection *) connection; @end +APPKIT_EXPORT_CLASS @interface IBToolTipAttribute: NSObject { NSString *name; @@ -117,6 +128,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBInitialTabViewItemAttribute: NSObject { NSString *name; @@ -125,6 +137,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBObjectRecord: NSObject { id objectID; @@ -137,6 +150,7 @@ - (id) objectID; @end +APPKIT_EXPORT_CLASS @interface IBMutableOrderedSet: NSObject { NSArray *orderedObjects; @@ -145,6 +159,7 @@ - (id) objectWithObjectID: (id)objID; @end +APPKIT_EXPORT_CLASS @interface IBObjectContainer: NSObject { NSMutableArray *connectionRecords; @@ -196,4 +211,11 @@ APPKIT_EXPORT_CLASS @end +APPKIT_EXPORT_CLASS +@interface IBScenesContaienr : NSObject +{ + IBMutableOrderedSet *_sceneRecords; +} +@end + #endif diff --git a/Headers/AppKit/NSStoryboard.h b/Headers/AppKit/NSStoryboard.h index 0772338f3..4e9e65798 100644 --- a/Headers/AppKit/NSStoryboard.h +++ b/Headers/AppKit/NSStoryboard.h @@ -33,7 +33,10 @@ extern "C" { #endif -@class NSString, NSBundle, NSMutableDictionary; +@class NSBundle; +@class NSData; +@class NSMutableDictionary; +@class NSString; typedef NSString *NSStoryboardName; typedef NSString *NSStoryboardSceneIdentifier; @@ -43,7 +46,8 @@ DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id); APPKIT_EXPORT_CLASS @interface NSStoryboard : NSObject { - id _transform; + NSData *_data; + NSMutableDictionary *_scenes; } #if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST) diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 51fb140bb..550ca6ff5 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -309,7 +309,9 @@ GSDisplayServer.m \ GSHelpManagerPanel.m \ GSInfoPanel.m \ GSMemoryPanel.m \ +GSScene.m \ GSSlideView.m \ +GSStoryboardLoader.m \ GSTextStorage.m \ GSTrackingRect.m \ GSServicesManager.m \ @@ -332,6 +334,7 @@ GSGormLoading.m \ GSIconManager.m \ GSImageMagickImageRep.m \ GSNibLoading.m \ +GSScenes.m \ GSTheme.m \ GSThemeDrawing.m \ GSThemeInspector.m \ @@ -346,7 +349,7 @@ GSToolTips.m \ GSToolbarView.m \ GSToolbarCustomizationPalette.m \ GSStandardWindowDecorationView.m \ -GSStoryboardTransform.m \ +GSStoryboardKeyedUnarchiver.m \ GSWindowDecorationView.m \ GSPrinting.m \ GSPrintOperation.m \ diff --git a/Source/GSModelLoaderFactory.m b/Source/GSModelLoaderFactory.m index 4d2857f5b..5d654de58 100644 --- a/Source/GSModelLoaderFactory.m +++ b/Source/GSModelLoaderFactory.m @@ -50,7 +50,7 @@ + (float) priority { - return 0.0; + return FLT_MAX; } - (BOOL) loadModelData: (NSData *)data diff --git a/Source/GSScene.h b/Source/GSScene.h new file mode 100644 index 000000000..e39815445 --- /dev/null +++ b/Source/GSScene.h @@ -0,0 +1,60 @@ +/* Interface of class GSScene + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 12-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#ifndef _GSScene_h_GNUSTEP_GUI_INCLUDE +#define _GSScene_h_GNUSTEP_GUI_INCLUDE + +#import +#import + +#if defined(__cplusplus) +extern "C" { +#endif + +@class NSMutableArray; +@class NSString; + +@interface GSScene : NSObject +{ + NSString *_sceneID; + NSMutableArray *_objects; + NSPoint _canvasLocation; +} + +- (NSString *) sceneID; +- (void) setSceneID: (NSString *)sceneID; + +- (NSMutableArray *) objects; +- (void) setObjects: (NSMutableArray *)objects; + +- (NSPoint) canvasLocation; +- (void) setCanvasLocation: (NSPoint)point; + +@end + +#if defined(__cplusplus) +} +#endif + +#endif /* _GSScene_h_GNUSTEP_GUI_INCLUDE */ diff --git a/Source/GSScene.m b/Source/GSScene.m new file mode 100644 index 000000000..dd0e2821d --- /dev/null +++ b/Source/GSScene.m @@ -0,0 +1,123 @@ +/* Implementation of class GSScene + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 12-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#import + +#import "GSScene.h" + +@implementation GSScene + +- (instancetype) init +{ + self = [super init]; + if (self != nil) + { + _sceneID = nil; + _objects = nil; + _canvasLocation = NSMakePoint(0.0, 0.0); + } + return self; +} + +- (void) dealloc +{ + RELEASE(_sceneID); + RELEASE(_objects); + [super dealloc]; +} + +- (NSString *) sceneID +{ + return _sceneID; +} + +- (void) setSceneID: (NSString *)sceneID +{ + ASSIGN(_sceneID, sceneID); +} + +- (NSMutableArray *) objects +{ + return _objects; +} + +- (void) setObjects: (NSMutableArray *)objects +{ + ASSIGN(_objects, objects); +} + +- (NSPoint) canvasLocation +{ + return _canvasLocation; +} + +- (void) setCanvasLocation: (NSPoint)point +{ + _canvasLocation = point; +} + +// NSCoding + +- (instancetype) initWithCoder: (NSCoder *)coder +{ + NSLog(@"Decoding GSScene"); + if ([coder allowsKeyedCoding]) + { + if ([coder containsValueForKey: @"NSSceneID"]) + { + [self setSceneID: [coder decodeObjectForKey: @"NSSceneID"]]; + } + + if ([coder containsValueForKey: @"NSObjects"]) + { + [self setObjects: [coder decodeObjectForKey: @"NSObjects"]]; + } + + if ([coder containsValueForKey: @"NSCanvasLocation"]) + { + [self setCanvasLocation: [coder decodePointForKey: @"NSCanvasLocation"]]; + } + } + return self; +} + +- (void) encodeWithCoder: (NSCoder *)coder +{ +} + +// NSCopying + +- (id) copyWithZone: (NSZone *)zone +{ + GSScene *scene = [[GSScene allocWithZone: zone] init]; + + [scene setSceneID: [self sceneID]]; + [scene setObjects: [self objects]]; + [scene setCanvasLocation: [self canvasLocation]]; + + return scene; +} + +@end + diff --git a/Source/GSScenes.h b/Source/GSScenes.h new file mode 100644 index 000000000..373386e5d --- /dev/null +++ b/Source/GSScenes.h @@ -0,0 +1,50 @@ +/* Interface of class GSScenes + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 18-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#ifndef _GSScenes_h_GNUSTEP_GUI_INCLUDE +#define _GSScenes_h_GNUSTEP_GUI_INCLUDE + +#import +#import + +#if defined(__cplusplus) +extern "C" { +#endif + +@interface GSScenes : NSObject +{ + NSMutableArray *_scenes; +} + +- (NSMutableArray *) scenes; +- (void) setScenes: (NSMutableArray *)scenes; + +@end + +#if defined(__cplusplus) +} +#endif + +#endif /* _GSScenes_h_GNUSTEP_GUI_INCLUDE */ + diff --git a/Source/GSScenes.m b/Source/GSScenes.m new file mode 100644 index 000000000..e7e9d454e --- /dev/null +++ b/Source/GSScenes.m @@ -0,0 +1,82 @@ +/* Implementation of class GSScenes + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 18-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#import "GSScenes.h" + +@implementation GSScenes + +- (instancetype) init +{ + self = [super init]; + if (self != nil) + { + _scenes = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void) dealloc +{ + RELEASE(_scenes); + [super dealloc]; +} + +- (NSMutableArray *)scenes +{ + return _scenes; +} + +- (void) setScenes: (NSMutableArray *)scenes +{ + ASSIGN(_scenes, scenes); +} + +- (id) initWithCoder: (NSCoder *)coder +{ + NSLog(@"GSScenes..."); + if ([coder allowsKeyedCoding] == YES) + { + if ([coder containsValueForKey: @"GSScenes"]) + { + [self setScenes: [coder decodeObjectForKey: @"GSScenes"]]; + } + } + return self; +} + +- (void) encodeWithCoder: (NSCoder *)coder +{ +} + +- (id) copyWithZone: (NSZone *)zone +{ + GSScenes *scenes = [[GSScenes allocWithZone: zone] init]; + + [scenes setScenes: [[self scenes] copyWithZone: zone]]; + + return scenes; +} + +@end + diff --git a/Source/GSStoryboardKeyedUnarchiver.h b/Source/GSStoryboardKeyedUnarchiver.h new file mode 100644 index 000000000..e03e3fa44 --- /dev/null +++ b/Source/GSStoryboardKeyedUnarchiver.h @@ -0,0 +1,45 @@ +/* Definition of class GSStoryboardKeyedUnarchiver + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 14-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#ifndef _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE +#define _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE + +#import "GSXib5KeyedUnarchiver.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +@interface GSStoryboardKeyedUnarchiver : GSXib5KeyedUnarchiver +{ + GSXibElement *_scenes; +} +@end + +#if defined(__cplusplus) +} +#endif + +#endif /* _GSStoryboardKeyedUnarchiver_h_GNUSTEP_GUI_INCLUDE */ + diff --git a/Source/GSStoryboardKeyedUnarchiver.m b/Source/GSStoryboardKeyedUnarchiver.m new file mode 100644 index 000000000..f2974a410 --- /dev/null +++ b/Source/GSStoryboardKeyedUnarchiver.m @@ -0,0 +1,44 @@ +/* Implementation of class GSStoryboardKeyedUnarchiver + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 14-05-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#import "GNUstepGUI/GSXibElement.h" +#import "GNUstepGUI/GSNibLoading.h" + +#import "GSStoryboardKeyedUnarchiver.h" + +@implementation GSStoryboardKeyedUnarchiver + +- (void) _initCommon +{ + [super _initCommon]; + + _scenes = [[GSXibElement alloc] initWithType: @"array" + andAttributes: [NSDictionary dictionaryWithObjectsAndKeys: + @"scenes", @"key", + nil]]; + +} + +@end + diff --git a/Source/GSStoryboardLoader.m b/Source/GSStoryboardLoader.m new file mode 100644 index 000000000..d7c97c484 --- /dev/null +++ b/Source/GSStoryboardLoader.m @@ -0,0 +1,258 @@ +/* GSXibLoader + + Xib (Cocoa XML) model loader + + Copyright (C) 2010, 2011 Free Software Foundation, Inc. + + Written by: Fred Kiefer + Created: March 2010 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110 USA. +*/ + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "AppKit/NSApplication.h" +#import "AppKit/NSMenu.h" +#import "AppKit/NSNib.h" + +#import "GNUstepGUI/GSModelLoaderFactory.h" +#import "GNUstepGUI/GSNibLoading.h" +#import "GNUstepGUI/GSXibLoading.h" +#import "GNUstepGUI/GSXibKeyedUnarchiver.h" + +#import + +@interface NSApplication (StorybardCompatibility) +- (void) _setMainMenu: (NSMenu*)aMenu; +@end + +@interface NSMenu (StoryboardCompatibility) +- (BOOL) _isMainMenu; +@end + +@implementation NSMenu (StoryboardCompatibility) + +- (BOOL) _isMainMenu +{ + if (_name) + return [_name isEqualToString:@"_NSMainMenu"]; + return NO; +} + +@end + +@interface GSStoryboardLoader: GSModelLoader +{ +} +@end + +@implementation GSStoryboardLoader + ++ (BOOL) canReadData: (NSData *)theData +{ + char *header = calloc(1024, sizeof(char)); + + if (header != NULL) + { + [theData getBytes: header + length: 1024]; + + NSString *hdr = [[NSString alloc] initWithBytes: header + length: 1024 + encoding: NSUTF8StringEncoding]; + AUTORELEASE(hdr); + if ([hdr containsString: @"Cocoa.Storyboard.XIB"]) + { + free(header); + return YES; + } + + free(header); + } + + return NO; +} + ++ (NSString*) type +{ + return @"storyboard"; +} + ++ (float) priority +{ + return 5.0; +} + +- (void) awake: (NSArray *)rootObjects + withContext: (NSDictionary *)context +{ + NSMutableArray *topLevelObjects = [context objectForKey: NSNibTopLevelObjects]; + id owner = [context objectForKey: NSNibOwner]; + NSEnumerator *en; + id obj; + NSUInteger index = 0; + + if ([rootObjects count] == 0) + { + NSWarnMLog(@"No root objects in XIB!"); + return; + } + + NSDebugLLog(@"Storyboard", @"First object %@", [rootObjects objectAtIndex: 0]); + NSDebugLLog(@"Storyboard", @"Second object %@", [rootObjects objectAtIndex: 1]); + NSDebugLLog(@"Storyboard", @"Third object %@", [rootObjects objectAtIndex: 2]); + // Use the owner as first root object + [(NSCustomObject*)[rootObjects objectAtIndex: 0] setRealObject: owner]; + + en = [rootObjects objectEnumerator]; + while ((obj = [en nextObject]) != nil) + { + index++; + + if ([obj respondsToSelector: @selector(nibInstantiate)]) + { + obj = [obj nibInstantiate]; + } + + // IGNORE file's owner, first responder and NSApplication instances... + if ((obj != nil) && (index > 3)) + { + [topLevelObjects addObject: obj]; + // All top level objects must be released by the caller to avoid + // leaking, unless they are going to be released by other nib + // objects on behalf of the owner. + RETAIN(obj); + } + + if (([obj isKindOfClass: [NSMenu class]]) && + ([obj _isMainMenu])) + { + // add the menu... + [NSApp _setMainMenu: obj]; + } + } +} + +- (void) awake: (NSArray *)rootObjects + inContainer: (id)objects + withContext: (NSDictionary *)context +{ + [self awake: rootObjects withContext: context]; + + // Load connections and awaken objects + if ([objects respondsToSelector: @selector(nibInstantiate)]) + { + [objects nibInstantiate]; + } +} + +- (BOOL) loadModelData: (NSData *)data + externalNameTable: (NSDictionary *)context + withZone: (NSZone *)zone +{ + BOOL loaded = NO; + + NS_DURING + { + if (data != nil) + { + NSKeyedUnarchiver *unarchiver = [GSXibKeyedUnarchiver unarchiverForReadingWithData: data]; + + if (unarchiver != nil) + { + NSArray *rootObjects; + IBObjectContainer *objects; + IBScenesContainer *scenes; + + NSDebugLLog(@"Storyboard", @"Invoking unarchiver"); + [unarchiver setObjectZone: zone]; + rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; + objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; + scenes = [unarchiver decodeObjectForkey: @"IBDocument.Scenes"]; + + NSLog(@"root objects = %@", rootObjects); + NSLog(@"objects = %@", objects); + NSLog(@"scenes = %@", scenes) + + /* + [self awake: rootObjects + inContainer: objects + withContext: context]; + */ + loaded = YES; + } + else + { + NSLog(@"Could not instantiate Xib unarchiver/Unable to parse Storyboard."); + } + } + else + { + NSLog(@"Data passed to Storyboard loading method is nil."); + } + } + NS_HANDLER + { + NSLog(@"Exception occurred while loading model: %@",[localException reason]); + } + NS_ENDHANDLER + + if (loaded == NO) + { + NSLog(@"Failed to load Storyboard\n"); + } + + return loaded; +} + +- (NSData*) dataForFile: (NSString*)fileName +{ + NSFileManager *mgr = [NSFileManager defaultManager]; + BOOL isDir = NO; + + NSDebugLLog(@"Storyboard", @"Loading Storyboard `%@'...\n", fileName); + if ([mgr fileExistsAtPath: fileName isDirectory: &isDir]) + { + if (isDir == NO) + { + return [NSData dataWithContentsOfFile: fileName]; + } + else + { + NSLog(@"Storyboard file specified %@, is directory.", fileName); + } + } + else + { + NSLog(@"Storyboard file specified %@, could not be found.", fileName); + } + + return nil; +} + +@end diff --git a/Source/GSStoryboardTransform.h b/Source/GSStoryboardTransform.h deleted file mode 100644 index ed17a8359..000000000 --- a/Source/GSStoryboardTransform.h +++ /dev/null @@ -1,121 +0,0 @@ -/* Interface of class GSStoryboardTransform - Copyright (C) 2020 Free Software Foundation, Inc. - - By: Gregory John Casamento - Date: Sat 04 Jul 2020 03:48:15 PM EDT - - This file is part of the GNUstep Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110 USA. -*/ - -#ifndef _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE -#define _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE - -#import - -@class NSString; -@class NSMutableDictionary; -@class NSDictionary; -@class NSData; -@class NSMapTable; -@class NSXMLDocument; - -#if defined(__cplusplus) -extern "C" { -#endif - -@interface GSStoryboardTransform : NSObject -{ - NSMutableDictionary *_scenesMap; - NSMutableDictionary *_controllerMap; - NSMutableDictionary *_identifierToSegueMap; - NSString *_initialViewControllerId; - NSString *_applicationSceneId; -} - -- (instancetype) initWithData: (NSData *)data; - -- (NSString *) initialViewControllerId; -- (NSString *) applicationSceneId; - -- (NSData *) dataForIdentifier: (NSString *)identifier; -- (NSMapTable *) segueMapForIdentifier: (NSString *)identifier; - -- (void) processStoryboard: (NSXMLDocument *)storyboardXml; -- (void) processSegues: (NSXMLDocument *)xml - forControllerId: (NSString *)identifier; -@end - -// Private classes used when parsing the XIB generated by the transformer... -@interface NSStoryboardSeguePerformAction : NSObject -{ - id _target; - SEL _action; - id _sender; - NSString *_identifier; - NSString *_kind; - id _popoverAnchorView; - NSStoryboardSegue *_storyboardSegue; - NSStoryboard *_storyboard; -} - -- (id) target; -- (void) setTarget: (id)target; - -- (NSString *) selector; -- (void) setSelector: (NSString *)s; - -- (SEL) action; -- (void) setAction: (SEL)action; - -- (id) sender; -- (void) setSender: (id)sender; - -- (NSString *) identifier; -- (void) setIdentifier: (NSString *)identifier; - -- (NSString *) kind; -- (void) setKind: (NSString *)kind; - -- (void) setPopoverAnchorView: (id)view; -- (id) popoverAnchorView; - -- (NSStoryboard *) storyboard; -- (void) setStoryboard: (NSStoryboard *)storyboard; - -- (NSStoryboardSegue *) storyboardSegue; -- (void) setStoryboardSegue: (NSStoryboardSegue *)ss; - -- (IBAction) doAction: (id)sender; -@end - -@interface NSControllerPlaceholder : NSObject -{ - NSString *_storyboardName; -} - -- (NSString *) storyboardName; -- (void) setStoryboardName: (NSString *)name; - -- (id) instantiate; -@end - -#if defined(__cplusplus) -} -#endif - -#endif /* _GSStoryboardTransform_h_GNUSTEP_GUI_INCLUDE */ diff --git a/Source/GSStoryboardTransform.m b/Source/GSStoryboardTransform.m deleted file mode 100644 index befb07aa3..000000000 --- a/Source/GSStoryboardTransform.m +++ /dev/null @@ -1,888 +0,0 @@ -/* Implementation of class GSStoryboardTransform - Copyright (C) 2020 Free Software Foundation, Inc. - - By: Gregory John Casamento - Date: Sat 04 Jul 2020 03:48:15 PM EDT - - This file is part of the GNUstep Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110 USA. -*/ - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import "AppKit/NSSeguePerforming.h" -#import "AppKit/NSStoryboard.h" -#import "AppKit/NSStoryboardSegue.h" -#import "AppKit/NSNibDeclarations.h" -#import "AppKit/NSViewController.h" -#import "AppKit/NSWindowController.h" - -#import "GSStoryboardTransform.h" -#import "GSFastEnumeration.h" - -#define APPLICATION @"application" - -@interface NSStoryboardSegue (__private__) -- (void) _setDestinationController: (id)controller; -- (void) _setSourceController: (id)controller; -@end - -@interface NSStoryboardSegue (__StoryboardPrivate__) -// Private to this class... -- (void) _setKind: (NSString *)k; -- (NSString *) _kind; -- (void) _setRelationship: (NSString *)r; -- (NSString *) _relationship; -- (void) _setPopoverAnchorView: (id)view; -- (id) _popoverAnchorView; -- (void) _setPopoverBehavior: (NSPopoverBehavior)behavior; -- (NSPopoverBehavior) _popoverBehavior; -- (void) _setPreferredEdge: (NSRectEdge)edge; -- (NSRectEdge) _preferredEdge; -@end - -// this needs to be set on segues -@implementation NSStoryboardSegue (__StoryboardPrivate__) -- (void) _setKind: (NSString *)k -{ - ASSIGN(_kind, k); -} - -- (NSString *) _kind -{ - return _kind; -} - -- (void) _setRelationship: (NSString *)r -{ - ASSIGN(_relationship, r); -} - -- (NSString *) _relationship -{ - return _relationship; -} - -- (void) _setPopoverAnchorView: (id)view -{ - ASSIGN(_popoverAnchorView, view); -} - -- (id) _popoverAnchorView -{ - return _popoverAnchorView; -} - -- (void) _setPopoverBehavior: (NSPopoverBehavior)behavior -{ - _popoverBehavior = behavior; -} - -- (NSPopoverBehavior) _popoverBehavior -{ - return _popoverBehavior; -} - -- (void) _setPreferredEdge: (NSRectEdge)edge -{ - _preferredEdge = edge; -} - -- (NSRectEdge) _preferredEdge -{ - return _preferredEdge; -} -@end - -@implementation NSStoryboardSeguePerformAction -- (id) target -{ - return _target; -} - -- (void) setTarget: (id)target -{ - ASSIGN(_target, target); -} - -- (SEL) action -{ - return _action; -} - -- (void) setAction: (SEL)action -{ - _action = action; -} - -- (NSString *) selector -{ - return NSStringFromSelector(_action); -} - -- (void) setSelector: (NSString *)s -{ - _action = NSSelectorFromString(s); -} - -- (id) sender -{ - return _sender; -} - -- (void) setSender: (id)sender -{ - ASSIGN(_sender, sender); -} - -- (NSString *) identifier -{ - return _identifier; -} - -- (void) setIdentifier: (NSString *)identifier -{ - ASSIGN(_identifier, identifier); -} - -- (NSString *) kind -{ - return _kind; -} - -- (void) setKind: (NSString *)kind -{ - ASSIGN(_kind, kind); -} - -- (void) setPopoverAnchorView: (id)view -{ - ASSIGN(_popoverAnchorView, view); -} - -- (id) popoverAnchorView -{ - return _popoverAnchorView; -} - -- (NSStoryboard *) storyboard -{ - return _storyboard; -} - -- (void) setStoryboard: (NSStoryboard *)storyboard -{ - ASSIGN(_storyboard, storyboard); -} - -- (NSStoryboardSegue *) storyboardSegue -{ - return _storyboardSegue; -} - -- (void) setStoryboardSegue: (NSStoryboardSegue *)ss -{ - ASSIGN(_storyboardSegue, ss); -} - -- (void) dealloc -{ - RELEASE(_storyboard); - RELEASE(_kind); - RELEASE(_identifier); - RELEASE(_popoverAnchorView); - RELEASE(_sender); - RELEASE(_storyboardSegue); - [super dealloc]; -} - -- (IBAction) doAction: (id)sender -{ - BOOL should = YES; - - // If the instance we are testing is a controller, then the value of should is set by this method.... - // if it is not, as it is possible to initiate a segue from an NSMenuItem, then we don't, but should - // remains set to YES so that the logic to replace the destination controller is still called. - if ([_sender respondsToSelector: @selector(shouldPerformSegueWithIdentifier:sender:)]) - { - should = [_sender shouldPerformSegueWithIdentifier: _identifier - sender: _sender]; - } - - if (should) - { - id destCon = [_storyboardSegue destinationController]; - if ([destCon isKindOfClass: [NSString class]]) - { - // resolve the destination controller - destCon = [_storyboard instantiateControllerWithIdentifier: destCon]; - [_storyboardSegue _setDestinationController: destCon]; // replace with actual controller... - } - [_storyboardSegue _setSourceController: _sender]; - - if (_sender != nil && - [_sender respondsToSelector: @selector(performSegueWithIdentifier:sender:)]) - { - [_sender performSegueWithIdentifier: _identifier - sender: _sender]; - } - else - { - [_storyboardSegue perform]; - } - } -} - -- (id) copyWithZone: (NSZone *)z -{ - NSStoryboardSeguePerformAction *pa = [[NSStoryboardSeguePerformAction allocWithZone: z] init]; - [pa setTarget: _target]; - [pa setSelector: [self selector]]; - [pa setSender: _sender]; - [pa setIdentifier: _identifier]; - [pa setPopoverAnchorView: _popoverAnchorView]; - [pa setStoryboardSegue: _storyboardSegue]; - [pa setStoryboard: _storyboard]; - return pa; -} - -- (instancetype) initWithCoder: (NSCoder *)coder -{ - self = [super init]; - if ([coder allowsKeyedCoding]) - { - if ([coder containsValueForKey: @"NSTarget"]) - { - [self setTarget: [coder decodeObjectForKey: @"NSTarget"]]; - } - if ([coder containsValueForKey: @"NSSelector"]) - { - [self setSelector: [coder decodeObjectForKey: @"NSSelector"]]; - } - if ([coder containsValueForKey: @"NSSender"]) - { - [self setSender: [coder decodeObjectForKey: @"NSSender"]]; - } - if ([coder containsValueForKey: @"NSIdentifier"]) - { - [self setIdentifier: [coder decodeObjectForKey: @"NSIdentifier"]]; - } - if ([coder containsValueForKey: @"NSKind"]) - { - [self setKind: [coder decodeObjectForKey: @"NSKind"]]; - } - if ([coder containsValueForKey: @"NSPopoverAnchorView"]) - { - [self setPopoverAnchorView: [coder decodeObjectForKey: @"NSPopoverAnchorView"]]; - } - } - return self; -} - -- (void) encodeWithCoder: (NSCoder *)coder -{ - // this is never encoded directly... -} -@end - -@implementation NSControllerPlaceholder - -- (NSString *) storyboardName -{ - return _storyboardName; -} - -- (void) setStoryboardName: (NSString *)name -{ - ASSIGNCOPY(_storyboardName, name); -} - -- (id) copyWithZone: (NSZone *)z -{ - NSControllerPlaceholder *c = [[NSControllerPlaceholder allocWithZone: z] init]; - [c setStoryboardName: _storyboardName]; - return c; -} - -- (instancetype) initWithCoder: (NSCoder *)coder -{ - self = [super init]; - if ([coder allowsKeyedCoding]) - { - if ([coder containsValueForKey: @"NSStoryboardName"]) - { - [self setStoryboardName: [coder decodeObjectForKey: @"NSStoryboardName"]]; - } - } - return self; -} - -- (void) encodeWithCoder: (NSCoder *)coder -{ - // this is never encoded directly... -} - -- (id) instantiate -{ - NSStoryboard *sb = [NSStoryboard storyboardWithName: _storyboardName - bundle: [NSBundle mainBundle]]; - return [sb instantiateInitialController]; -} - -@end - -@implementation GSStoryboardTransform - -- (instancetype) initWithData: (NSData *)data -{ - self = [super init]; - if (self != nil) - { - NSXMLDocument *xml = [[NSXMLDocument alloc] initWithData: data - options: 0 - error: NULL]; - - _scenesMap = [[NSMutableDictionary alloc] initWithCapacity: 10]; - _controllerMap = [[NSMutableDictionary alloc] initWithCapacity: 10]; - _identifierToSegueMap = [[NSMutableDictionary alloc] initWithCapacity: 10]; - - [self processStoryboard: xml]; - RELEASE(xml); - } - return self; -} - -- (void) dealloc -{ - RELEASE(_initialViewControllerId); - RELEASE(_applicationSceneId); - RELEASE(_scenesMap); - RELEASE(_controllerMap); - RELEASE(_identifierToSegueMap); - [super dealloc]; -} - -- (NSString *) initialViewControllerId -{ - return _initialViewControllerId; -} - -- (NSString *) applicationSceneId -{ - return _applicationSceneId; -} - -- (NSMapTable *) segueMapForIdentifier: (NSString *)identifier -{ - return [_identifierToSegueMap objectForKey: identifier]; -} - -- (NSXMLElement *) createCustomObjectWithId: (NSString *)ident - userLabel: (NSString *)userLabel - customClass: (NSString *)className -{ - NSXMLElement *customObject = - [[NSXMLElement alloc] initWithName: @"customObject"]; - NSXMLNode *idValue = - [NSXMLNode attributeWithName: @"id" - stringValue: ident]; - NSXMLNode *usrLabel = - [NSXMLNode attributeWithName: @"userLabel" - stringValue: userLabel]; - NSXMLNode *customCls = - [NSXMLNode attributeWithName: @"customClass" - stringValue: className]; - - [customObject addAttribute: idValue]; - [customObject addAttribute: usrLabel]; - [customObject addAttribute: customCls]; - - AUTORELEASE(customObject); - - return customObject; -} - -- (NSData *) dataForIdentifier: (NSString *)identifier -{ - NSString *sceneId = [_controllerMap objectForKey: identifier]; - NSXMLDocument *xml = [_scenesMap objectForKey: sceneId]; - return [xml XMLData]; -} - -- (void) addStandardObjects: (NSXMLElement *)objects - classString: (NSString *) customClassString - connections: (NSXMLNode *)appCons - firstResponderId: (NSString *)firstResponderId -{ - NSXMLElement *customObject = nil; - - customObject = - [self createCustomObjectWithId: @"-3" - userLabel: @"Application" - customClass: @"NSObject"]; - [objects insertChild: customObject - atIndex: 0]; - customObject = - [self createCustomObjectWithId: firstResponderId - userLabel: @"First Responder" - customClass: @"FirstResponder"]; - [objects insertChild: customObject - atIndex: 0]; - customObject = - [self createCustomObjectWithId: @"-2" - userLabel: @"File's Owner" - customClass: customClassString]; - if (appCons != nil) - { - [customObject addChild: appCons]; - } - [objects insertChild: customObject - atIndex: 0]; -} - -- (void) processChild: (NSXMLElement *)objects - withDoc: (NSXMLElement *)doc - withAppNode: (NSXMLNode *)appNode - sceneId: (NSString *)sceneId - firstResponderId: (NSString *)firstResponderId -{ - NSString *customClassString = nil; - NSXMLNode *appCons = nil; - - if (appNode != nil) - { - NSArray *appConsArr = [appNode nodesForXPath: @"connections" error: NULL]; - - appCons = [appConsArr objectAtIndex: 0]; - if (appCons != nil) - { - [appCons detach]; - } - - // Assign application scene... - ASSIGN(_applicationSceneId, sceneId); - [_controllerMap setObject: _applicationSceneId - forKey: APPLICATION]; - - // Move all application children to objects... - NSArray *appChildren = [appNode children]; - FOR_IN(NSXMLElement*, ae, appChildren) - [ae detach]; - [objects addChild: ae]; - END_FOR_IN(appChildren); - - // Remove the appNode - [appNode detach]; - - // create a customObject entry for NSApplication reference... - NSXMLNode *appCustomClass = [(NSXMLElement *)appNode - attributeForName: @"customClass"]; - customClassString = ([appCustomClass stringValue] == nil) ? - @"NSApplication" : [appCustomClass stringValue]; - } - - [self addStandardObjects: objects - classString: customClassString - connections: appCons - firstResponderId: firstResponderId]; - - // Add it to the document - [objects detach]; - [doc addChild: objects]; -} - -- (NSArray *) subclassesOfClass: (Class)clz -{ - NSMutableArray *subclasses = [GSObjCAllSubclassesOfClass(clz) mutableCopy]; - NSMutableArray *result = [NSMutableArray arrayWithCapacity: [subclasses count]]; - - [subclasses insertObject: clz atIndex: 0]; - FOR_IN(Class, cls, subclasses) - { - NSString *className = NSStringFromClass(cls); - NSString *classNameNoNamespace = [className substringFromIndex: 2]; - NSString *xmlClassName = [NSString stringWithFormat: @"%@%@", - [[classNameNoNamespace substringToIndex: 1] lowercaseString], - [classNameNoNamespace substringFromIndex: 1]]; - NSString *lowerCaseName = [xmlClassName lowercaseString]; - - [result addObject: xmlClassName]; - [result addObject: lowerCaseName]; - } - END_FOR_IN(subclasses); - - return result; -} - -- (NSArray *) findSubclassesOf: (Class)clz - inDocument: (NSXMLDocument *)document -{ - NSArray *result = nil; - NSArray *xmlClassNames = [self subclassesOfClass: clz]; - - FOR_IN(NSString*, xmlClassName, xmlClassNames) - { - NSString *xpath = [NSString stringWithFormat: @"//%@",xmlClassName]; - result = [document nodesForXPath: xpath error: NULL]; - if ([result count] > 0) - { - break; - } - } - END_FOR_IN(xmlClassNames); - - return result; -} - -- (NSString *) controllerIdWithDocument: (NSXMLDocument *)document -{ - NSString *controllerId = nil; - NSArray *windowControllers = [self findSubclassesOf: [NSWindowController class] - inDocument: document]; - NSArray *viewControllers = [self findSubclassesOf: [NSViewController class] - inDocument: document]; - NSArray *controllerPlaceholders = [document nodesForXPath: @"//controllerPlaceholder" - error: NULL]; - - if ([windowControllers count] > 0) - { - NSXMLElement *ce = [windowControllers objectAtIndex: 0]; - NSXMLNode *attr = [ce attributeForName: @"id"]; - controllerId = [attr stringValue]; - - FOR_IN(NSXMLElement*, o, windowControllers) - { - NSXMLElement *objects = (NSXMLElement *)[o parent]; - NSArray *windows = [o nodesForXPath: @"//window" error: NULL]; - FOR_IN(NSXMLNode*, w, windows) - { - [w detach]; - [objects addChild: w]; - } - END_FOR_IN(windows); - } - END_FOR_IN(windowControllers); - } - - if ([viewControllers count] > 0) - { - NSXMLElement *ce = [viewControllers objectAtIndex: 0]; - NSXMLNode *attr = [ce attributeForName: @"id"]; - controllerId = [attr stringValue]; - } - - if ([controllerPlaceholders count] > 0) - { - NSXMLElement *ce = [controllerPlaceholders objectAtIndex: 0]; - NSXMLNode *attr = [ce attributeForName: @"id"]; - controllerId = [attr stringValue]; - } - - return controllerId; -} - -- (void) processStoryboard: (NSXMLDocument *)xml -{ - NSArray *docNodes = [xml nodesForXPath: @"document" error: NULL]; - - if ([docNodes count] > 0) - { - NSXMLElement *docNode = [docNodes objectAtIndex: 0]; - NSArray *array = [docNode nodesForXPath: @"//scene" error: NULL]; - NSArray *firstResponderIdNodes = [docNode nodesForXPath: @"//objects/customObject[@sceneMemberID =\"firstResponder\"]/@id" - error: NULL]; - NSString *firstResponderId = @"-1"; - - if([firstResponderIdNodes count] > 0) - { - firstResponderId = [[firstResponderIdNodes objectAtIndex: 0] stringValue]; - } - - // Set initial view controller... - ASSIGN(_initialViewControllerId, [[docNode attributeForName: @"initialViewController"] stringValue]); - FOR_IN(NSXMLElement*, e, array) - { - NSXMLElement *doc = [[NSXMLElement alloc] initWithName: @"document"]; - NSArray *children = [e children]; - NSXMLDocument *document = nil; - NSString *sceneId = [[e attributeForName: @"sceneID"] stringValue]; - NSString *controllerId = nil; - // Move children... - FOR_IN(NSXMLElement*, child, children) - { - if ([[child name] isEqualToString: @"point"] == YES) - continue; // go on if it's a point element, we don't use that in the app... - - NSArray *subnodes = [child nodesForXPath: @"//application" error: NULL]; - NSXMLNode *appNode = [subnodes objectAtIndex: 0]; - [self processChild: child - withDoc: doc - withAppNode: appNode - sceneId: sceneId - firstResponderId: firstResponderId]; - - // fix other custom objects - document = [[NSXMLDocument alloc] initWithRootElement: doc]; - controllerId = [self controllerIdWithDocument: document]; - controllerId = (controllerId != nil) ? controllerId : APPLICATION; - RELEASE(doc); - - // Create document... - [_scenesMap setObject: document - forKey: sceneId]; - - // Map controllerId's to scenes... - if (controllerId != nil) - { - [_controllerMap setObject: sceneId - forKey: controllerId]; - - [self processSegues: document - forControllerId: controllerId]; - } - RELEASE(document); - } - END_FOR_IN(children); - } - END_FOR_IN(array); - } - else - { - [NSException raise: NSInternalInconsistencyException - format: @"No document element found in storyboard file"]; - } -} - -- (BOOL) isProcessedDocument: (NSXMLDocument *)xmlIn -{ - NSArray *docArray = [xmlIn nodesForXPath: @"document" error: NULL]; - if ([docArray count] > 0) - { - NSXMLElement *docElem = (NSXMLElement *)[docArray objectAtIndex: 0]; - NSXMLNode *a = [docElem attributeForName: @"processed"]; - NSString *value = [a stringValue]; - if (value != nil) - { - return YES; - } - else - { - NSXMLNode *new_attr = [NSXMLNode attributeWithName: @"processed" - stringValue: @"true"]; - [docElem addAttribute: new_attr]; - } - } - return NO; -} - -- (NSXMLElement *) createStoryboardProxyElementWithSelector: (NSString *)selector - target: (NSString *)dst - segueIdentifier: (NSString *)ident - sender: (NSString *)src - kind: (NSString *)kind - anchorView: (NSString *)anchorView -{ - NSXMLElement *sbproxy = [NSXMLElement elementWithName: @"storyboardSeguePerformAction"]; - - NSXMLNode *pselector - = [NSXMLNode attributeWithName: @"selector" - stringValue: selector]; - NSXMLNode *ptarget - = [NSXMLNode attributeWithName: @"target" - stringValue: dst]; - NSString *pident_value = [[NSUUID UUID] UUIDString]; - NSXMLNode *pident - = [NSXMLNode attributeWithName: @"id" - stringValue: pident_value]; - NSXMLNode *psegueIdent - = [NSXMLNode attributeWithName: @"identifier" - stringValue: ident]; - NSXMLNode *psender - = [NSXMLNode attributeWithName: @"sender" - stringValue: src]; - NSXMLNode *pkind - = [NSXMLNode attributeWithName: @"kind" - stringValue: kind]; - NSXMLNode *panchorview - = [NSXMLNode attributeWithName: @"popoverAnchorView" - stringValue: anchorView]; - - [sbproxy addAttribute: pselector]; - [sbproxy addAttribute: ptarget]; - [sbproxy addAttribute: pident]; - [sbproxy addAttribute: psegueIdent]; - [sbproxy addAttribute: psender]; - [sbproxy addAttribute: pkind]; - [sbproxy addAttribute: panchorview]; - - return sbproxy; -} - -- (NSMapTable *) processConnections: (NSArray *)connectionsArray - withObjects: (NSXMLElement *)objects - controllerId: (NSString *)src -{ - NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable]; - - FOR_IN (NSXMLElement*, connections, connectionsArray) - { - NSArray *children = [connections children]; // there should be only one per set. - - FOR_IN (NSXMLElement*, obj, children) - if ([[obj name] isEqualToString: @"segue"]) - { - // get the information from the segue. - id connections_parent = [[obj parent] parent]; - id segue_parent = connections; // [obj parent]; - NSString *connections_parent_name = [connections_parent name]; - NSXMLNode *attr = [obj attributeForName: @"destination"]; - NSString *dst = [attr stringValue]; - attr = [obj attributeForName: @"kind"]; - NSString *kind = [attr stringValue]; - attr = [obj attributeForName: @"relationship"]; - NSString *rel = [attr stringValue]; - attr = [obj attributeForName: @"id"]; - NSString *uid = [attr stringValue]; - attr = [obj attributeForName: @"identifier"]; - NSString *ident = [attr stringValue]; - if (ident == nil) - { - ident = [[NSUUID UUID] UUIDString]; - } - attr = [obj attributeForName: @"popoverAnchorView"]; - NSString *av = [attr stringValue]; - attr = [obj attributeForName: @"popoverBehavior"]; - NSString *pb = [attr stringValue]; - NSPopoverBehavior behavior = NSPopoverBehaviorApplicationDefined; - if ([pb isEqualToString: @"a"]) - { - behavior = NSPopoverBehaviorApplicationDefined; - } - else if ([pb isEqualToString: @"t"]) - { - behavior = NSPopoverBehaviorTransient; - } - else if ([pb isEqualToString: @"s"]) - { - behavior = NSPopoverBehaviorSemitransient; - } - - attr = [obj attributeForName: @"preferredEdge"]; - NSString *pe = [attr stringValue]; - NSRectEdge edge = NSMinXEdge; - if ([pe isEqualToString: @"maxY"]) - { - edge = NSMaxYEdge; - } - else if ([pe isEqualToString: @"minY"]) - { - edge = NSMinYEdge; - } - else if ([pe isEqualToString: @"maxX"]) - { - edge = NSMaxXEdge; - } - else if ([pe isEqualToString: @"minX"]) - { - edge = NSMinXEdge; - } - [obj detach]; // segue can't be in the archive since it doesn't conform to NSCoding - - // Create proxy object to invoke methods on the window controller - NSXMLElement *sbproxy = [self createStoryboardProxyElementWithSelector: @"doAction:" - target: dst - segueIdentifier: ident - sender: src - kind: kind - anchorView: av]; - - NSUInteger count = [[objects children] count]; - [objects insertChild: sbproxy - atIndex: count - 1]; - - // add action to parent ONLY if it is NOT a controller.. - if (![[self subclassesOfClass: [NSWindowController class]] containsObject: connections_parent_name] && - ![[self subclassesOfClass: [NSViewController class]] containsObject: connections_parent_name]) - { - // Create action... - NSXMLElement *action = [NSXMLElement elementWithName: @"action"]; - NSXMLNode *selector - = [NSXMLNode attributeWithName: @"selector" - stringValue: @"doAction:"]; - NSXMLNode *target - = [NSXMLNode attributeWithName: @"target" - stringValue: [[sbproxy attributeForName: @"id"] stringValue]]; - NSXMLNode *controller_ident - = [NSXMLNode attributeWithName: @"id" - stringValue: uid]; - [action addAttribute: selector]; - [action addAttribute: target]; - [action addAttribute: controller_ident]; - [segue_parent addChild: action]; - } - - // Create the segue... - NSStoryboardSegue *ss = [[NSStoryboardSegue alloc] initWithIdentifier: ident - source: src - destination: dst]; - [ss _setKind: kind]; - [ss _setRelationship: rel]; - [ss _setPopoverBehavior: behavior]; - [ss _setPreferredEdge: edge]; - - // Add to maptable... - [mapTable setObject: ss - forKey: ident]; - - } // only process segue objects... - END_FOR_IN(children); - } // iterate over connection objs - END_FOR_IN(connectionsArray); - - return mapTable; -} - -- (void) processSegues: (NSXMLDocument *)xml - forControllerId: (NSString *)identifier -{ - BOOL processed = [self isProcessedDocument: xml]; - if (!processed) - { - NSArray *array = [xml nodesForXPath: @"//objects[1]" - error: NULL]; - NSXMLElement *objects = [array objectAtIndex: 0]; // get the "objects" section - NSArray *connectionsArray = [xml nodesForXPath: @"//connections" - error: NULL]; - NSMapTable *mapTable = [self processConnections: connectionsArray - withObjects: objects - controllerId: identifier]; - [_identifierToSegueMap setObject: mapTable - forKey: identifier]; - } -} - -@end diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 75c64ba26..0f9bb33ab 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -68,7 +68,10 @@ #import "AppKit/NSTabView.h" #import "AppKit/NSToolbarItem.h" #import "AppKit/NSView.h" + #import "GSCodingFlags.h" +#import "GSScenes.h" +#import "GSScene.h" #define DEBUG_XIB5 0 @@ -229,6 +232,8 @@ static NSArray *XmlBoolDefaultYes = nil; @"NSStackViewContainer", @"beginningViews", @"NSStackViewContainer", @"middleViews", @"NSStackViewContainer", @"endViews", + // @"GSScene", @"scene", + @"NSMutableArray", @"scenes", nil]; RETAIN(XmlTagToObjectClassMap); @@ -238,7 +243,7 @@ static NSArray *XmlBoolDefaultYes = nil; XmlTagsToSkip = [NSArray arrayWithObject: @"dependencies"]; RETAIN(XmlTagsToSkip); - ClassNamePrefixes = [NSArray arrayWithObjects: @"NS", @"IB", nil]; + ClassNamePrefixes = [NSArray arrayWithObjects: @"NS", @"IB", @"GS", nil]; RETAIN(ClassNamePrefixes); XmlReferenceAttributes = [NSArray arrayWithObjects: @"headerView", @"initialItem", @@ -699,7 +704,7 @@ static NSArray *XmlBoolDefaultYes = nil; // Parse the XML data [theParser parse]; - // Decode optional resources + // Decode optional resourcess _resources = RETAIN([self decodeObjectForKey: @"resources"]); } NS_HANDLER diff --git a/Source/GSXibKeyedUnarchiver.m b/Source/GSXibKeyedUnarchiver.m index d7cabe691..04f7e1356 100644 --- a/Source/GSXibKeyedUnarchiver.m +++ b/Source/GSXibKeyedUnarchiver.m @@ -35,10 +35,13 @@ */ #import + #import "GNUstepGUI/GSXibKeyedUnarchiver.h" #import "GNUstepGUI/GSXibElement.h" #import "GNUstepGUI/GSNibLoading.h" + #import "GSXib5KeyedUnarchiver.h" +#import "GSStoryboardKeyedUnarchiver.h" @implementation GSXibKeyedUnarchiver @@ -49,11 +52,8 @@ NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data options: 0 error: NULL]; - if (document == nil) - { - return NO; - } - else + + if (document) { // Test to see if this is an Xcode 5 XIB... NSArray *documentNodes = [document nodesForXPath: @"/document" error: NULL]; @@ -62,16 +62,47 @@ // specific to check here... return [documentNodes count] != 0; } + + return NO; #else + // We now default to checking XIB 5 versions return YES; #endif } ++ (BOOL) checkStoryboard: (NSData *)data +{ +#if GNUSTEP_BASE_HAVE_LIBXML + // Ensure we have a storyboard...first see if we can parse the XML... + NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data + options: 0 + error: NULL]; + + if (document) + { + // Test to see if this is an Xcode 5 XIB... + NSArray *nodes = [document nodesForXPath: @"/scenes" error: NULL]; + + // Need at LEAST ONE scene node...we should find something a bit more + // specific to check here... + return [nodes count] != 0; + } +#endif + + // We now default to checking XIB 5 versions + return NO; +} + + (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data { NSKeyedUnarchiver *unarchiver = nil; + // if ([self checkStoryboard: data]) + // { + // unarchiver = [[GSStoryboardKeyedUnarchiver alloc] initForReadingWithData: data]; + // } + // else if ([self checkXib5: data]) { unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; @@ -80,6 +111,7 @@ { unarchiver = [[GSXibKeyedUnarchiver alloc] initForReadingWithData: data]; } + return AUTORELEASE(unarchiver); } diff --git a/Source/NSStoryboard.m b/Source/NSStoryboard.m index 4197f9ed0..b738b133e 100644 --- a/Source/NSStoryboard.m +++ b/Source/NSStoryboard.m @@ -35,6 +35,7 @@ #import "AppKit/NSApplication.h" #import "AppKit/NSNib.h" +#import "AppKit/NSNibLoading.h" #import "AppKit/NSStoryboard.h" #import "AppKit/NSWindowController.h" #import "AppKit/NSViewController.h" @@ -42,7 +43,7 @@ #import "AppKit/NSNibDeclarations.h" #import "GNUstepGUI/GSModelLoaderFactory.h" -#import "GSStoryboardTransform.h" +#import "GNUstepGUI/GSXibKeyedUnarchiver.h" #import "GSFastEnumeration.h" static NSStoryboard *__mainStoryboard = nil; @@ -111,9 +112,16 @@ static NSStoryboard *__mainStoryboard = nil; if (self != nil) { NSString *path = [bundle pathForResource: name - ofType: @"storyboard"]; - NSData *data = [NSData dataWithContentsOfFile: path]; - _transform = [[GSStoryboardTransform alloc] initWithData: data]; + ofType: @"storyboard"]; + _data = [NSData dataWithContentsOfFile: path]; + + if (_data != nil) + { + } + else + { + NSLog(@"Failed to load storyboard with name \"%@\" at \"%@.\"", name, path); + } } return self; } @@ -142,7 +150,7 @@ static NSStoryboard *__mainStoryboard = nil; // Instance methods... - (void) dealloc { - RELEASE(_transform); + RELEASE(_scenes); [super dealloc]; } @@ -158,7 +166,7 @@ static NSStoryboard *__mainStoryboard = nil; - (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block { - return [self instantiateControllerWithIdentifier: [_transform initialViewControllerId] + return [self instantiateControllerWithIdentifier: @"" // [_transform initialViewControllerId] creator: block]; } @@ -172,6 +180,8 @@ static NSStoryboard *__mainStoryboard = nil; creator: (NSStoryboardControllerCreator)block { id result = nil; + + /* NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5]; NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects, NSNibTopLevelObjects, @@ -260,6 +270,8 @@ static NSStoryboard *__mainStoryboard = nil; { CALL_BLOCK(block, self); } + */ + return result; } @end