discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Cocoa compatible keyed decoding


From: Fred Kiefer
Subject: Cocoa compatible keyed decoding
Date: Fri, 30 Jan 2004 21:03:47 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821

I just added some basic code to a few GUI classes, that allows to load these from Cocoa XML NIB files. The aim behind this is to be able to read in NIB files created by Apples InterfaceBuilder and use them in GNUstep. Richard did the great work on the underlying code to read the XML NIB format. Many thanks to him! What I did was just inspect a few NIB files to find out what values show up for which classes and try to bring them into some working code.

The implementation of keyed decoding is done in the initWithCoder: method of each class, where a check, if the decoder supports keyed encoding, has been added. As the information on the keys and values for each class was taken from an empirical sample (acually a quite small one) some keys will be missing. Also many classes are missing and what is even worse, all the bit flag information still needs to be decoded. Here only people with a Cocoa system can help: If you are interested in keyed decoding for GNUstep, you may contribute by creating NIB archives and comparing the values you find there with the settings you made for the view/cell in the InterfaceBuilder. This is a simple, but rather boring task. I would volunteer to coordinate this, but cannot contribute as I don't run an Apple computer.

There are a few implementation details for the new decoding code, that should be noted. First, I try to use the designated initialiser for the view classes (initWithFrame:), instead of setting all values inside of the decoding method. I think, this is needed as only values, that are different from the defaults seem to be encoded in the NIB files. Second, I rather call methods to set the read in values, instead of accessing the ivars directly. This seems a lot cleaner to me and the added time should not cost too much. I would expect a few problems coming from this, though, as GNUstep has not been used in this way before.

