From 423c9c1982ef6e9e72f8cd7740a85938bf8482e8 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 13 May 2024 12:26:34 -0400 Subject: [PATCH 01/10] Add new files for handling storyboards, still doesn't fully function --- .../GNUstepGUI/GSXibKeyedUnarchiver.h | 2 + Headers/AppKit/NSStoryboard.h | 6 +- Source/GNUmakefile | 2 + Source/GSModelLoaderFactory.m | 2 +- Source/GSScene.h | 60 +++++ Source/GSScene.m | 122 +++++++++ Source/GSStoryboardLoader.m | 249 ++++++++++++++++++ Source/GSXib5KeyedUnarchiver.m | 2 + Source/GSXibKeyedUnarchiver.m | 33 ++- Source/NSStoryboard.m | 41 ++- 10 files changed, 508 insertions(+), 11 deletions(-) create mode 100644 Source/GSScene.h create mode 100644 Source/GSScene.m create mode 100644 Source/GSStoryboardLoader.m 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/AppKit/NSStoryboard.h b/Headers/AppKit/NSStoryboard.h index 0772338f3..29dc911ed 100644 --- a/Headers/AppKit/NSStoryboard.h +++ b/Headers/AppKit/NSStoryboard.h @@ -33,7 +33,9 @@ extern "C" { #endif -@class NSString, NSBundle, NSMutableDictionary; +@class NSBundle; +@class NSMutableDictionary; +@class NSString; typedef NSString *NSStoryboardName; typedef NSString *NSStoryboardSceneIdentifier; @@ -43,7 +45,7 @@ DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id); APPKIT_EXPORT_CLASS @interface NSStoryboard : NSObject { - id _transform; + NSMutableDictionary *_scenes; } #if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST) diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 5e1409a10..e7dd7fbde 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -307,7 +307,9 @@ GSDisplayServer.m \ GSHelpManagerPanel.m \ GSInfoPanel.m \ GSMemoryPanel.m \ +GSScene.m \ GSSlideView.m \ +GSStoryboardLoader.m \ GSTextStorage.m \ GSTrackingRect.m \ GSServicesManager.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..8f23069c9 --- /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 NSArray; +@class NSString; + +@interface GSScene : NSObject +{ + NSString *_sceneID; + NSArray *_objects; + NSPoint _canvasLocation; +} + +- (NSString *) sceneID; +- (void) setSceneID: (NSString *)sceneID; + +- (NSArray *) objects; +- (void) setObjects: (NSArray *)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..eef41f601 --- /dev/null +++ b/Source/GSScene.m @@ -0,0 +1,122 @@ +/* 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); +} + +- (NSArray *) objects +{ + return _objects; +} + +- (void) setObjects: (NSArray *)objects +{ + ASSIGNCOPY(_objects, objects); +} + +- (NSPoint) canvasLocation +{ + return _canvasLocation; +} + +- (void) setCanvasLocation: (NSPoint)point +{ + _canvasLocation = point; +} + +// NSCoding + +- (instancetype) initWithCoder: (NSCoder *)coder +{ + 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/GSStoryboardLoader.m b/Source/GSStoryboardLoader.m new file mode 100644 index 000000000..226a9e478 --- /dev/null +++ b/Source/GSStoryboardLoader.m @@ -0,0 +1,249 @@ +/* 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(@"XIB", @"First object %@", [rootObjects objectAtIndex: 0]); + NSDebugLLog(@"XIB", @"Second object %@", [rootObjects objectAtIndex: 1]); + NSDebugLLog(@"XIB", @"Third object %@", [rootObjects objectAtIndex: 2]); + // Use the owner as first root object + [(NSCustomObject*)[rootObjects objectAtIndex: 0] setRealObject: owner]; + + en = [rootObjects objectEnumerator]; + while ((obj = [en nextObject]) != nil) + { + index++; + + if ([obj respondsToSelector: @selector(nibInstantiate)]) + { + obj = [obj nibInstantiate]; + } + + // IGNORE file's owner, first responder and NSApplication instances... + if ((obj != nil) && (index > 3)) + { + [topLevelObjects addObject: obj]; + // All top level objects must be released by the caller to avoid + // leaking, unless they are going to be released by other nib + // objects on behalf of the owner. + RETAIN(obj); + } + + if (([obj isKindOfClass: [NSMenu class]]) && + ([obj _isMainMenu])) + { + // add the menu... + [NSApp _setMainMenu: obj]; + } + } +} + +- (void) awake: (NSArray *)rootObjects + inContainer: (id)objects + withContext: (NSDictionary *)context +{ + [self awake: rootObjects withContext: context]; + + // Load connections and awaken objects + if ([objects respondsToSelector: @selector(nibInstantiate)]) + { + [objects nibInstantiate]; + } +} + +- (BOOL) loadModelData: (NSData *)data + externalNameTable: (NSDictionary *)context + withZone: (NSZone *)zone +{ + BOOL loaded = NO; + + NS_DURING + { + if (data != nil) + { + NSKeyedUnarchiver *unarchiver = [GSXibKeyedUnarchiver unarchiverForReadingWithData: data]; + + if (unarchiver != nil) + { + IBObjectContainer *objects; + + NSDebugLLog(@"XIB", @"Invoking unarchiver"); + [unarchiver setObjectZone: zone]; + // rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; + objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; + NSLog(@"objects %@", objects); + /* + [self awake: rootObjects + inContainer: objects + withContext: context]; + */ + loaded = YES; + } + else + { + NSLog(@"Could not instantiate Xib unarchiver/Unable to parse Storyboard."); + } + } + else + { + NSLog(@"Data passed to Storyboard loading method is nil."); + } + } + NS_HANDLER + { + NSLog(@"Exception occurred while loading model: %@",[localException reason]); + } + NS_ENDHANDLER + + if (loaded == NO) + { + NSLog(@"Failed to load Storyboard\n"); + } + + return loaded; +} + +- (NSData*) dataForFile: (NSString*)fileName +{ + NSFileManager *mgr = [NSFileManager defaultManager]; + BOOL isDir = NO; + + NSDebugLLog(@"XIB", @"Loading Storyboard `%@'...\n", fileName); + if ([mgr fileExistsAtPath: fileName isDirectory: &isDir]) + { + if (isDir == NO) + { + return [NSData dataWithContentsOfFile: fileName]; + } + else + { + NSLog(@"Storyboard file specified %@, is directory.", fileName); + } + } + else + { + NSLog(@"Storyboard file specified %@, could not be found.", fileName); + } + return nil; +} + +@end diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 80b75bfaa..f1fe1033e 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -68,6 +68,7 @@ #import "AppKit/NSTabView.h" #import "AppKit/NSToolbarItem.h" #import "AppKit/NSView.h" + #import "GSCodingFlags.h" #define DEBUG_XIB5 0 @@ -229,6 +230,7 @@ static NSArray *XmlBoolDefaultYes = nil; @"NSStackViewContainer", @"beginningViews", @"NSStackViewContainer", @"middleViews", @"NSStackViewContainer", @"endViews", + @"GSScene", @"scene", nil]; RETAIN(XmlTagToObjectClassMap); diff --git a/Source/GSXibKeyedUnarchiver.m b/Source/GSXibKeyedUnarchiver.m index d7cabe691..7ca9b6bc4 100644 --- a/Source/GSXibKeyedUnarchiver.m +++ b/Source/GSXibKeyedUnarchiver.m @@ -68,11 +68,41 @@ #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 == nil) + { + return NO; + } + else + { + // Test to see if this is an Xcode 5 XIB... + NSArray *nodes = [document nodesForXPath: @"/scene" error: NULL]; + + // Need at LEAST ONE scene node...we should find something a bit more + // specific to check here... + return [nodes count] != 0; + } +#else + // We now default to checking XIB 5 versions + return YES; +#endif +} + + (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data { NSKeyedUnarchiver *unarchiver = nil; - if ([self checkXib5: data]) + if ([self checkStoryboard: data]) + { + unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; + } + else if ([self checkXib5: data]) { unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; } @@ -80,6 +110,7 @@ { unarchiver = [[GSXibKeyedUnarchiver alloc] initForReadingWithData: data]; } + return AUTORELEASE(unarchiver); } diff --git a/Source/NSStoryboard.m b/Source/NSStoryboard.m index 4197f9ed0..befcd6e8b 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; @@ -110,10 +111,32 @@ static NSStoryboard *__mainStoryboard = nil; self = [super init]; if (self != nil) { - NSString *path = [bundle pathForResource: name - ofType: @"storyboard"]; - NSData *data = [NSData dataWithContentsOfFile: path]; - _transform = [[GSStoryboardTransform alloc] initWithData: data]; + BOOL success = NO; + + success = [bundle loadNibFile: name + externalNameTable: nil + withZone: NSDefaultMallocZone()]; + + if (success) + { + } + /* + if (unarchiver != nil) + { + NSArray *rootObjects; + IBObjectContainer *objects; + + NSDebugLLog(@"XIB", @"Invoking unarchiver"); + [unarchiver setObjectZone: zone]; + rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; + objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; + NSDebugLLog(@"XIB", @"rootObjects %@", rootObjects); + [self awake: rootObjects + inContainer: objects + withContext: context]; + loaded = YES; + } + */ } return self; } @@ -142,7 +165,7 @@ static NSStoryboard *__mainStoryboard = nil; // Instance methods... - (void) dealloc { - RELEASE(_transform); + RELEASE(_scenes); [super dealloc]; } @@ -158,7 +181,7 @@ static NSStoryboard *__mainStoryboard = nil; - (id) instantiateInitialControllerWithCreator: (NSStoryboardControllerCreator)block { - return [self instantiateControllerWithIdentifier: [_transform initialViewControllerId] + return [self instantiateControllerWithIdentifier: @"" // [_transform initialViewControllerId] creator: block]; } @@ -172,6 +195,8 @@ static NSStoryboard *__mainStoryboard = nil; creator: (NSStoryboardControllerCreator)block { id result = nil; + + /* NSMutableArray *topLevelObjects = [NSMutableArray arrayWithCapacity: 5]; NSDictionary *table = [NSDictionary dictionaryWithObjectsAndKeys: topLevelObjects, NSNibTopLevelObjects, @@ -260,6 +285,8 @@ static NSStoryboard *__mainStoryboard = nil; { CALL_BLOCK(block, self); } + */ + return result; } @end From 12590eaab12e7d0971c581842c9035cfe7caff10 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 13 May 2024 12:42:18 -0400 Subject: [PATCH 02/10] Minor change to unpack 'scenes' --- Source/GSXib5KeyedUnarchiver.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index f1fe1033e..5d5c77eb0 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -231,6 +231,7 @@ static NSArray *XmlBoolDefaultYes = nil; @"NSStackViewContainer", @"middleViews", @"NSStackViewContainer", @"endViews", @"GSScene", @"scene", + @"NSMutableArray", @"scenes", nil]; RETAIN(XmlTagToObjectClassMap); From e8d438e6f919faedb2911f09190cb97220c9fdbe Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 13 May 2024 13:25:07 -0400 Subject: [PATCH 03/10] Update GSScene to use NSMutableArray --- Source/GSScene.h | 8 ++++---- Source/GSScene.m | 6 +++--- Source/GSXib5KeyedUnarchiver.m | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Source/GSScene.h b/Source/GSScene.h index 8f23069c9..e39815445 100644 --- a/Source/GSScene.h +++ b/Source/GSScene.h @@ -32,21 +32,21 @@ extern "C" { #endif -@class NSArray; +@class NSMutableArray; @class NSString; @interface GSScene : NSObject { NSString *_sceneID; - NSArray *_objects; + NSMutableArray *_objects; NSPoint _canvasLocation; } - (NSString *) sceneID; - (void) setSceneID: (NSString *)sceneID; -- (NSArray *) objects; -- (void) setObjects: (NSArray *)objects; +- (NSMutableArray *) objects; +- (void) setObjects: (NSMutableArray *)objects; - (NSPoint) canvasLocation; - (void) setCanvasLocation: (NSPoint)point; diff --git a/Source/GSScene.m b/Source/GSScene.m index eef41f601..bf91a3fd1 100644 --- a/Source/GSScene.m +++ b/Source/GSScene.m @@ -57,14 +57,14 @@ ASSIGN(_sceneID, sceneID); } -- (NSArray *) objects +- (NSMutableArray *) objects { return _objects; } -- (void) setObjects: (NSArray *)objects +- (void) setObjects: (NSMutableArray *)objects { - ASSIGNCOPY(_objects, objects); + ASSIGN(_objects, objects); } - (NSPoint) canvasLocation diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 5d5c77eb0..862fdeab7 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -70,6 +70,7 @@ #import "AppKit/NSView.h" #import "GSCodingFlags.h" +#import "GSScene.h" #define DEBUG_XIB5 0 From d3661d974c9d558ed6a03ea48aac1946a7ebd879 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 13 May 2024 14:19:03 -0400 Subject: [PATCH 04/10] Remove GSStoryboardTransform.[hm] --- Source/GNUmakefile | 1 - Source/GSStoryboardTransform.h | 121 ----- Source/GSStoryboardTransform.m | 888 --------------------------------- 3 files changed, 1010 deletions(-) delete mode 100644 Source/GSStoryboardTransform.h delete mode 100644 Source/GSStoryboardTransform.m diff --git a/Source/GNUmakefile b/Source/GNUmakefile index e7dd7fbde..9d4d0ad85 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -346,7 +346,6 @@ GSToolTips.m \ GSToolbarView.m \ GSToolbarCustomizationPalette.m \ GSStandardWindowDecorationView.m \ -GSStoryboardTransform.m \ GSWindowDecorationView.m \ GSPrinting.m \ GSPrintOperation.m \ 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 From 2ae0dbc0da7272c69e47d00b17f7ac33b27af0df Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 14 May 2024 13:42:13 -0400 Subject: [PATCH 05/10] Add version of GSStoryboaddKeyedUnarchiver --- Source/GNUmakefile | 1 + Source/GSStoryboardKeyedUnarchiver.h | 43 ++++++++++++++++++++++++++++ Source/GSStoryboardKeyedUnarchiver.m | 30 +++++++++++++++++++ Source/GSXib5KeyedUnarchiver.h | 1 + Source/GSXib5KeyedUnarchiver.m | 5 ++++ Source/GSXibKeyedUnarchiver.m | 13 +++++++-- 6 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 Source/GSStoryboardKeyedUnarchiver.h create mode 100644 Source/GSStoryboardKeyedUnarchiver.m diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 9d4d0ad85..18eb0c31d 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -346,6 +346,7 @@ GSToolTips.m \ GSToolbarView.m \ GSToolbarCustomizationPalette.m \ GSStandardWindowDecorationView.m \ +GSStoryboardKeyedUnarchiver.m \ GSWindowDecorationView.m \ GSPrinting.m \ GSPrintOperation.m \ diff --git a/Source/GSStoryboardKeyedUnarchiver.h b/Source/GSStoryboardKeyedUnarchiver.h new file mode 100644 index 000000000..17347e1cb --- /dev/null +++ b/Source/GSStoryboardKeyedUnarchiver.h @@ -0,0 +1,43 @@ +/* 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 + +@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..678389338 --- /dev/null +++ b/Source/GSStoryboardKeyedUnarchiver.m @@ -0,0 +1,30 @@ +/* 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 "GSStoryboardKeyedUnarchiver.h" + +@implementation GSStoryboardKeyedUnarchiver + +@end + diff --git a/Source/GSXib5KeyedUnarchiver.h b/Source/GSXib5KeyedUnarchiver.h index 1ce296143..c74a3ac63 100644 --- a/Source/GSXib5KeyedUnarchiver.h +++ b/Source/GSXib5KeyedUnarchiver.h @@ -41,6 +41,7 @@ GSXibElement *_orderedObjects; GSXibElement *_flattenedProperties; GSXibElement *_runtimeAttributes; + GSXibElement *_scenes; NSMutableDictionary *_orderedObjectsDict; NSArray *_resources; } diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 862fdeab7..3621ddde8 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -747,6 +747,11 @@ static NSArray *XmlBoolDefaultYes = nil; @"connectionRecords", @"key", nil]]; + _scenes = [[GSXibElement alloc] initWithType: @"array" + andAttributes: [NSDictionary dictionaryWithObjectsAndKeys: + @"scenes", @"key", + nil]]; + // objectRecords... [_objectRecords setElement: _orderedObjects forKey: @"orderedObjects"]; diff --git a/Source/GSXibKeyedUnarchiver.m b/Source/GSXibKeyedUnarchiver.m index 7ca9b6bc4..4bf3f5e3e 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,6 +52,7 @@ NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data options: 0 error: NULL]; + if (document == nil) { return NO; @@ -63,6 +67,7 @@ return [documentNodes count] != 0; } #else + // We now default to checking XIB 5 versions return YES; #endif @@ -75,6 +80,7 @@ NSXMLDocument *document = [[NSXMLDocument alloc] initWithData: data options: 0 error: NULL]; + if (document == nil) { return NO; @@ -82,15 +88,16 @@ else { // Test to see if this is an Xcode 5 XIB... - NSArray *nodes = [document nodesForXPath: @"/scene" error: NULL]; + 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; } #else + // We now default to checking XIB 5 versions - return YES; + return NO; #endif } @@ -100,7 +107,7 @@ if ([self checkStoryboard: data]) { - unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; + unarchiver = [[GSStoryboardKeyedUnarchiver alloc] initForReadingWithData: data]; } else if ([self checkXib5: data]) { From 7764330b98e5ada946e910668e3c10ab1c157c0f Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 14 May 2024 13:49:44 -0400 Subject: [PATCH 06/10] Move scenes to GSStoryboardKeyedUnarchiver --- Source/GSStoryboardKeyedUnarchiver.h | 4 +++- Source/GSStoryboardKeyedUnarchiver.m | 14 ++++++++++++++ Source/GSXib5KeyedUnarchiver.h | 1 - Source/GSXib5KeyedUnarchiver.m | 5 ----- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Source/GSStoryboardKeyedUnarchiver.h b/Source/GSStoryboardKeyedUnarchiver.h index 17347e1cb..e03e3fa44 100644 --- a/Source/GSStoryboardKeyedUnarchiver.h +++ b/Source/GSStoryboardKeyedUnarchiver.h @@ -32,7 +32,9 @@ extern "C" { #endif @interface GSStoryboardKeyedUnarchiver : GSXib5KeyedUnarchiver - +{ + GSXibElement *_scenes; +} @end #if defined(__cplusplus) diff --git a/Source/GSStoryboardKeyedUnarchiver.m b/Source/GSStoryboardKeyedUnarchiver.m index 678389338..f2974a410 100644 --- a/Source/GSStoryboardKeyedUnarchiver.m +++ b/Source/GSStoryboardKeyedUnarchiver.m @@ -22,9 +22,23 @@ 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/GSXib5KeyedUnarchiver.h b/Source/GSXib5KeyedUnarchiver.h index c74a3ac63..1ce296143 100644 --- a/Source/GSXib5KeyedUnarchiver.h +++ b/Source/GSXib5KeyedUnarchiver.h @@ -41,7 +41,6 @@ GSXibElement *_orderedObjects; GSXibElement *_flattenedProperties; GSXibElement *_runtimeAttributes; - GSXibElement *_scenes; NSMutableDictionary *_orderedObjectsDict; NSArray *_resources; } diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 3621ddde8..862fdeab7 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -747,11 +747,6 @@ static NSArray *XmlBoolDefaultYes = nil; @"connectionRecords", @"key", nil]]; - _scenes = [[GSXibElement alloc] initWithType: @"array" - andAttributes: [NSDictionary dictionaryWithObjectsAndKeys: - @"scenes", @"key", - nil]]; - // objectRecords... [_objectRecords setElement: _orderedObjects forKey: @"orderedObjects"]; From 463a78a4f7d8a722f89f67f781b0392e67d7e34d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 18 May 2024 11:53:57 -0400 Subject: [PATCH 07/10] Update scenes and update prefix handling for XIB decoding --- Source/GNUmakefile | 1 + Source/GSScene.m | 1 + Source/GSScenes.h | 43 ++++++++++++++++++++++++++++++++++ Source/GSScenes.m | 30 ++++++++++++++++++++++++ Source/GSStoryboardLoader.m | 8 +++++-- Source/GSXib5KeyedUnarchiver.m | 7 +++--- Source/GSXibKeyedUnarchiver.m | 17 ++++---------- 7 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 Source/GSScenes.h create mode 100644 Source/GSScenes.m diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 18eb0c31d..e60c8028c 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -332,6 +332,7 @@ GSGormLoading.m \ GSIconManager.m \ GSImageMagickImageRep.m \ GSNibLoading.m \ +GSScenes.m \ GSTheme.m \ GSThemeDrawing.m \ GSThemeInspector.m \ diff --git a/Source/GSScene.m b/Source/GSScene.m index bf91a3fd1..dd0e2821d 100644 --- a/Source/GSScene.m +++ b/Source/GSScene.m @@ -81,6 +81,7 @@ - (instancetype) initWithCoder: (NSCoder *)coder { + NSLog(@"Decoding GSScene"); if ([coder allowsKeyedCoding]) { if ([coder containsValueForKey: @"NSSceneID"]) diff --git a/Source/GSScenes.h b/Source/GSScenes.h new file mode 100644 index 000000000..9e7ae01fa --- /dev/null +++ b/Source/GSScenes.h @@ -0,0 +1,43 @@ +/* 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 + +#if defined(__cplusplus) +extern "C" { +#endif + +@interface GSScenes : NSObject + +@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..ee0aeb75b --- /dev/null +++ b/Source/GSScenes.m @@ -0,0 +1,30 @@ +/* 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 + +@end + diff --git a/Source/GSStoryboardLoader.m b/Source/GSStoryboardLoader.m index 226a9e478..9761f7669 100644 --- a/Source/GSStoryboardLoader.m +++ b/Source/GSStoryboardLoader.m @@ -184,13 +184,17 @@ if (unarchiver != nil) { + NSArray *rootObjects; IBObjectContainer *objects; NSDebugLLog(@"XIB", @"Invoking unarchiver"); [unarchiver setObjectZone: zone]; - // rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; + rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; - NSLog(@"objects %@", objects); + + // NSLog(@"root objects %@", rootObjects); + // NSLog(@"objects %@", objects); + /* [self awake: rootObjects inContainer: objects diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 862fdeab7..384916b4c 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -70,6 +70,7 @@ #import "AppKit/NSView.h" #import "GSCodingFlags.h" +#import "GSScenes.h" #import "GSScene.h" #define DEBUG_XIB5 0 @@ -231,8 +232,8 @@ static NSArray *XmlBoolDefaultYes = nil; @"NSStackViewContainer", @"beginningViews", @"NSStackViewContainer", @"middleViews", @"NSStackViewContainer", @"endViews", - @"GSScene", @"scene", - @"NSMutableArray", @"scenes", + // @"GSScene", @"scene", + // @"NSMutableArray", @"scenes", nil]; RETAIN(XmlTagToObjectClassMap); @@ -242,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", diff --git a/Source/GSXibKeyedUnarchiver.m b/Source/GSXibKeyedUnarchiver.m index 4bf3f5e3e..b77501b2a 100644 --- a/Source/GSXibKeyedUnarchiver.m +++ b/Source/GSXibKeyedUnarchiver.m @@ -53,11 +53,7 @@ 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]; @@ -66,6 +62,8 @@ // specific to check here... return [documentNodes count] != 0; } + + return NO; #else // We now default to checking XIB 5 versions @@ -81,11 +79,7 @@ options: 0 error: NULL]; - if (document == nil) - { - return NO; - } - else + if (document) { // Test to see if this is an Xcode 5 XIB... NSArray *nodes = [document nodesForXPath: @"/scenes" error: NULL]; @@ -94,11 +88,10 @@ // specific to check here... return [nodes count] != 0; } -#else +#endif // We now default to checking XIB 5 versions return NO; -#endif } + (NSKeyedUnarchiver *) unarchiverForReadingWithData: (NSData *)data From f133faf70b04c62454889124d1a95ce65e83943d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 18 May 2024 23:24:04 -0400 Subject: [PATCH 08/10] Update scenes --- Source/GSScenes.h | 9 +++++++- Source/GSScenes.m | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Source/GSScenes.h b/Source/GSScenes.h index 9e7ae01fa..373386e5d 100644 --- a/Source/GSScenes.h +++ b/Source/GSScenes.h @@ -26,12 +26,19 @@ #define _GSScenes_h_GNUSTEP_GUI_INCLUDE #import +#import #if defined(__cplusplus) extern "C" { #endif -@interface GSScenes : NSObject +@interface GSScenes : NSObject +{ + NSMutableArray *_scenes; +} + +- (NSMutableArray *) scenes; +- (void) setScenes: (NSMutableArray *)scenes; @end diff --git a/Source/GSScenes.m b/Source/GSScenes.m index ee0aeb75b..e7e9d454e 100644 --- a/Source/GSScenes.m +++ b/Source/GSScenes.m @@ -26,5 +26,57 @@ @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 From 0ded1feee045ef225206945a6005289e63507693 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 12 May 2025 08:25:13 -0400 Subject: [PATCH 09/10] Changes to refactor storyboard loader --- Headers/Additions/GNUstepGUI/GSXibLoading.h | 14 +++++++++++ Headers/AppKit/NSStoryboard.h | 2 ++ Source/GSStoryboardLoader.m | 12 +++++---- Source/GSXib5KeyedUnarchiver.m | 4 +-- Source/GSXibKeyedUnarchiver.m | 11 +++++---- Source/NSStoryboard.m | 27 +++++---------------- 6 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Headers/Additions/GNUstepGUI/GSXibLoading.h b/Headers/Additions/GNUstepGUI/GSXibLoading.h index 346b929c5..33816cb18 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; @@ -70,6 +74,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBConnection: NSObject { NSString *label; @@ -84,23 +89,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 +118,7 @@ - (IBConnection *) connection; @end +APPKIT_EXPORT_CLASS @interface IBToolTipAttribute: NSObject { NSString *name; @@ -117,6 +127,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBInitialTabViewItemAttribute: NSObject { NSString *name; @@ -125,6 +136,7 @@ } @end +APPKIT_EXPORT_CLASS @interface IBObjectRecord: NSObject { id objectID; @@ -137,6 +149,7 @@ - (id) objectID; @end +APPKIT_EXPORT_CLASS @interface IBMutableOrderedSet: NSObject { NSArray *orderedObjects; @@ -145,6 +158,7 @@ - (id) objectWithObjectID: (id)objID; @end +APPKIT_EXPORT_CLASS @interface IBObjectContainer: NSObject { NSMutableArray *connectionRecords; diff --git a/Headers/AppKit/NSStoryboard.h b/Headers/AppKit/NSStoryboard.h index 29dc911ed..4e9e65798 100644 --- a/Headers/AppKit/NSStoryboard.h +++ b/Headers/AppKit/NSStoryboard.h @@ -34,6 +34,7 @@ extern "C" { #endif @class NSBundle; +@class NSData; @class NSMutableDictionary; @class NSString; @@ -45,6 +46,7 @@ DEFINE_BLOCK_TYPE(NSStoryboardControllerCreator, NSCoder*, id); APPKIT_EXPORT_CLASS @interface NSStoryboard : NSObject { + NSData *_data; NSMutableDictionary *_scenes; } diff --git a/Source/GSStoryboardLoader.m b/Source/GSStoryboardLoader.m index 9761f7669..7d9b570b6 100644 --- a/Source/GSStoryboardLoader.m +++ b/Source/GSStoryboardLoader.m @@ -39,6 +39,7 @@ #import "AppKit/NSApplication.h" #import "AppKit/NSMenu.h" #import "AppKit/NSNib.h" + #import "GNUstepGUI/GSModelLoaderFactory.h" #import "GNUstepGUI/GSNibLoading.h" #import "GNUstepGUI/GSXibLoading.h" @@ -122,9 +123,9 @@ return; } - NSDebugLLog(@"XIB", @"First object %@", [rootObjects objectAtIndex: 0]); - NSDebugLLog(@"XIB", @"Second object %@", [rootObjects objectAtIndex: 1]); - NSDebugLLog(@"XIB", @"Third object %@", [rootObjects objectAtIndex: 2]); + 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]; @@ -187,7 +188,7 @@ NSArray *rootObjects; IBObjectContainer *objects; - NSDebugLLog(@"XIB", @"Invoking unarchiver"); + NSDebugLLog(@"Storyboard", @"Invoking unarchiver"); [unarchiver setObjectZone: zone]; rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; @@ -231,7 +232,7 @@ NSFileManager *mgr = [NSFileManager defaultManager]; BOOL isDir = NO; - NSDebugLLog(@"XIB", @"Loading Storyboard `%@'...\n", fileName); + NSDebugLLog(@"Storyboard", @"Loading Storyboard `%@'...\n", fileName); if ([mgr fileExistsAtPath: fileName isDirectory: &isDir]) { if (isDir == NO) @@ -247,6 +248,7 @@ { NSLog(@"Storyboard file specified %@, could not be found.", fileName); } + return nil; } diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 051aae905..0f9bb33ab 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -233,7 +233,7 @@ static NSArray *XmlBoolDefaultYes = nil; @"NSStackViewContainer", @"middleViews", @"NSStackViewContainer", @"endViews", // @"GSScene", @"scene", - // @"NSMutableArray", @"scenes", + @"NSMutableArray", @"scenes", nil]; RETAIN(XmlTagToObjectClassMap); @@ -704,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 b77501b2a..04f7e1356 100644 --- a/Source/GSXibKeyedUnarchiver.m +++ b/Source/GSXibKeyedUnarchiver.m @@ -98,11 +98,12 @@ { NSKeyedUnarchiver *unarchiver = nil; - if ([self checkStoryboard: data]) - { - unarchiver = [[GSStoryboardKeyedUnarchiver alloc] initForReadingWithData: data]; - } - else if ([self checkXib5: data]) + // if ([self checkStoryboard: data]) + // { + // unarchiver = [[GSStoryboardKeyedUnarchiver alloc] initForReadingWithData: data]; + // } + // else + if ([self checkXib5: data]) { unarchiver = [[GSXib5KeyedUnarchiver alloc] initForReadingWithData: data]; } diff --git a/Source/NSStoryboard.m b/Source/NSStoryboard.m index befcd6e8b..b738b133e 100644 --- a/Source/NSStoryboard.m +++ b/Source/NSStoryboard.m @@ -111,32 +111,17 @@ static NSStoryboard *__mainStoryboard = nil; self = [super init]; if (self != nil) { - BOOL success = NO; - - success = [bundle loadNibFile: name - externalNameTable: nil - withZone: NSDefaultMallocZone()]; + NSString *path = [bundle pathForResource: name + ofType: @"storyboard"]; + _data = [NSData dataWithContentsOfFile: path]; - if (success) + if (_data != nil) { } - /* - if (unarchiver != nil) + else { - NSArray *rootObjects; - IBObjectContainer *objects; - - NSDebugLLog(@"XIB", @"Invoking unarchiver"); - [unarchiver setObjectZone: zone]; - rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; - objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; - NSDebugLLog(@"XIB", @"rootObjects %@", rootObjects); - [self awake: rootObjects - inContainer: objects - withContext: context]; - loaded = YES; + NSLog(@"Failed to load storyboard with name \"%@\" at \"%@.\"", name, path); } - */ } return self; } From 92d03bb28c0c9a059cfe768d5e5542be0b9755e9 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 12 May 2025 18:43:42 -0400 Subject: [PATCH 10/10] More changes and refactoring --- Headers/Additions/GNUstepGUI/GSXibLoading.h | 8 ++++++++ Source/GSStoryboardLoader.m | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Headers/Additions/GNUstepGUI/GSXibLoading.h b/Headers/Additions/GNUstepGUI/GSXibLoading.h index 33816cb18..3d8da3e5c 100644 --- a/Headers/Additions/GNUstepGUI/GSXibLoading.h +++ b/Headers/Additions/GNUstepGUI/GSXibLoading.h @@ -68,6 +68,7 @@ APPKIT_EXPORT_CLASS } @end +APPKIT_EXPORT_CLASS @interface IBClassDescriber: NSObject { NSMutableArray *referencedPartialClassDescriptions; @@ -210,4 +211,11 @@ APPKIT_EXPORT_CLASS @end +APPKIT_EXPORT_CLASS +@interface IBScenesContaienr : NSObject +{ + IBMutableOrderedSet *_sceneRecords; +} +@end + #endif diff --git a/Source/GSStoryboardLoader.m b/Source/GSStoryboardLoader.m index 7d9b570b6..d7c97c484 100644 --- a/Source/GSStoryboardLoader.m +++ b/Source/GSStoryboardLoader.m @@ -187,15 +187,18 @@ { NSArray *rootObjects; IBObjectContainer *objects; - + IBScenesContainer *scenes; + NSDebugLLog(@"Storyboard", @"Invoking unarchiver"); [unarchiver setObjectZone: zone]; rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; - - // NSLog(@"root objects %@", rootObjects); - // NSLog(@"objects %@", objects); + scenes = [unarchiver decodeObjectForkey: @"IBDocument.Scenes"]; + NSLog(@"root objects = %@", rootObjects); + NSLog(@"objects = %@", objects); + NSLog(@"scenes = %@", scenes) + /* [self awake: rootObjects inContainer: objects