1/* <title>GSXibLoader</title> 2 3 <abstract>Xib (Cocoa XML) model loader</abstract> 4 5 Copyright (C) 2010, 2011 Free Software Foundation, Inc. 6 7 Written by: Fred Kiefer <FredKiefer@gmx.de> 8 Created: March 2010 9 10 This file is part of the GNUstep Base Library. 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; if not, write to the Free 24 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110 USA. 25*/ 26 27#import <Foundation/NSArray.h> 28#import <Foundation/NSAutoreleasePool.h> 29#import <Foundation/NSData.h> 30#import <Foundation/NSDebug.h> 31#import <Foundation/NSDictionary.h> 32#import <Foundation/NSException.h> 33#import <Foundation/NSFileManager.h> 34#import <Foundation/NSKeyedArchiver.h> 35#import <Foundation/NSKeyValueCoding.h> 36#import <Foundation/NSString.h> 37#import <Foundation/NSValue.h> 38 39#import "AppKit/NSApplication.h" 40#import "AppKit/NSMenu.h" 41#import "AppKit/NSNib.h" 42#import "GNUstepGUI/GSModelLoaderFactory.h" 43#import "GNUstepGUI/GSNibLoading.h" 44#import "GNUstepGUI/GSXibLoading.h" 45#import "GNUstepGUI/GSXibKeyedUnarchiver.h" 46 47@interface NSApplication (NibCompatibility) 48- (void) _setMainMenu: (NSMenu*)aMenu; 49@end 50 51@interface NSMenu (XibCompatibility) 52- (BOOL) _isMainMenu; 53@end 54 55@implementation NSMenu (XibCompatibility) 56 57- (BOOL) _isMainMenu 58{ 59 if (_name) 60 return [_name isEqualToString:@"_NSMainMenu"]; 61 return NO; 62} 63 64@end 65 66@interface GSXibLoader: GSModelLoader 67{ 68} 69@end 70 71@implementation GSXibLoader 72 73+ (NSString*) type 74{ 75 return @"xib"; 76} 77 78+ (float) priority 79{ 80 return 4.0; 81} 82 83- (void) awake: (NSArray *)rootObjects 84 withContext: (NSDictionary *)context 85{ 86 NSMutableArray *topLevelObjects = [context objectForKey: NSNibTopLevelObjects]; 87 id owner = [context objectForKey: NSNibOwner]; 88 NSEnumerator *en; 89 id obj; 90 NSUInteger index = 0; 91 92 if ([rootObjects count] == 0) 93 { 94 NSWarnMLog(@"No root objects in XIB!"); 95 return; 96 } 97 98 // Use the owner as first root object 99 [(NSCustomObject*)[rootObjects objectAtIndex: 0] setRealObject: owner]; 100 101 en = [rootObjects objectEnumerator]; 102 while ((obj = [en nextObject]) != nil) 103 { 104 index++; 105 106 if ([obj respondsToSelector: @selector(nibInstantiate)]) 107 { 108 obj = [obj nibInstantiate]; 109 } 110 111 // IGNORE file's owner, first responder and NSApplication instances... 112 if ((obj != nil) && (index > 3)) 113 { 114 [topLevelObjects addObject: obj]; 115 // All top level objects must be released by the caller to avoid 116 // leaking, unless they are going to be released by other nib 117 // objects on behalf of the owner. 118 RETAIN(obj); 119 } 120 121 if (([obj isKindOfClass: [NSMenu class]]) && 122 ([obj _isMainMenu])) 123 { 124 // add the menu... 125 [NSApp _setMainMenu: obj]; 126 } 127 } 128} 129 130- (void) awake: (NSArray *)rootObjects 131 inContainer: (id)objects 132 withContext: (NSDictionary *)context 133{ 134 [self awake: rootObjects withContext: context]; 135 136 // Load connections and awaken objects 137 if ([objects respondsToSelector: @selector(nibInstantiate)]) 138 { 139 [objects nibInstantiate]; 140 } 141} 142 143- (BOOL) loadModelData: (NSData *)data 144 externalNameTable: (NSDictionary *)context 145 withZone: (NSZone *)zone; 146{ 147 BOOL loaded = NO; 148 149 NS_DURING 150 { 151 if (data != nil) 152 { 153 NSKeyedUnarchiver *unarchiver = [GSXibKeyedUnarchiver unarchiverForReadingWithData: data]; 154 155 if (unarchiver != nil) 156 { 157 NSArray *rootObjects; 158 IBObjectContainer *objects; 159 160 NSDebugLLog(@"XIB", @"Invoking unarchiver"); 161 [unarchiver setObjectZone: zone]; 162 rootObjects = [unarchiver decodeObjectForKey: @"IBDocument.RootObjects"]; 163 objects = [unarchiver decodeObjectForKey: @"IBDocument.Objects"]; 164 NSDebugLLog(@"XIB", @"rootObjects %@", rootObjects); 165 [self awake: rootObjects 166 inContainer: objects 167 withContext: context]; 168 loaded = YES; 169 } 170 else 171 { 172 NSLog(@"Could not instantiate Xib unarchiver/Unable to parse Xib."); 173 } 174 } 175 else 176 { 177 NSLog(@"Data passed to Xib loading method is nil."); 178 } 179 } 180 NS_HANDLER 181 { 182 NSLog(@"Exception occurred while loading model: %@",[localException reason]); 183 } 184 NS_ENDHANDLER 185 186 if (loaded == NO) 187 { 188 NSLog(@"Failed to load Xib\n"); 189 } 190 191 return loaded; 192} 193 194- (NSData*) dataForFile: (NSString*)fileName 195{ 196 NSFileManager *mgr = [NSFileManager defaultManager]; 197 BOOL isDir = NO; 198 199 NSDebugLLog(@"XIB", @"Loading Xib `%@'...\n", fileName); 200 if ([mgr fileExistsAtPath: fileName isDirectory: &isDir]) 201 { 202 if (isDir == NO) 203 { 204 return [NSData dataWithContentsOfFile: fileName]; 205 } 206 else 207 { 208 NSLog(@"Xib file specified %@, is directory.", fileName); 209 } 210 } 211 else 212 { 213 NSLog(@"Xib file specified %@, could not be found.", fileName); 214 } 215 return nil; 216} 217 218@end 219