1/** <title>GormCustomClassInspector</title>
2
3   <abstract>allow user to select custom classes</abstract>
4
5   Copyright (C) 2002 Free Software Foundation, Inc.
6   Author:  Gregory John Casamento <greg_casamento@yahoo.com>
7   Date: September 2002
8
9   This file is part of GNUstep.
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Library General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Library General Public License for more details.
20
21   You should have received a copy of the GNU Library General Public
22   License along with this library; see the file COPYING.LIB.
23   If not, write to the Free Software Foundation,
24   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25*/
26
27/* All Rights reserved */
28
29#include <AppKit/AppKit.h>
30#include "GormCustomClassInspector.h"
31#include "GormPrivate.h"
32#include "GormClassManager.h"
33#include "GormDocument.h"
34#include "GormPrivate.h"
35#include "GormViewEditor.h"
36
37@implementation GormCustomClassInspector
38+ (void) initialize
39{
40  if (self == [GormCustomClassInspector class])
41    {
42      // TBD
43    }
44}
45
46- (id) init
47{
48  self = [super init];
49  if (self != nil)
50    {
51      // initialize all member variables...
52      _classManager = nil;
53      _currentSelectionClassName = nil;
54      _rowToSelect = 0;
55
56      // load the gui...
57      if (![NSBundle loadNibNamed: @"GormCustomClassInspector"
58			    owner: self])
59	{
60	  NSLog(@"Could not open gorm GormCustomClassInspector");
61	  return nil;
62	}
63    }
64  return self;
65}
66
67- (void) _setCurrentSelectionClassName: (id)anobject
68{
69  NSString	 *className;
70
71  className = [_classManager customClassForObject: anobject];
72  if ([className isEqualToString: @""]
73    || className == nil)
74    {
75      className = [anobject className];
76    }
77
78  ASSIGN(_currentSelectionClassName, className);
79  ASSIGN(_parentClassName, [anobject className]);
80}
81
82- (NSMutableArray *) _generateClassList
83{
84  NSMutableArray *classes = [NSMutableArray arrayWithObject: _parentClassName];
85  NSArray *subclasses = [_classManager allSubclassesOf: _parentClassName];
86  NSEnumerator *en = [subclasses objectEnumerator];
87  NSString *className = nil;
88  Class parentClass = NSClassFromString(_parentClassName);
89
90  while((className = [en nextObject]) != nil)
91    {
92      if([_classManager isCustomClass: className] == YES)
93	{
94	  NSString *superClass = [_classManager nonCustomSuperClassOf: className];
95	  Class cls = NSClassFromString(superClass);
96	  if(cls != nil)
97	    {
98	      if([cls respondsToSelector: @selector(canSubstituteForClass:)])
99		{
100		  if([cls canSubstituteForClass: parentClass])
101		    {
102		      [classes addObject: className];
103		    }
104		}
105	    }
106	}
107      else if(parentClass != nil)
108	{
109	  Class cls = NSClassFromString(className);
110	  if(cls != nil)
111	    {
112	      if([cls respondsToSelector: @selector(canSubstituteForClass:)])
113		{
114		  if([cls canSubstituteForClass: parentClass])
115		    {
116		      [classes addObject: className];
117		    }
118		}
119	    }
120	}
121    }
122
123  return classes;
124}
125
126- (void) setObject: (id)anObject
127{
128  if(anObject != nil)
129    {
130      NSMutableArray *classes = nil;
131
132      [super setObject: anObject];
133      _document = [(id<IB>)NSApp activeDocument];
134      _classManager = [(id<Gorm>)NSApp classManager];
135
136      // get the information...
137      NSDebugLog(@"Current selection %@", [self object]);
138      [self _setCurrentSelectionClassName: [self object]];
139
140      // load the array...
141      [browser loadColumnZero];
142
143      // get a list of all of the classes allowed and the class to be shown
144      // and select the appropriate row in the inspector...
145      classes = [self _generateClassList];
146      // [NSMutableArray arrayWithObject: _parentClassName];
147      // [classes addObjectsFromArray: [_classManager allCustomSubclassesOf: _parentClassName]];
148
149      _rowToSelect = [classes indexOfObject: _currentSelectionClassName];
150      _rowToSelect = (_rowToSelect != NSNotFound)?_rowToSelect:0;
151
152      if(_rowToSelect != NSNotFound)
153	{
154	  [browser selectRow: _rowToSelect inColumn: 0];
155	}
156    }
157}
158
159- (void) awakeFromNib
160{
161  [browser setTarget: self];
162  [browser setAction: @selector(select:)];
163  [browser setMaxVisibleColumns: 1];
164}
165
166- (void) _replaceWithCellClassForClassName: (NSString *)name
167{
168  NSString *className = name;
169  if([[object class] respondsToSelector: @selector(cellClass)])
170    {
171      if([_classManager customClassForObject: object])
172	{
173	  if([_classManager isCustomClass: className])
174	    {
175	      className = [_classManager nonCustomSuperClassOf: name];
176	    }
177	}
178
179      if(className != nil)
180	{
181	  Class cls = NSClassFromString(className);
182	  if(cls != nil)
183	    {
184	      Class cellClass = [cls cellClass];
185
186	      if(cellClass != [[object cell] class])
187		{
188		  id newCell = [[cellClass alloc] init];
189		  id cell = RETAIN([object cell]); // retain the old cell for now...
190		  BOOL   drawsBackground = NO;
191
192		  if([object respondsToSelector: @selector(drawsBackground)])
193		    {
194		      drawsBackground = [object drawsBackground];
195		    }
196
197		  // TODO: Need to find a more generic way to handle this.  Perhaps using
198		  // encoding, kv-copying or @defs(...).
199		  // set the new cell..
200		  [object setCell: newCell];
201
202		  // general state...
203		  if([newCell respondsToSelector: @selector(setFont:)] &&
204		     [cell respondsToSelector: @selector(font)])
205		    {
206		      [newCell setFont: [cell font]];
207		    }
208		  if([newCell respondsToSelector: @selector(setEnabled:)] &&
209		     [cell respondsToSelector: @selector(isEnabled)])
210		    {
211		      [newCell setEnabled: [cell isEnabled]];
212		    }
213		  if([newCell respondsToSelector: @selector(setEditable:)] &&
214		     [cell respondsToSelector: @selector(isEditable)])
215		    {
216		      [newCell setEditable: [cell isEditable]];
217		    }
218		  if([newCell respondsToSelector: @selector(setImportsGraphics:)] &&
219		     [cell respondsToSelector: @selector(importsGraphics)])
220		    {
221		      [newCell setImportsGraphics: [cell importsGraphics]];
222		    }
223		  if([newCell respondsToSelector: @selector(setShowsFirstResponder:)] &&
224		     [cell respondsToSelector: @selector(showsFirstResponder)])
225		    {
226		      [newCell setShowsFirstResponder: [cell showsFirstResponder]];
227		    }
228		  if([newCell respondsToSelector: @selector(setRefusesFirstResponder:)] &&
229		     [cell respondsToSelector: @selector(refusesFirstResponder)])
230		    {
231		      [newCell setRefusesFirstResponder: [cell refusesFirstResponder]];
232		    }
233		  if([newCell respondsToSelector: @selector(setBordered:)] &&
234		     [cell respondsToSelector: @selector(isBordered)])
235		    {
236		      [newCell setBordered: [cell isBordered]];
237		    }
238		  if([newCell respondsToSelector: @selector(setBezeled:)] &&
239		     [cell respondsToSelector: @selector(isBezeled)])
240		    {
241		      [newCell setBezeled: [cell isBezeled]];
242		    }
243		  if([newCell respondsToSelector: @selector(setScrollable:)] &&
244		     [cell respondsToSelector: @selector(isScrollable)])
245		    {
246		      [newCell setScrollable: [cell isScrollable]];
247		    }
248		  if([newCell respondsToSelector: @selector(setSelectable:)] &&
249		     [cell respondsToSelector: @selector(isSelectable)])
250		    {
251		      [newCell setSelectable: [cell isSelectable]];
252		    }
253		  if([newCell respondsToSelector: @selector(setState:)] &&
254		     [cell respondsToSelector: @selector(state)])
255		    {
256		      [newCell setState: [cell state]];
257		    }
258
259		  if([(NSCell *)cell type] == NSTextCellType)
260		    {
261		      // title...
262		      if([newCell respondsToSelector: @selector(setStringValue:)] &&
263			 [cell respondsToSelector: @selector(stringValue)])
264			{
265			  [newCell setStringValue: [cell stringValue]];
266			}
267		      if([newCell respondsToSelector: @selector(setTitle:)] &&
268			 [cell respondsToSelector: @selector(title)])
269			{
270			  [newCell setTitle: [cell title]];
271			}
272		      if([newCell respondsToSelector: @selector(setAlternateTitle:)] &&
273			 [cell respondsToSelector: @selector(alternateTitle)])
274			{
275			  [newCell setAlternateTitle: [cell alternateTitle]];
276			}
277		    }
278		  else if([(NSCell *)cell type] == NSImageCellType)
279		    {
280		      // images...
281		      if([newCell respondsToSelector: @selector(setAlternateImage:)] &&
282			 [cell respondsToSelector: @selector(alternateImage)])
283			{
284			  [newCell setAlternateImage: [cell alternateImage]];
285			}
286		      if([newCell respondsToSelector: @selector(setImage:)] &&
287			 [cell respondsToSelector: @selector(image)])
288			{
289			  [newCell setImage: [cell image]];
290			}
291		      if([newCell respondsToSelector: @selector(setImagePosition:)] &&
292			 [cell respondsToSelector: @selector(imagePosition)])
293			{
294			  [newCell setImagePosition: [cell imagePosition]];
295			}
296		    }
297		  // set attributes of textfield.
298		  if([object respondsToSelector: @selector(setDrawsBackground:)])
299		    {
300		      [object setDrawsBackground: drawsBackground];
301		    }
302		  [object setNeedsDisplay: YES];
303		  RELEASE(cell);
304		}
305	    }
306	}
307    }
308}
309
310- (void) select: (id)sender
311{
312  NSCell *cell = [browser selectedCellInColumn: 0];
313  NSString *stringValue = [NSString stringWithString: [cell stringValue]];
314  NSString *nameForObject = [_document nameForObject: [self object]];
315  NSString *classForObject = [[self object] className];
316  GormViewEditor *gve = (GormViewEditor *)[_document editorForObject: [self object]
317						     create: NO];
318
319  NSDebugLog(@"selected = %@, class = %@",stringValue,nameForObject);
320
321  /* add or remove the mapping as necessary. */
322  if(nameForObject != nil)
323    {
324      [super ok: sender];
325      if (![stringValue isEqualToString: classForObject])
326	{
327	  [_classManager setCustomClass: stringValue
328			 forName: nameForObject];
329	}
330      else
331	{
332	  [_classManager removeCustomClassForName: nameForObject];
333	}
334
335      [gve setToolTip: [NSString stringWithFormat: @"%@,%@",
336				 nameForObject,
337				 stringValue]];
338
339      [self _replaceWithCellClassForClassName: stringValue];
340    }
341  else
342    NSLog(@"name for object %@ returned as nil",[self object]);
343}
344
345// Browser delegate
346- (void)    browser: (NSBrowser *)sender
347createRowsForColumn: (NSInteger)column
348	   inMatrix: (NSMatrix *)matrix
349{
350  if (_parentClassName != nil)
351    {
352      NSMutableArray	*classes;
353      NSEnumerator	*e = nil;
354      NSString		*class = nil;
355      NSBrowserCell	*cell = nil;
356      NSInteger		i = 0;
357
358      classes = [self _generateClassList];
359      // [NSMutableArray arrayWithObject: _parentClassName];
360      // get a list of all of the classes allowed and the class to be shown.
361      //[classes addObjectsFromArray:
362      // [_classManager allCustomSubclassesOf: _parentClassName]];
363
364      // enumerate through the classes...
365      e = [classes objectEnumerator];
366      while ((class = [e nextObject]) != nil)
367	{
368	  if ([class isEqualToString: _currentSelectionClassName])
369	    {
370	      _rowToSelect = i;
371	    }
372	  [matrix insertRow: i withCells: nil];
373	  cell = [matrix cellAtRow: i column: 0];
374	  [cell setLeaf: YES];
375	  i++;
376	  [cell setStringValue: class];
377	}
378    }
379}
380
381- (NSString*) browser: (NSBrowser*)sender
382	titleOfColumn: (NSInteger)column
383{
384  NSDebugLog(@"Delegate called");
385  return @"Class";
386}
387
388- (void) browser: (NSBrowser *)sender
389 willDisplayCell: (id)cell
390	   atRow: (NSInteger)row
391	  column: (NSInteger)column
392{
393}
394
395- (BOOL) browser: (NSBrowser *)sender
396   isColumnValid: (NSInteger)column
397{
398  return YES;
399}
400@end
401