diff --git a/GormCore/Plugins/Xib/GormXIBModelGenerator.h b/GormCore/Plugins/Xib/GormXIBModelGenerator.h new file mode 100644 index 00000000..47e09a77 --- /dev/null +++ b/GormCore/Plugins/Xib/GormXIBModelGenerator.h @@ -0,0 +1,69 @@ +/** GormXIBKeyedArchiver + + Interface of GormXIBKeyedArchiver + + Copyright (C) 2023 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: 2023 + + This file is part of the GNUstep GUI 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; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef GormXIBModelGenerator_H_INCLUDE +#define GormXIBModelGenerator_H_INCLUDE + +#import + +@class GormDocument; +@class NSMutableDictionary; +@class NSString; +@class NSData; + +@interface GormXIBModelGenerator : NSObject +{ + GormDocument *_gormDocument; + NSMutableDictionary *_mappingDictionary; +} + +/** + * Returns an autoreleased GormXIBModelGenerator object; + */ ++ (instancetype) xibWithGormDocument: (GormDocument *)doc; + +/** + * Initialize with GormDocument object to parse the XML from or into. + */ +- (instancetype) initWithGormDocument: (GormDocument *)doc; + +/** + * The data for the XIB document that has been created + */ +- (NSData *) data; + +/** + * Exports XIB file. This method starts the process and calls + * another method that recurses through the objects in the model and + * maps any properties as appropriate when exporting. + */ +- (BOOL) exportXIBDocumentWithName: (NSString *)name; + +@end + +#endif // GormXIBModelGenerator_H_INCLUDE diff --git a/GormCore/Plugins/Xib/GormXIBModelGenerator.m b/GormCore/Plugins/Xib/GormXIBModelGenerator.m new file mode 100644 index 00000000..0c0cccb5 --- /dev/null +++ b/GormCore/Plugins/Xib/GormXIBModelGenerator.m @@ -0,0 +1,341 @@ +/** GormXIBKeyedArchiver + + Interface of GormXIBKeyedArchiver + + Copyright (C) 2023 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: 2023 + + This file is part of the GNUstep GUI 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; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import + +#import "GormDocument.h" +#import "GormDocumentController.h" +#import "GormFilePrefsManager.h" +#import "GormProtocol.h" +#import "GormPrivate.h" + +#import "GormXIBModelGenerator.h" + +@implementation GormXIBModelGenerator + +/** + * Returns an autoreleast GormXIBDocument object; + */ ++ (instancetype) xibWithGormDocument: (GormDocument *)doc +{ + return AUTORELEASE([[self alloc] initWithGormDocument: doc]); +} + +/** + * Initialize with GormDocument object to parse the XML from or into. + */ +- (instancetype) initWithGormDocument: (GormDocument *)doc +{ + self = [super init]; + if (self != nil) + { + ASSIGN(_gormDocument, doc); + _mappingDictionary = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void) dealloc +{ + DESTROY(_gormDocument); + DESTROY(_mappingDictionary); + + [super dealloc]; +} + +- (NSString *) _convertName: (NSString *)className +{ + NSString *result = [className stringByReplacingOccurrencesOfString: @"NS" + withString: @""]; + + // Try removing other prefixes... + result = [result stringByReplacingOccurrencesOfString: @"GS" + withString: @""]; + result = [result stringByReplacingOccurrencesOfString: @"Gorm" + withString: @""]; + + // Lowercase the first letter of the class to make the element name + NSString *first = [[result substringToIndex: 1] lowercaseString]; + NSString *rest = [result substringFromIndex: 1]; + + result = [NSString stringWithFormat: @"%@%@", first, rest]; + + return result; +} + +- (NSString *) _createIdentifierForObject: (id)obj +{ + NSString *result = nil; + + if ([obj isKindOfClass: [GormObjectProxy class]]) + { + NSString *className = [obj className]; + + if ([className isEqualToString: @"NSApplication"]) + { + result = @"-3"; + } + else if ([className isEqualToString: @"NSOwner"]) + { + result = @"-2"; + } + else if ([className isEqualToString: @"NSFirst"]) + { + result = @"-1"; + } + } + else + { + result = [_gormDocument nameForObject: obj]; + } + + return result; +} + +- (NSString *) _userLabelForObject: (id)obj +{ + NSString *result = nil; + + if ([obj isKindOfClass: [GormObjectProxy class]]) + { + NSString *className = [obj className]; + + if ([className isEqualToString: @"NSApplication"]) + { + result = @"Application"; + } + else if ([className isEqualToString: @"NSOwner"]) + { + result = @"File's Owner"; + } + else if ([className isEqualToString: @"NSFirst"]) + { + result = @"First Responder"; + } + } + + return result; +} + +- (void) _collectObjectsFromObject: (id)obj + withNode: (NSXMLElement *)node +{ + NSString *ident = [self _createIdentifierForObject: obj]; + + if (ident != nil) + { + NSString *className = NSStringFromClass([obj class]); + NSString *elementName = [self _convertName: className]; + NSXMLElement *elem = [NSXMLNode elementWithName: elementName]; + NSXMLNode *attr = [NSXMLNode attributeWithName: @"id" stringValue: ident]; + [elem addAttribute: attr]; + + NSString *userLabel = [self _userLabelForObject: obj]; + if (userLabel != nil) + { + attr = [NSXMLNode attributeWithName: @"userLabel" stringValue: userLabel]; + [elem addAttribute: attr]; + } + + if ([obj isKindOfClass: [GormObjectProxy class]] || + [obj respondsToSelector: @selector(className)]) + { + if ([className isEqualToString: [obj className]] == NO) + { + className = [obj className]; + attr = [NSXMLNode attributeWithName: @"customClass" stringValue: className]; + [elem addAttribute: attr]; + } + } + + [node addChild: elem]; + + // If the object responds to "title" get that and add it to the XML + if ([obj respondsToSelector: @selector(title)]) + { + NSString *title = [obj title]; + if (title != nil) + { + attr = [NSXMLNode attributeWithName: @"title" stringValue: title]; + [elem addAttribute: attr]; + } + } + + // For each different class, recurse through the structure as needed. + if ([obj isKindOfClass: [NSMenu class]] || + [obj isKindOfClass: [NSPopUpButton class]]) + { + NSArray *items = [obj itemArray]; + NSEnumerator *en = [items objectEnumerator]; + id item = nil; + while ((item = [en nextObject]) != nil) + { + [self _collectObjectsFromObject: item + withNode: elem]; + } + } + else if ([obj isKindOfClass: [NSMenuItem class]]) + { + NSMenu *sm = [obj submenu]; + if (sm != nil) + { + [self _collectObjectsFromObject: sm + withNode: elem]; + } + } + else if ([obj isKindOfClass: [NSWindow class]]) + { + [self _collectObjectsFromObject: [obj contentView] + withNode: elem]; + } + else if ([obj isKindOfClass: [NSView class]]) + { + NSArray *subviews = [obj subviews]; + NSEnumerator *en = [subviews objectEnumerator]; + id v = nil; + + while ((v = [en nextObject]) != nil) + { + [self _collectObjectsFromObject: v + withNode: elem]; + } + } + } +} + +- (void) _buildXIBDocumentWithParentNode: (NSXMLElement *)parentNode +{ + NSEnumerator *en = [[_gormDocument topLevelObjects] objectEnumerator]; + id o = nil; + + [_gormDocument deactivateEditors]; + while ((o = [en nextObject]) != nil) + { + [self _collectObjectsFromObject: o + withNode: parentNode]; + } + [_gormDocument reactivateEditors]; +} + +- (NSData *) data +{ + NSString *plugInId = @"com.apple.InterfaceBuilder.CocoaPlugin"; // @"gnu.gnustep.Gorm"; + NSString *typeId = @"com.apple.InterfaceBuilder3.Cocoa.XIB"; // @"gnu.gnustep.Gorm"; + // NSString *toolId = @"gnu.gnustep.Gorm"; + // NSString *toolName = @"Gorm"; + NSString *toolVersion = @"21507"; // [NSString stringWithFormat: @"%d", [GormFilePrefsManager currentVersion]]; + + // id delegate = [NSApp delegate]; + + // Build root element... + NSXMLElement *rootElement = [NSXMLNode elementWithName: @"document"]; + NSXMLNode *attr = [NSXMLNode namespaceWithName: @"type" + stringValue: typeId]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"version" stringValue: @"3.0"]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"toolsVersion" stringValue: toolVersion]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"targetRuntime" stringValue: @"MacOSX.Cocoa"]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"useAutolayout" stringValue: @"YES"]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"propertyAccessControl" stringValue: @"none"]; + [rootElement addAttribute: attr]; + + attr = [NSXMLNode attributeWithName: @"customObjectInstantiationMethod" stringValue: @"direct"]; + [rootElement addAttribute: attr]; + + // Build dependencies... + NSXMLElement *dependencies = [NSXMLNode elementWithName: @"dependencies"]; + NSXMLElement *deployment = [NSXMLNode elementWithName: @"deployment"]; + attr = [NSXMLNode attributeWithName: @"identifier" stringValue: @"macosx"]; + [deployment addAttribute: attr]; + [dependencies addChild: deployment]; + + NSXMLElement *plugIn = [NSXMLNode elementWithName: @"plugIn"]; + attr = [NSXMLNode attributeWithName: @"identifier" stringValue: plugInId]; + [plugIn addAttribute: attr]; + attr = [NSXMLNode attributeWithName: @"version" stringValue: toolVersion]; + [plugIn addAttribute: attr]; + [dependencies addChild: plugIn]; + + NSXMLElement *capability = [NSXMLNode elementWithName: @"capability"]; + attr = [NSXMLNode attributeWithName: @"name" stringValue: plugInId]; + [capability addAttribute: attr]; + attr = [NSXMLNode attributeWithName: @"minToolsVersion" stringValue: toolVersion]; + [capability addAttribute: attr]; + [dependencies addChild: capability]; + [rootElement addChild: dependencies]; + + NSXMLDocument *xibDocument = [NSXMLNode documentWithRootElement: rootElement]; + NSXMLElement *objects = [NSXMLNode elementWithName: @"objects"]; + + // add body to document... + [rootElement addChild: objects]; + + // Recursively build the XIB document from the GormDocument... + [self _buildXIBDocumentWithParentNode: objects]; + + NSData *data = [xibDocument XMLDataWithOptions: NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement ]; + + return data; +} + +- (BOOL) exportXIBDocumentWithName: (NSString *)name +{ + BOOL result = NO; + + if (name != nil) + { + NSData *data = [self data]; + NSString *xmlString = [[NSString alloc] initWithBytes: [data bytes] length: [data length] encoding: NSUTF8StringEncoding]; + + AUTORELEASE(xmlString); + result = [xmlString writeToFile: name atomically: YES]; + } + + return result; +} + +@end diff --git a/GormCore/Plugins/Xib/GormXibWrapperBuilder.m b/GormCore/Plugins/Xib/GormXibWrapperBuilder.m new file mode 100644 index 00000000..e1d95c63 --- /dev/null +++ b/GormCore/Plugins/Xib/GormXibWrapperBuilder.m @@ -0,0 +1,53 @@ +/* GormWrapperBuilder + * + * Copyright (C) 2006-2013 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#import +#import + +#import + +#import "GormXIBModelGenerator.h" + +@interface GormXibWrapperBuilder : GormWrapperBuilder +@end + +@implementation GormXibWrapperBuilder + ++ (NSString *) fileType +{ + return @"GSXibFileType"; +} + +- (NSMutableDictionary *)buildFileWrapperDictionaryWithDocument: (GormDocument *)doc +{ + GormXIBModelGenerator *generator = [GormXIBModelGenerator xibWithGormDocument: doc]; + NSData *data = [generator data]; + NSMutableDictionary *fileWrappers = [NSMutableDictionary dictionary]; + NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: data]; + + [fileWrappers setObject: fileWrapper forKey: @"file.xib"]; + + return fileWrappers; +} +@end