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