For those of you, wanting to test the code, I have attached my simple NIB loading application. This still doesn't, of course, do anything usefull. Actual NIB loading, as Gregory pointed out before, requires a lot more than just to be able to dearchive the objects. But we may get there at some point.
/* 
   Tester for XML Nib loading
   Copyright (C) 2004 Free Software Foundation, Inc.

   Written by: Fred Kiefer <FredKiefer@gmx.de>
   Created: January 2004

   This file is part of the GNUstep Base Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include <Foundation/Foundation.h>
#include <Foundation/NSKeyedArchiver.h>
#include <AppKit/AppKit.h>
#include <GNUstepGUI/GSNibCompatibility.h>



@implementation NSLayoutManager (NSKeyedCoding)

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      int i;
      id delegate = [aDecoder decodeObjectForKey: @"NSDelegate"];
      int flags;
      NSArray *array = [aDecoder decodeObjectForKey: @"NSTextContainers"];
      NSTextStorage *storage = [aDecoder decodeObjectForKey: @"NSTextStorage"];
      
      self = [self init];
      if ([aDecoder containsValueForKey: @"NSLMFlags"])
        {
          flags = [aDecoder decodeIntForKey: @"NSLMFlags"];
          // FIXME
        }
      [self setDelegate: delegate];
      [storage addLayoutManager: self];
      for (i = 0; i < [array count]; i++)
        { 
          [self addTextContainer: [array objectAtIndex: i]];
        }

      return self;
    }
  else
    {
      return self;
    }
}
@end


@implementation NSTextContainer (NSKeyedCoding)

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      //NSLayoutManager *manager = [aDecoder decodeObjectForKey: 
@"NSLayoutManager"];
      NSTextView *view = [aDecoder decodeObjectForKey: @"NSTextView"];
      NSSize size = NSZeroSize;
  
      if ([aDecoder containsValueForKey: @"NSWidth"])
        {
          size.width = [aDecoder decodeFloatForKey: @"NSWidth"];
        }
      self = [self initWithContainerSize: size];
      if ([aDecoder containsValueForKey: @"NSTCFlags"])
        {
          int flags = [aDecoder decodeIntForKey: @"NSTCFlags"];
          // FIXME
        }
      // No need to set manager as the decoding of the layout manager does it
      [self setTextView: view];
      return self;
    }
  else
    {
      return self;
    }
}
@end

@implementation NSTextStorage (NSKeyedCoding)

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      id delegate = [aDecoder decodeObjectForKey: @"NSDelegate"];
      NSString *string = [aDecoder decodeObjectForKey: @"NSString"];
      
      self = [self initWithString: string];
      [self setDelegate: delegate];
      return self;
    }
  else
    {
      return self;
    }      
}

@end

@interface NSTextViewSharedData : NSObject 
{
@public
  NSColor *backgroundColor;
  NSParagraphStyle *paragraphStyle;
  int flags;
  NSColor *insertionColor;
  NSArray *linkAttr;
  NSArray *markAttr;
  NSArray *selectedAttr;
}
@end

@implementation NSTextViewSharedData

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      backgroundColor = [aDecoder decodeObjectForKey: @"NSBackgroundColor"];
      paragraphStyle = [aDecoder decodeObjectForKey: 
@"NSDefaultParagraphStyle"];
      // FIXME
      flags = [aDecoder decodeIntForKey: @"NSFlags"];
      insertionColor = [aDecoder decodeObjectForKey: @"NSInsertionColor"];
      linkAttr = [aDecoder decodeObjectForKey: @"NSLinkAttributes"];
      markAttr = [aDecoder decodeObjectForKey: @"NSMarkedAttributes"];
      selectedAttr = [aDecoder decodeObjectForKey: @"NSSelectedAttributes"];
      
      return self;
    }
  else
    {
      return self;
    }
}
@end

@implementation NSTextView (NSKeyedCoding)

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      id delegate = [aDecoder decodeObjectForKey: @"NSDelegate"];
      NSSize frameSize = [aDecoder decodeSizeForKey: @"NSFrameSize"];
      NSSize maxSize = [aDecoder decodeSizeForKey: @"NSMaxSize"];
      NSSize minSize = [aDecoder decodeSizeForKey: @"NSMinize"];
      NSTextViewSharedData *shared = [aDecoder decodeObjectForKey: 
@"NSSharedData"];
      int tvFlags = [aDecoder decodeIntForKey: @"NSTVFlags"];
      NSTextContainer *container = [aDecoder decodeObjectForKey: 
@"NSTextContainer"];
      //NSTextStorage *storage = [aDecoder decodeObjectForKey: 
@"NSTextStorage"];
      
      self = [super initWithCoder: aDecoder];
      [self setDelegate: delegate];
      // FIXME set the flags, shared data, storage
      [self setMaxSize: maxSize];
      [self setMinSize: minSize];
      [self setTextContainer: container];

      return self;
    }
  else
    {
      return self;
    }
}
@end





@interface NSCustomObject : NSObject 
{
}
@end

@implementation NSCustomObject

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      NSString *classname = [aDecoder decodeObjectForKey: @"NSClassName"];
      Class c = NSClassFromString(classname);
      
      // FIXME
      RELEASE(self);
      return [c alloc];
    }
  else
    {
      return self;
    }
}
@end


@implementation NSWindowTemplate (NSKeyedCoding)

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      NSRect screenRect = [aDecoder decodeRectForKey: @"NSScreenRect"];
      NSRect windowRect = [aDecoder decodeRectForKey: @"NSWindowRect"];
      NSString *viewClass = [aDecoder decodeObjectForKey: @"NSViewClass"];
      NSString *windowClass = [aDecoder decodeObjectForKey: @"NSWindowClass"];
      NSString *title = [aDecoder decodeObjectForKey: @"NSWindowTitle"];
      NSView *view = [aDecoder decodeObjectForKey: @"NSWindowView"];
      int flags = [aDecoder decodeIntForKey: @"NSWTFlags"];
      int style = [aDecoder decodeIntForKey: @"NSWindowStyleMask"];
      int backing = [aDecoder decodeIntForKey: @"NSWindowBacking"];
      
      ASSIGN(_className, windowClass);
      _backingType = backing;
      _styleMask = style;
      _frame = windowRect;

      if ([aDecoder containsValueForKey: @"NSMinSize"])
        {
          NSSize minSize = [aDecoder decodeSizeForKey: @"NSMinSize"];
          [self setMinSize: minSize];
        }
      if ([aDecoder containsValueForKey: @"NSMaxSize"])
        {
          NSSize maxSize = [aDecoder decodeSizeForKey: @"NSMaxSize"];
          [self setMaxSize: maxSize];
        }
      [self setTitle: title];

      return self;
    }
  else
    {
      return self;
    }
}
@end

@interface NSIBObjectData : NSObject 
{
  id root;
  NSMutableArray *windows;
}
@end

@implementation NSIBObjectData

- (id) initWithCoder: (NSCoder*)aDecoder
{
  if ([aDecoder allowsKeyedCoding])
    {
      NSArray *classesKeys = [aDecoder decodeObjectForKey: @"NSClassesKeys"];
      NSArray *classesValues = [aDecoder decodeObjectForKey: 
@"NSClassesValues"];
      NSMutableArray *connections = [aDecoder decodeObjectForKey: 
@"NSConnections"];
      NSFontManager *manager = [aDecoder decodeObjectForKey: @"NSFontManager"];
      NSString *framework = [aDecoder decodeObjectForKey: @"NSFramework"];
      NSArray *namesKeys = [aDecoder decodeObjectForKey: @"NSNamesKeys"];
      NSArray *namesValues = [aDecoder decodeObjectForKey: @"NSNamesValues"];
      int next = [aDecoder decodeIntForKey: @"NSNextOid"];
      NSArray *objectKeys = [aDecoder decodeObjectForKey: @"NSObjectsKeys"];
      NSArray *objectValues = [aDecoder decodeObjectForKey: @"NSObjectsValues"];
      NSArray *oidKeys = [aDecoder decodeObjectForKey: @"NSOidsKeys"];
      NSArray *oidValues = [aDecoder decodeObjectForKey: @"NSOidsValues"];
      
      root = [aDecoder decodeObjectForKey: @"NSRoot"];
      windows = [aDecoder decodeObjectForKey: @"NSVisibleWindows"];
     
      NSLog(@"Class  keys %@, values %@ .", classesKeys, classesValues);
      NSLog(@"Names  keys %@, values %@ .", namesKeys, namesValues);
      NSLog(@"Objects  keys %@, values %@ .", objectKeys, objectValues);
      NSLog(@"OIDs  keys %@, values %@ .", oidKeys, oidValues);

      NSLog(@"Windows %@, root %@ .", windows, root);
      NSLog(@"Connections %@, framework %@ .", connections, framework);
 
      return self;
    }
  else
    {
      return self;
    }
}

- (NSArray*) windows
{
  return windows;
}

- (id) root
{
  return root;
}
@end
/* 
   Tester for XML Nib loading
   Copyright (C) 2004 Free Software Foundation, Inc.

   Written by: Fred Kiefer <FredKiefer@gmx.de>
   Created: January 2004

   This file is part of the GNUstep Base Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSData.h>
#include <Foundation/NSKeyedArchiver.h>
#include <Foundation/NSString.h>
#include <AppKit/NSApplication.h>

@interface Delegate: NSObject
{
}
@end

@implementation Delegate
- (Class) unarchiver: (NSKeyedUnarchiver*)anUnarchiver
  cannotDecodeObjectOfClassName: (NSString*)aName
  originalClasses: (NSArray*)classNames
{
  NSLog(@"Cannot decode %@", aName);
  return Nil;
}

- (id) unarchiver: (NSKeyedUnarchiver*)anUnarchiver
  didDecodeObject: (id)anObject
{
  NSLog(@"decoded %@", anObject);
  return anObject;
}
- (void) unarchiverDidFinish: (NSKeyedUnarchiver*)anUnarchiver
{}
- (void) unarchiverWillFinish: (NSKeyedUnarchiver*)anUnarchiver
{}

- (void) unarchiver: (NSKeyedUnarchiver*)anUnarchiver
  willReplaceObject: (id)anObject
         withObject: (id)newObject
{}

@end

int main (int argc, const char *argv[])
{
  CREATE_AUTORELEASE_POOL(pool);
  NSString *file;
  id root;
  NSKeyedUnarchiver *u;
  Delegate *delegate = [[Delegate alloc] init];

  if (argc < 2)
    {
      NSLog(@"No file given");
      return;
    }

  file = [NSString stringWithCString: argv[1]];

  [NSApplication sharedApplication];
  u = [[NSKeyedUnarchiver alloc] initForReadingWithData: 
                                     [NSData dataWithContentsOfFile: file]];
  [u setDelegate: delegate];
  root = [u decodeObjectForKey: @"IB.objectdata"];
  NSLog(@"Loaded root object %@ from nib file.", root);

  RELEASE(pool);
  return 0;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]