1 |
/** <title>GSNibTemplates</title> |
2 |
|
3 |
<abstract>Contains all of the private classes used in .gorm files.</abstract> |
4 |
|
5 |
Copyright (C) 2003 Free Software Foundation, Inc. |
6 |
|
7 |
Author: Gregory John Casamento |
8 |
Date: July 2003. |
9 |
|
10 |
This file is part of the GNUstep GUI Library. |
11 |
|
12 |
This library is free software; you can redistribute it and/or |
13 |
modify it under the terms of the GNU Library 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 |
Library General Public License for more details. |
21 |
|
22 |
You should have received a copy of the GNU Library General Public |
23 |
License along with this library; |
24 |
If not, write to the Free Software Foundation, |
25 |
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
26 |
*/ |
27 |
|
28 |
// #include "gnustep/gui/config.h" |
29 |
#include <Foundation/NSClassDescription.h> |
30 |
#include <Foundation/NSArchiver.h> |
31 |
#include <Foundation/NSArray.h> |
32 |
#include <Foundation/NSBundle.h> |
33 |
#include <Foundation/NSCoder.h> |
34 |
#include <Foundation/NSData.h> |
35 |
#include <Foundation/NSDictionary.h> |
36 |
#include <Foundation/NSDebug.h> |
37 |
#include <Foundation/NSEnumerator.h> |
38 |
#include <Foundation/NSException.h> |
39 |
#include <Foundation/NSInvocation.h> |
40 |
#include <Foundation/NSObjCRuntime.h> |
41 |
#include <Foundation/NSPathUtilities.h> |
42 |
#include <Foundation/NSFileManager.h> |
43 |
#include <Foundation/NSString.h> |
44 |
#include <Foundation/NSUserDefaults.h> |
45 |
#include <Foundation/NSKeyValueCoding.h> |
46 |
#include "AppKit/NSMenu.h" |
47 |
#include "AppKit/NSControl.h" |
48 |
#include "AppKit/NSImage.h" |
49 |
#include "AppKit/NSSound.h" |
50 |
#include "AppKit/NSView.h" |
51 |
#include "AppKit/NSTextView.h" |
52 |
#include "AppKit/NSWindow.h" |
53 |
#include <AppKit/NSNibLoading.h> |
54 |
#include <AppKit/NSNibConnector.h> |
55 |
#include <AppKit/NSApplication.h> |
56 |
#include <GNUstepBase/GSObjCRuntime.h> |
57 |
#include <GNUstepGUI/GSNibTemplates.h> |
58 |
|
59 |
static const int currentVersion = 1; // GSNibItem version number... |
60 |
|
61 |
@interface NSApplication (GSNibContainer) |
62 |
- (void)_deactivateVisibleWindow: (NSWindow *)win; |
63 |
@end |
64 |
|
65 |
@implementation NSApplication (GSNibContainer) |
66 |
/* Since awakeWithContext often gets called before the the app becomes |
67 |
active, [win -orderFront:] requests get ignored, so we add the window |
68 |
to the inactive list, so it gets sent an -orderFront when the app |
69 |
becomes active. */ |
70 |
- (void) _deactivateVisibleWindow: (NSWindow *)win |
71 |
{ |
72 |
if (_inactive) |
73 |
[_inactive addObject: win]; |
74 |
} |
75 |
@end |
76 |
|
77 |
/* |
78 |
* The GSNibContainer class manages the internals of a nib file. |
79 |
*/ |
80 |
@implementation GSNibContainer |
81 |
|
82 |
+ (void) initialize |
83 |
{ |
84 |
if (self == [GSNibContainer class]) |
85 |
{ |
86 |
[self setVersion: GNUSTEP_NIB_VERSION]; |
87 |
} |
88 |
} |
89 |
|
90 |
- (void) awakeWithContext: (NSDictionary*)context |
91 |
{ |
92 |
if (_isAwake == NO) |
93 |
{ |
94 |
NSEnumerator *enumerator; |
95 |
NSNibConnector *connection; |
96 |
NSString *key; |
97 |
NSArray *visible; |
98 |
NSMenu *menu; |
99 |
|
100 |
_isAwake = YES; |
101 |
/* |
102 |
* Add local entries into name table. |
103 |
*/ |
104 |
if ([context count] > 0) |
105 |
{ |
106 |
[nameTable addEntriesFromDictionary: context]; |
107 |
} |
108 |
|
109 |
/* |
110 |
* Now establish all connections by taking the names |
111 |
* stored in the connection objects, and replaciong them |
112 |
* with the corresponding values from the name table |
113 |
* before telling the connections to establish themselves. |
114 |
*/ |
115 |
enumerator = [connections objectEnumerator]; |
116 |
while ((connection = [enumerator nextObject]) != nil) |
117 |
{ |
118 |
id val; |
119 |
|
120 |
val = [nameTable objectForKey: [connection source]]; |
121 |
[connection setSource: val]; |
122 |
val = [nameTable objectForKey: [connection destination]]; |
123 |
[connection setDestination: val]; |
124 |
[connection establishConnection]; |
125 |
// release the connections, now that they have been established. |
126 |
RELEASE(connection); |
127 |
} |
128 |
|
129 |
/* |
130 |
* See if there is a main menu to be set. Report #4815, mainMenu |
131 |
* should be initialized before awakeFromNib is called. |
132 |
*/ |
133 |
menu = [nameTable objectForKey: @"NSMenu"]; |
134 |
if (menu != nil && [menu isKindOfClass: [NSMenu class]] == YES) |
135 |
{ |
136 |
[NSApp setMainMenu: menu]; |
137 |
} |
138 |
|
139 |
/* |
140 |
* Set the Services menu. |
141 |
* Report #5205, Services/Window menu does not behave correctly. |
142 |
*/ |
143 |
menu = [nameTable objectForKey: @"NSServicesMenu"]; |
144 |
if (menu != nil && [menu isKindOfClass: [NSMenu class]] == YES) |
145 |
{ |
146 |
[NSApp setServicesMenu: menu]; |
147 |
} |
148 |
|
149 |
/* |
150 |
* Set the Services menu. |
151 |
* Report #5205, Services/Window menu does not behave correctly. |
152 |
*/ |
153 |
menu = [nameTable objectForKey: @"NSWindowsMenu"]; |
154 |
if (menu != nil && [menu isKindOfClass: [NSMenu class]] == YES) |
155 |
{ |
156 |
[NSApp setWindowsMenu: menu]; |
157 |
} |
158 |
|
159 |
/* |
160 |
* Now tell all the objects that they have been loaded from |
161 |
* a nib. |
162 |
*/ |
163 |
enumerator = [nameTable keyEnumerator]; |
164 |
while ((key = [enumerator nextObject]) != nil) |
165 |
{ |
166 |
if ([context objectForKey: key] == nil || |
167 |
[key isEqualToString: @"NSOwner"]) // we want to send the message to the owner |
168 |
{ |
169 |
id o; |
170 |
|
171 |
o = [nameTable objectForKey: key]; |
172 |
if ([o respondsToSelector: @selector(awakeFromNib)]) |
173 |
{ |
174 |
[o awakeFromNib]; |
175 |
} |
176 |
} |
177 |
} |
178 |
|
179 |
/* |
180 |
* See if there are objects that should be made visible. |
181 |
*/ |
182 |
visible = [nameTable objectForKey: @"NSVisible"]; |
183 |
if (visible != nil |
184 |
&& [visible isKindOfClass: [NSArray class]] == YES) |
185 |
{ |
186 |
unsigned pos = [visible count]; |
187 |
|
188 |
while (pos-- > 0) |
189 |
{ |
190 |
NSWindow *win = [visible objectAtIndex: pos]; |
191 |
if ([NSApp isActive]) |
192 |
[win orderFront: self]; |
193 |
else |
194 |
[NSApp _deactivateVisibleWindow: win]; |
195 |
} |
196 |
} |
197 |
|
198 |
/* |
199 |
* Now remove any objects added from the context dictionary. |
200 |
*/ |
201 |
if ([context count] > 0) |
202 |
{ |
203 |
[nameTable removeObjectsForKeys: [context allKeys]]; |
204 |
} |
205 |
} |
206 |
} |
207 |
|
208 |
- (NSMutableArray*) connections |
209 |
{ |
210 |
return connections; |
211 |
} |
212 |
|
213 |
- (void) dealloc |
214 |
{ |
215 |
RELEASE(nameTable); |
216 |
RELEASE(connections); |
217 |
[super dealloc]; |
218 |
} |
219 |
|
220 |
- (void) encodeWithCoder: (NSCoder*)aCoder |
221 |
{ |
222 |
[aCoder encodeObject: nameTable]; |
223 |
[aCoder encodeObject: connections]; |
224 |
} |
225 |
|
226 |
- (id) init |
227 |
{ |
228 |
if ((self = [super init]) != nil) |
229 |
{ |
230 |
nameTable = [[NSMutableDictionary alloc] initWithCapacity: 8]; |
231 |
connections = [[NSMutableArray alloc] initWithCapacity: 8]; |
232 |
} |
233 |
return self; |
234 |
} |
235 |
|
236 |
- (id) initWithCoder: (NSCoder*)aCoder |
237 |
{ |
238 |
int version = [aCoder versionForClassName: @"GSNibContainer"]; |
239 |
|
240 |
if(version == GNUSTEP_NIB_VERSION) |
241 |
{ |
242 |
[aCoder decodeValueOfObjCType: @encode(id) at: &nameTable]; |
243 |
[aCoder decodeValueOfObjCType: @encode(id) at: &connections]; |
244 |
} |
245 |
|
246 |
return self; |
247 |
} |
248 |
|
249 |
- (NSMutableDictionary*) nameTable |
250 |
{ |
251 |
return nameTable; |
252 |
} |
253 |
@end |
254 |
|
255 |
// The first standin objects here are for views and normal objects like controllers |
256 |
// or data sources. |
257 |
@implementation GSNibItem |
258 |
+ (void) initialize |
259 |
{ |
260 |
if (self == [GSNibItem class]) |
261 |
{ |
262 |
[self setVersion: currentVersion]; |
263 |
} |
264 |
} |
265 |
|
266 |
- (void) dealloc |
267 |
{ |
268 |
RELEASE(theClass); |
269 |
[super dealloc]; |
270 |
} |
271 |
|
272 |
- (void) encodeWithCoder: (NSCoder*)aCoder |
273 |
{ |
274 |
[aCoder encodeObject: theClass]; |
275 |
[aCoder encodeRect: theFrame]; |
276 |
[aCoder encodeValueOfObjCType: @encode(unsigned int) |
277 |
at: &autoresizingMask]; |
278 |
} |
279 |
|
280 |
- (id) initWithCoder: (NSCoder*)aCoder |
281 |
{ |
282 |
int version = [aCoder versionForClassName: |
283 |
NSStringFromClass([self class])]; |
284 |
|
285 |
if (version == 1) |
286 |
{ |
287 |
id obj; |
288 |
Class cls; |
289 |
unsigned int mask; |
290 |
|
291 |
[aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; |
292 |
theFrame = [aCoder decodeRect]; |
293 |
[aCoder decodeValueOfObjCType: @encode(unsigned int) |
294 |
at: &mask]; |
295 |
|
296 |
cls = NSClassFromString(theClass); |
297 |
if (cls == nil) |
298 |
{ |
299 |
[NSException raise: NSInternalInconsistencyException |
300 |
format: @"Unable to find class '%@'", theClass]; |
301 |
} |
302 |
|
303 |
obj = [cls allocWithZone: [self zone]]; |
304 |
if (theFrame.size.height > 0 && theFrame.size.width > 0) |
305 |
obj = [obj initWithFrame: theFrame]; |
306 |
else |
307 |
obj = [obj init]; |
308 |
|
309 |
if ([obj respondsToSelector: @selector(setAutoresizingMask:)]) |
310 |
{ |
311 |
[obj setAutoresizingMask: mask]; |
312 |
} |
313 |
|
314 |
RELEASE(self); |
315 |
return obj; |
316 |
} |
317 |
else if (version == 0) |
318 |
{ |
319 |
id obj; |
320 |
Class cls; |
321 |
|
322 |
[aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; |
323 |
theFrame = [aCoder decodeRect]; |
324 |
|
325 |
cls = NSClassFromString(theClass); |
326 |
if (cls == nil) |
327 |
{ |
328 |
[NSException raise: NSInternalInconsistencyException |
329 |
format: @"Unable to find class '%@'", theClass]; |
330 |
} |
331 |
|
332 |
obj = [cls allocWithZone: [self zone]]; |
333 |
if (theFrame.size.height > 0 && theFrame.size.width > 0) |
334 |
obj = [obj initWithFrame: theFrame]; |
335 |
else |
336 |
obj = [obj init]; |
337 |
|
338 |
RELEASE(self); |
339 |
return obj; |
340 |
} |
341 |
else |
342 |
{ |
343 |
NSLog(@"no initWithCoder for this version"); |
344 |
RELEASE(self); |
345 |
return nil; |
346 |
} |
347 |
} |
348 |
|
349 |
@end |
350 |
|
351 |
@implementation GSCustomView |
352 |
+ (void) initialize |
353 |
{ |
354 |
if (self == [GSCustomView class]) |
355 |
{ |
356 |
[self setVersion: currentVersion]; |
357 |
} |
358 |
} |
359 |
|
360 |
- (void) encodeWithCoder: (NSCoder*)aCoder |
361 |
{ |
362 |
[super encodeWithCoder: aCoder]; |
363 |
} |
364 |
|
365 |
- (id) initWithCoder: (NSCoder*)aCoder |
366 |
{ |
367 |
return [super initWithCoder: aCoder]; |
368 |
} |
369 |
@end |
370 |
|
371 |
/* |
372 |
These stand-ins are here for use by GUI elements within Gorm. Since each gui element |
373 |
has it's own "designated initializer" it's important to provide a division between these |
374 |
so that when they are loaded, the application will call the correct initializer. |
375 |
|
376 |
Some "tricks" are employed in this code. For instance the use of initWithCoder and |
377 |
encodeWithCoder directly as opposed to using the encodeObjC.. methods is the obvious |
378 |
standout. To understand this it's necessary to explain a little about how encoding itself |
379 |
works. |
380 |
|
381 |
When the model is saved by the Interface Builder (whether Gorm or another |
382 |
IB equivalent) these classes should be used to substitute for the actual classes. The actual |
383 |
classes are encoded as part of it, but since they are being replaced we can't use the normal |
384 |
encode methods to do it and must encode it directly. |
385 |
|
386 |
Also, the reason for encoding the superclass itself is that by doing so the unarchiver knows |
387 |
what version is referred to by the encoded object. This way we can replace the object with |
388 |
a substitute class which will allow it to create itself as the custom class when read it by |
389 |
the application, and using the encoding system to do it in a clean way. |
390 |
*/ |
391 |
@implementation GSClassSwapper |
392 |
+ (void) initialize |
393 |
{ |
394 |
if (self == [GSClassSwapper class]) |
395 |
{ |
396 |
[self setVersion: GSSWAPPER_VERSION]; |
397 |
} |
398 |
} |
399 |
|
400 |
- (id) initWithObject: (id)object className: (NSString *)className superClassName: (NSString *)superClassName |
401 |
{ |
402 |
if((self = [self init]) != nil) |
403 |
{ |
404 |
NSDebugLog(@"Created template %@ -> %@",NSStringFromClass([self class]), className); |
405 |
ASSIGN(_object, object); |
406 |
ASSIGN(_className, [className copy]); |
407 |
NSAssert(![className isEqualToString: superClassName], NSInvalidArgumentException); |
408 |
_superClass = NSClassFromString(superClassName); |
409 |
if(_superClass == nil) |
410 |
{ |
411 |
[NSException raise: NSInternalInconsistencyException |
412 |
format: @"Unable to find class '%@'", superClassName]; |
413 |
} |
414 |
} |
415 |
return self; |
416 |
} |
417 |
|
418 |
- init |
419 |
{ |
420 |
if((self = [super init]) != nil) |
421 |
{ |
422 |
_className = nil; |
423 |
_superClass = nil; |
424 |
_object = nil; |
425 |
} |
426 |
return self; |
427 |
} |
428 |
|
429 |
- (void) setClassName: (NSString *)name |
430 |
{ |
431 |
ASSIGN(_className, [name copy]); |
432 |
} |
433 |
|
434 |
- (NSString *)className |
435 |
{ |
436 |
return _className; |
437 |
} |
438 |
|
439 |
- (id) initWithCoder: (NSCoder *)coder |
440 |
{ |
441 |
id obj = nil; |
442 |
int version = [coder versionForClassName: @"GSClassSwapper"]; |
443 |
if(version == 0) |
444 |
{ |
445 |
if((self = [super init]) != nil) |
446 |
{ |
447 |
// decode class/superclass... |
448 |
[coder decodeValueOfObjCType: @encode(id) at: &_className]; |
449 |
[coder decodeValueOfObjCType: @encode(Class) at: &_superClass]; |
450 |
|
451 |
// if we are living within the interface builder app, then don't try to |
452 |
// morph into the subclass. |
453 |
if([self respondsToSelector: @selector(isInInterfaceBuilder)]) |
454 |
{ |
455 |
obj = [[_superClass alloc] initWithCoder: coder]; // unarchive the object... |
456 |
} |
457 |
else |
458 |
{ |
459 |
Class aClass = NSClassFromString(_className); |
460 |
if(aClass == 0) |
461 |
{ |
462 |
[NSException raise: NSInternalInconsistencyException |
463 |
format: @"Unable to find class '%@'", _className]; |
464 |
} |
465 |
|
466 |
// Initialize the object... dont call decode, since this wont |
467 |
// allow us to instantiate the class we want. |
468 |
obj = [[aClass alloc] initWithCoder: coder]; // unarchive the object... |
469 |
} |
470 |
} |
471 |
} |
472 |
|
473 |
// Do this here since we are not using decode to do this. |
474 |
// Normally decode does a retain, so we must do it here. |
475 |
RETAIN(obj); |
476 |
|
477 |
// change the class of the instance to the one we want to see... |
478 |
return obj; |
479 |
} |
480 |
|
481 |
- (void) encodeWithCoder: (NSCoder *)aCoder |
482 |
{ |
483 |
[aCoder encodeValueOfObjCType: @encode(id) at: &_className]; |
484 |
[aCoder encodeValueOfObjCType: @encode(Class) at: &_superClass]; |
485 |
|
486 |
if(_object != nil) |
487 |
{ |
488 |
// Don't call encodeValue, the way templates are used will prevent |
489 |
// it from being saved correctly. Just call encodeWithCoder directly. |
490 |
[_object encodeWithCoder: aCoder]; |
491 |
} |
492 |
} |
493 |
@end |
494 |
|
495 |
@implementation GSWindowTemplate |
496 |
+ (void) initialize |
497 |
{ |
498 |
if (self == [GSWindowTemplate class]) |
499 |
{ |
500 |
[self setVersion: GSWINDOWT_VERSION]; |
501 |
} |
502 |
} |
503 |
|
504 |
- (BOOL)deferFlag |
505 |
{ |
506 |
return _deferFlag; |
507 |
} |
508 |
|
509 |
- (void)setDeferFlag: (BOOL)flag |
510 |
{ |
511 |
_deferFlag = flag; |
512 |
} |
513 |
|
514 |
// NSCoding... |
515 |
- (id) initWithCoder: (NSCoder *)coder |
516 |
{ |
517 |
id obj = [super initWithCoder: coder]; |
518 |
if(obj != nil) |
519 |
{ |
520 |
NSView *contentView = nil; |
521 |
|
522 |
// decode the defer flag... |
523 |
[coder decodeValueOfObjCType: @encode(BOOL) at: &_deferFlag]; |
524 |
|
525 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
526 |
{ |
527 |
if(GSGetInstanceMethodNotInherited([obj class], @selector(initWithContentRect:styleMask:backing:defer:)) != NULL) |
528 |
{ |
529 |
// if we are not in interface builder, call |
530 |
// designated initializer per spec... |
531 |
contentView = [obj contentView]; |
532 |
obj = [obj initWithContentRect: [obj frame] |
533 |
styleMask: [obj styleMask] |
534 |
backing: [obj backingType] |
535 |
defer: _deferFlag]; |
536 |
|
537 |
// set the content view back |
538 |
[obj setContentView: contentView]; |
539 |
} |
540 |
} |
541 |
RELEASE(self); |
542 |
} |
543 |
return obj; |
544 |
} |
545 |
|
546 |
- (void) encodeWithCoder: (NSCoder *)coder |
547 |
{ |
548 |
[super encodeWithCoder: coder]; |
549 |
[coder encodeValueOfObjCType: @encode(BOOL) at: &_deferFlag]; |
550 |
} |
551 |
@end |
552 |
|
553 |
@implementation GSViewTemplate |
554 |
+ (void) initialize |
555 |
{ |
556 |
if (self == [GSViewTemplate class]) |
557 |
{ |
558 |
[self setVersion: GSVIEWT_VERSION]; |
559 |
} |
560 |
} |
561 |
|
562 |
- (id) initWithCoder: (NSCoder *)coder |
563 |
{ |
564 |
id obj = [super initWithCoder: coder]; |
565 |
if(obj != nil) |
566 |
{ |
567 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
568 |
{ |
569 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(initWithFrame:)) != NULL) |
570 |
{ |
571 |
NSRect theFrame = [obj frame]; |
572 |
obj = [obj initWithFrame: theFrame]; |
573 |
} |
574 |
} |
575 |
RELEASE(self); |
576 |
} |
577 |
return obj; |
578 |
} |
579 |
@end |
580 |
|
581 |
// Template for any classes which derive from NSText |
582 |
@implementation GSTextTemplate |
583 |
+ (void) initialize |
584 |
{ |
585 |
if (self == [GSTextTemplate class]) |
586 |
{ |
587 |
[self setVersion: GSTEXTT_VERSION]; |
588 |
} |
589 |
} |
590 |
|
591 |
- (id) initWithCoder: (NSCoder *)coder |
592 |
{ |
593 |
id obj = [super initWithCoder: coder]; |
594 |
if(obj != nil) |
595 |
{ |
596 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
597 |
{ |
598 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(initWithFrame:)) != NULL) |
599 |
{ |
600 |
NSRect theFrame = [obj frame]; |
601 |
obj = [obj initWithFrame: theFrame]; |
602 |
} |
603 |
} |
604 |
RELEASE(self); |
605 |
} |
606 |
return obj; |
607 |
} |
608 |
@end |
609 |
|
610 |
// Template for any classes which derive from GSTextView |
611 |
@implementation GSTextViewTemplate |
612 |
+ (void) initialize |
613 |
{ |
614 |
if (self == [GSTextViewTemplate class]) |
615 |
{ |
616 |
[self setVersion: GSTEXTVIEWT_VERSION]; |
617 |
} |
618 |
} |
619 |
|
620 |
- (id) initWithCoder: (NSCoder *)coder |
621 |
{ |
622 |
id obj = [super initWithCoder: coder]; |
623 |
if(obj != nil) |
624 |
{ |
625 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
626 |
{ |
627 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(initWithFrame:textContainer:)) != NULL) |
628 |
{ |
629 |
NSRect theFrame = [obj frame]; |
630 |
id textContainer = [obj textContainer]; |
631 |
obj = [obj initWithFrame: theFrame |
632 |
textContainer: textContainer]; |
633 |
} |
634 |
} |
635 |
RELEASE(self); |
636 |
} |
637 |
return obj; |
638 |
} |
639 |
@end |
640 |
|
641 |
// Template for any classes which derive from NSMenu. |
642 |
@implementation GSMenuTemplate |
643 |
+ (void) initialize |
644 |
{ |
645 |
if (self == [GSMenuTemplate class]) |
646 |
{ |
647 |
[self setVersion: GSMENUT_VERSION]; |
648 |
} |
649 |
} |
650 |
|
651 |
- (id) initWithCoder: (NSCoder *)coder |
652 |
{ |
653 |
id obj = [super initWithCoder: coder]; |
654 |
if(obj != nil) |
655 |
{ |
656 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
657 |
{ |
658 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(initWithTitle:)) != NULL) |
659 |
{ |
660 |
NSString *theTitle = [obj title]; |
661 |
obj = [obj initWithTitle: theTitle]; |
662 |
} |
663 |
} |
664 |
RELEASE(self); |
665 |
} |
666 |
return obj; |
667 |
} |
668 |
@end |
669 |
|
670 |
|
671 |
// Template for any classes which derive from NSControl |
672 |
@implementation GSControlTemplate |
673 |
+ (void) initialize |
674 |
{ |
675 |
if (self == [GSControlTemplate class]) |
676 |
{ |
677 |
[self setVersion: GSCONTROLT_VERSION]; |
678 |
} |
679 |
} |
680 |
|
681 |
- (id) initWithCoder: (NSCoder *)coder |
682 |
{ |
683 |
id obj = [super initWithCoder: coder]; |
684 |
if(obj != nil) |
685 |
{ |
686 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
687 |
{ |
688 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(initWithFrame:)) != NULL) |
689 |
{ |
690 |
NSRect theFrame = [obj frame]; |
691 |
obj = [obj initWithFrame: theFrame]; |
692 |
} |
693 |
} |
694 |
RELEASE(self); |
695 |
} |
696 |
return obj; |
697 |
} |
698 |
@end |
699 |
|
700 |
@implementation GSObjectTemplate |
701 |
+ (void) initialize |
702 |
{ |
703 |
if (self == [GSObjectTemplate class]) |
704 |
{ |
705 |
[self setVersion: GSOBJECTT_VERSION]; |
706 |
} |
707 |
} |
708 |
|
709 |
- (id) initWithCoder: (NSCoder *)coder |
710 |
{ |
711 |
id obj = [super initWithCoder: coder]; |
712 |
if(obj != nil) |
713 |
{ |
714 |
if(![self respondsToSelector: @selector(isInInterfaceBuilder)]) |
715 |
{ |
716 |
if(GSGetInstanceMethodNotInherited([obj class],@selector(init)) != NULL) |
717 |
{ |
718 |
obj = [self init]; |
719 |
} |
720 |
} |
721 |
RELEASE(self); |
722 |
} |
723 |
return obj; |
724 |
} |
725 |
@end |
726 |
|
727 |
@interface NSObject (NibInstantiation) |
728 |
- (id) nibInstantiate; |
729 |
@end |
730 |
|
731 |
@implementation NSObject (NibInstantiation) |
732 |
- (id) nibInstantiate |
733 |
{ |
734 |
// default implementation of nibInstantiate |
735 |
return self; |
736 |
} |
737 |
@end |
738 |
|
739 |
// Order in this factory method is very important. Which template to create must be determined |
740 |
// in sequence because of the class hierarchy. |
741 |
@implementation GSTemplateFactory |
742 |
+ (id) templateForObject: (id) object |
743 |
withClassName: (NSString *)className |
744 |
withSuperClassName: (NSString *)superClassName |
745 |
{ |
746 |
id template = nil; |
747 |
if(object != nil) |
748 |
{ |
749 |
// NSData *objectData = nil; |
750 |
// [archiver encodeRootObject: object]; |
751 |
// objectData = [archiver archiverData]; |
752 |
if ([object isKindOfClass: [NSWindow class]]) |
753 |
{ |
754 |
template = [[GSWindowTemplate alloc] initWithObject: object |
755 |
className: className |
756 |
superClassName: superClassName]; |
757 |
} |
758 |
else if ([object isKindOfClass: [NSTextView class]]) |
759 |
{ |
760 |
template = [[GSTextViewTemplate alloc] initWithObject: object |
761 |
className: className |
762 |
superClassName: superClassName]; |
763 |
} |
764 |
else if ([object isKindOfClass: [NSText class]]) |
765 |
{ |
766 |
template = [[GSTextTemplate alloc] initWithObject: object |
767 |
className: className |
768 |
superClassName: superClassName]; |
769 |
} |
770 |
else if ([object isKindOfClass: [NSControl class]]) |
771 |
{ |
772 |
template = [[GSControlTemplate alloc] initWithObject: object |
773 |
className: className |
774 |
superClassName: superClassName]; |
775 |
} |
776 |
else if ([object isKindOfClass: [NSView class]]) |
777 |
{ |
778 |
template = [[GSViewTemplate alloc] initWithObject: object |
779 |
className: className |
780 |
superClassName: superClassName]; |
781 |
} |
782 |
else if ([object isKindOfClass: [NSMenu class]]) |
783 |
{ |
784 |
template = [[GSMenuTemplate alloc] initWithObject: object |
785 |
className: className |
786 |
superClassName: superClassName]; |
787 |
} |
788 |
else if ([object isKindOfClass: [NSObject class]]) // for gui elements derived from NSObject |
789 |
{ |
790 |
template = [[GSObjectTemplate alloc] initWithObject: object |
791 |
className: className |
792 |
superClassName: superClassName]; |
793 |
} |
794 |
} |
795 |
return template; |
796 |
} |
797 |
@end |
798 |
|
799 |
////////////////////////////////////////////////////////////////////////////////////////// |
800 |
////////////////// DEPRECATED TEMPLATES ----- THESE SHOULD NOT BE USED ////////////////// |
801 |
////////////////////////////////////////////////////////////////////////////////////////// |
802 |
|
803 |
/* |
804 |
These templates are from the old system, which had some issues. Currently I believe |
805 |
that NSWindowTemplate was the only one seeing use, so it is the only one included. |
806 |
if any more are needed they will be added back. |
807 |
|
808 |
As these classes are deprecated, they should disappear from the gnustep distribution |
809 |
in the next major release. |
810 |
*/ |
811 |
|
812 |
@implementation NSWindowTemplate |
813 |
+ (void) initialize |
814 |
{ |
815 |
if (self == [NSWindowTemplate class]) |
816 |
{ |
817 |
[self setVersion: 0]; |
818 |
} |
819 |
} |
820 |
|
821 |
- (void) dealloc |
822 |
{ |
823 |
RELEASE(_parentClassName); |
824 |
RELEASE(_className); |
825 |
[super dealloc]; |
826 |
} |
827 |
|
828 |
- init |
829 |
{ |
830 |
[super init]; |
831 |
|
832 |
// Start initially with the highest level class... |
833 |
ASSIGN(_className, NSStringFromClass([super class])); |
834 |
ASSIGN(_parentClassName, NSStringFromClass([super class])); |
835 |
|
836 |
// defer flag... |
837 |
_deferFlag = NO; |
838 |
|
839 |
return self; |
840 |
} |
841 |
|
842 |
- (id) initWithCoder: (NSCoder *)aCoder |
843 |
{ |
844 |
[aCoder decodeValueOfObjCType: @encode(id) at: &_className]; |
845 |
[aCoder decodeValueOfObjCType: @encode(id) at: &_parentClassName]; |
846 |
[aCoder decodeValueOfObjCType: @encode(BOOL) at: &_deferFlag]; |
847 |
return [super initWithCoder: aCoder]; |
848 |
} |
849 |
|
850 |
- (void) encodeWithCoder: (NSCoder *)aCoder |
851 |
{ |
852 |
[aCoder encodeValueOfObjCType: @encode(id) at: &_className]; |
853 |
[aCoder encodeValueOfObjCType: @encode(id) at: &_parentClassName]; |
854 |
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_deferFlag]; |
855 |
[super encodeWithCoder: aCoder]; |
856 |
} |
857 |
|
858 |
- (id) awakeAfterUsingCoder: (NSCoder *)coder |
859 |
{ |
860 |
if([self respondsToSelector: @selector(isInInterfaceBuilder)]) |
861 |
{ |
862 |
// if we live in the interface builder, give them an instance of |
863 |
// the parent, not the child.. |
864 |
[self setClassName: _parentClassName]; |
865 |
} |
866 |
|
867 |
return [self instantiateObject: coder]; |
868 |
} |
869 |
|
870 |
- (id) instantiateObject: (NSCoder *)coder |
871 |
{ |
872 |
id obj = nil; |
873 |
Class aClass = NSClassFromString(_className); |
874 |
|
875 |
if (aClass == nil) |
876 |
{ |
877 |
[NSException raise: NSInternalInconsistencyException |
878 |
format: @"Unable to find class '%@'", _className]; |
879 |
} |
880 |
|
881 |
obj = [[aClass allocWithZone: [self zone]] |
882 |
initWithContentRect: [self frame] |
883 |
styleMask: [self styleMask] |
884 |
backing: [self backingType] |
885 |
defer: _deferFlag]; |
886 |
|
887 |
// fill in actual object from template... |
888 |
[obj setBackgroundColor: [self backgroundColor]]; |
889 |
[(NSWindow*)obj setContentView: [self contentView]]; |
890 |
[obj setFrameAutosaveName: [self frameAutosaveName]]; |
891 |
[obj setHidesOnDeactivate: [self hidesOnDeactivate]]; |
892 |
[obj setInitialFirstResponder: [self initialFirstResponder]]; |
893 |
[obj setAutodisplay: [self isAutodisplay]]; |
894 |
[obj setReleasedWhenClosed: [self isReleasedWhenClosed]]; |
895 |
[obj _setVisible: [self isVisible]]; |
896 |
[obj setTitle: [self title]]; |
897 |
[obj setFrame: [self frame] display: NO]; |
898 |
|
899 |
RELEASE(self); |
900 |
return obj; |
901 |
} |
902 |
|
903 |
// setters and getters... |
904 |
- (void) setClassName: (NSString *)name |
905 |
{ |
906 |
ASSIGN(_className, name); |
907 |
} |
908 |
|
909 |
- (NSString *)className |
910 |
{ |
911 |
return _className; |
912 |
} |
913 |
|
914 |
- (BOOL)deferFlag |
915 |
{ |
916 |
return _deferFlag; |
917 |
} |
918 |
|
919 |
- (void)setDeferFlag: (BOOL)flag |
920 |
{ |
921 |
_deferFlag = flag; |
922 |
} |
923 |
@end |