From 145a8afd69754ccbe5245dbd47082bcb1a19b1da Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 10 Jun 2006 13:34:44 +0000 Subject: [PATCH] Nib support changes. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@23043 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 19 + Gorm.m | 9 +- GormCore/GModelDecoder.m | 4 +- GormCore/GNUmakefile | 6 + GormCore/GormCustomView.m | 67 ++- GormCore/GormDocument.h | 82 ++- GormCore/GormDocument.m | 898 ++++++++++-------------------- GormCore/GormDocumentController.m | 1 - GormCore/GormGormWrapperBuilder.m | 195 +++++++ GormCore/GormGormWrapperLoader.m | 410 ++++++++++++++ GormCore/GormPrivate.h | 3 +- GormCore/GormPrivate.m | 88 +-- GormCore/GormWrapperBuilder.h | 51 ++ GormCore/GormWrapperBuilder.m | 165 ++++++ GormCore/GormWrapperLoader.h | 51 ++ GormCore/GormWrapperLoader.m | 157 ++++++ 16 files changed, 1507 insertions(+), 699 deletions(-) create mode 100644 GormCore/GormGormWrapperBuilder.m create mode 100644 GormCore/GormGormWrapperLoader.m create mode 100644 GormCore/GormWrapperBuilder.h create mode 100644 GormCore/GormWrapperBuilder.m create mode 100644 GormCore/GormWrapperLoader.h create mode 100644 GormCore/GormWrapperLoader.m diff --git a/ChangeLog b/ChangeLog index 985442c3..1bc52b28 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2006-06-10 09:24 Gregory John Casamento + + * GormCore/GModelDecoder.m: Changes to make this compile with + new modifications. + * GormCore/GNUmakefile: Addition of new files. + * GormCore/GormCustomView.m:Encoding changes for NSCustomView. + * GormCore/GormDocumentController.m: Removed touch, so that it + is possible to quit when first creating a new document, this is the + way other document oriented apps behave. + * GormCore/GormDocument.[hm]: Added container methods and + coding methods. + * GormCore/GormGormWrapperBuilder.m: Class whic writes gorm files. + * GormCore/GormGormWrapperLoader.m: Class which loads gorm files + * GormCore/GormPrivate.[hm]: Simplification of init call to + GormObjectProxy. + * GormCore/GormWrapperBuilder.[hm]: Wrapper builder + * GormCore/GormWrapperLoader.[hm]: Wrapper loader + * Gorm.m: Change testInterface to encode the doc. + 2006-06-05 21:20 Gregory John Casamento * GormCore/GormDocumentController.m: touches the initial document diff --git a/Gorm.m b/Gorm.m index d3a747cd..e1e623e2 100644 --- a/Gorm.m +++ b/Gorm.m @@ -42,7 +42,7 @@ NSMutableArray *documents; BOOL isConnecting; BOOL isTesting; - id testContainer; + id testContainer; id gormMenu; NSMenu *mainMenu; // saves the main menu... NSMenu *servicesMenu; // saves the services menu... @@ -451,7 +451,7 @@ // do not allow custom classes during testing. [GSClassSwapper setIsInInterfaceBuilder: YES]; - [archiver encodeRootObject: [activeDoc container]]; + [archiver encodeRootObject: activeDoc]; data = RETAIN([archiver archiverData]); // Released below... [activeDoc endArchiving]; RELEASE(archiver); @@ -478,6 +478,7 @@ NSMutableDictionary *nameTable = [testContainer nameTable]; // initialize the context. + RETAIN(testContainer); topObjects = [[NSMutableArray alloc] init]; context = [NSDictionary dictionaryWithObjectsAndKeys: topObjects, @"NSTopLevelObjects", self, @"NSOwner", nil]; @@ -859,8 +860,8 @@ DESTROY(testingWindows); - // deallocate top level objects - RELEASE(topObjects); + // deallocate + RELEASE(testContainer); return self; } diff --git a/GormCore/GModelDecoder.m b/GormCore/GModelDecoder.m index fb56b953..b30f5f79 100644 --- a/GormCore/GModelDecoder.m +++ b/GormCore/GModelDecoder.m @@ -563,11 +563,11 @@ static BOOL gormFileOwnerDecoded; [newcon setSource: source]; [newcon setDestination: (dest != nil)?dest:[self firstResponder]]; [newcon setLabel: [con label]]; - [[container connections] addObject: newcon]; + [[self connections] addObject: newcon]; } // make sure that all of the actions on the application's delegate object are also added to FirstResponder. - enumerator = [[container connections] objectEnumerator]; + enumerator = [connections objectEnumerator]; while ((con = [enumerator nextObject]) != nil) { if([con isKindOfClass: [NSNibControlConnector class]]) diff --git a/GormCore/GNUmakefile b/GormCore/GNUmakefile index ca9fd899..83355e04 100644 --- a/GormCore/GNUmakefile +++ b/GormCore/GNUmakefile @@ -86,6 +86,8 @@ GormCore_HEADER_FILES = \ GormViewWithContentViewEditor.h \ GormViewWithSubviewsEditor.h \ GormWindowEditor.h \ + GormWrapperBuilder.h \ + GormWrapperLoader.h \ NSCell+GormAdditions.h \ NSColorWell+GormExtensions.h \ NSFontManager+GormExtensions.h \ @@ -139,6 +141,10 @@ GormCore_OBJC_FILES = \ GormViewWithContentViewEditor.m \ GormViewWithSubviewsEditor.m \ GormWindowEditor.m \ + GormWrapperBuilder.m \ + GormWrapperLoader.m \ + GormGormWrapperBuilder.m \ + GormGormWrapperLoader.m \ NSCell+GormAdditions.m \ NSColorWell+GormExtensions.m \ NSFontManager+GormExtensions.m \ diff --git a/GormCore/GormCustomView.m b/GormCore/GormCustomView.m index b2c771c5..fa7a8065 100644 --- a/GormCore/GormCustomView.m +++ b/GormCore/GormCustomView.m @@ -32,6 +32,7 @@ #include #include +#include @class GSCustomView; @@ -87,38 +88,50 @@ - (id) initWithCoder: (NSCoder*)aCoder { - int version = [aCoder versionForClassName: - NSStringFromClass([GSCustomView class])]; - - if (version == 1) + if([aCoder allowsKeyedCoding]) { - NSString *string; - // do not decode super. We need to maintain mapping to NibItems - string = [aCoder decodeObject]; - _frame = [aCoder decodeRect]; - [self initWithFrame: _frame]; - [aCoder decodeValueOfObjCType: @encode(unsigned int) - at: &_autoresizingMask]; - [self setClassName: string]; - return self; - } - else if (version == 0) - { - NSString *string; - // do not decode super. We need to maintain mapping to NibItems - string = [aCoder decodeObject]; - _frame = [aCoder decodeRect]; - - [self initWithFrame: _frame]; - [self setClassName: string]; - return self; + NSCustomView *customView = [[NSCustomView alloc] initWithCoder: aCoder]; + [self initWithFrame: [customView frame]]; + [self setClassName: [customView className]]; + _autoresizingMask = [customView autoresizingMask]; + RELEASE(customView); } else { - NSLog(@"no initWithCoder for version"); - RELEASE(self); - return nil; + int version = [aCoder versionForClassName: + NSStringFromClass([GSCustomView class])]; + + if (version == 1) + { + NSString *string; + // do not decode super. We need to maintain mapping to NibItems + string = [aCoder decodeObject]; + _frame = [aCoder decodeRect]; + [self initWithFrame: _frame]; + [aCoder decodeValueOfObjCType: @encode(unsigned int) + at: &_autoresizingMask]; + [self setClassName: string]; + return self; + } + else if (version == 0) + { + NSString *string; + // do not decode super. We need to maintain mapping to NibItems + string = [aCoder decodeObject]; + _frame = [aCoder decodeRect]; + + [self initWithFrame: _frame]; + [self setClassName: string]; + return self; + } + else + { + NSLog(@"no initWithCoder for version"); + RELEASE(self); + return nil; + } } + return nil; } @end diff --git a/GormCore/GormDocument.h b/GormCore/GormDocument.h index 5842eeea..120e9bc3 100644 --- a/GormCore/GormDocument.h +++ b/GormCore/GormDocument.h @@ -31,7 +31,7 @@ #include #include -@class GormClassManager, GormClassEditor, GormObjectProxy, GormFilesOwner; +@class GormClassManager, GormClassEditor, GormObjectProxy, GormFilesOwner, GormFilePrefsManager; /* * Each document has a GormFirstResponder object that is used as a placeholder @@ -42,7 +42,7 @@ } @end -@interface GormDocument : NSDocument +@interface GormDocument : NSDocument { GormClassManager *classManager; GormFilesOwner *filesOwner; @@ -70,14 +70,20 @@ id lastEditor; BOOL isOlderArchive; id filePrefsView; - id filePrefsManager; + GormFilePrefsManager *filePrefsManager; NSWindow *filePrefsWindow; NSMutableArray *resourceManagers; NSData *infoData; /* data.info contents */ NSMutableArray *images; /* temporary storage for images. */ NSMutableArray *sounds; /* temporary storage for sounds. */ - NSFileWrapper *scmDirWrapper; - id container; + NSFileWrapper *scmWrapper; + + // container data structures + NSMutableDictionary *nameTable; + NSMutableArray *connections; + NSMutableSet *topLevelObjects; + NSMutableSet *visibleWindows; + NSMutableSet *deferredWindows; } /* Archiving objects */ @@ -146,11 +152,6 @@ */ - (NSWindow*) window; -/** - * Return the container object associated with this document. - */ -- (id) container; - /** * Returns YES, if obj is a top level object. */ @@ -311,9 +312,66 @@ - (NSWindow*) windowAndRect: (NSRect*)r forObject: (id)object; /** - * The container class to use in editing.... + * Save the SCM directory. */ -- (Class) containerClass; +- (void) setSCMWrapper: (NSFileWrapper *) wrapper; + +/** + * Save the SCM directory. + */ +- (NSFileWrapper *) scmWrapper; + +/** + * Images + */ +- (NSArray *) images; + +/** + * Sounds + */ +- (NSArray *) sounds; + +/** + * Images + */ +- (void) setImages: (NSArray *) imgs; + +/** + * Sounds + */ +- (void) setSounds: (NSArray *) snds; + +/** + * File's Owner + */ +- (GormFilesOwner *) filesOwner; + +/** + * File preferences. + */ +- (GormFilePrefsManager *) filePrefsManager; + +/** + * Windows visible at launch... + */ +- (NSSet *) visibleWindows; + +/** + * Windows deferred. + */ +- (NSSet *) deferredWindows; + +- (void) setDocumentOpen: (BOOL) flag; + +- (BOOL) isDocumentOpen; + +- (void) setInfoData: (NSData *)data; + +- (NSData *) infoData; + +- (void) setOlderArchive: (BOOL)flag; + +- (BOOL) isOlderArchive; @end @interface GormDocument (MenuValidation) diff --git a/GormCore/GormDocument.m b/GormCore/GormDocument.m index 000b61b5..83548583 100644 --- a/GormCore/GormDocument.m +++ b/GormCore/GormDocument.m @@ -50,6 +50,8 @@ #include "GormSoundEditor.h" #include "GormImageEditor.h" #include "GormObjectEditor.h" +#include "GormWrapperBuilder.h" +#include "GormWrapperLoader.h" @interface GormDisplayCell : NSButtonCell @end @@ -85,9 +87,6 @@ } @end -// Internal only -NSString *GSCustomClassMap = @"GSCustomClassMap"; - @interface NSDocument (GormPrivate) - (NSWindow *) _docWindow; @end @@ -207,11 +206,6 @@ static NSImage *fileImage = nil; } } -- (Class) containerClass -{ - return [GSNibContainer class]; -} - /** * Initialize the new GormDocument object. */ @@ -271,9 +265,14 @@ static NSImage *fileImage = nil; [self createResourceManagers]; /* - * Set up container.... - */ - container = [[[self containerClass] alloc] init]; + * Set up container data.... + */ + nameTable = [[NSMutableDictionary alloc] init]; + connections = [[NSMutableArray alloc] init]; + topLevelObjects = [[NSMutableSet alloc] init]; + visibleWindows = [[NSMutableSet alloc] init]; + deferredWindows = [[NSMutableSet alloc] init]; + filesOwner = [[GormFilesOwner alloc] init]; [self setName: @"NSOwner" forObject: filesOwner]; firstResponder = [[GormFirstResponder alloc] init]; @@ -435,7 +434,7 @@ static NSImage *fileImage = nil; hidden = [[NSMutableArray alloc] init]; // reposition the loaded menu appropriately... - mainMenu = [[container nameTable] objectForKey: @"NSMenu"]; + mainMenu = [nameTable objectForKey: @"NSMenu"]; if(mainMenu != nil) { NSRect frame = [window frame]; @@ -503,7 +502,7 @@ static NSImage *fileImage = nil; // All of the entries in the items array are "top level items" // which should be visible in the object's view. // - en = [[container topLevelObjects] objectEnumerator]; + en = [topLevelObjects objectEnumerator]; while((o = [en nextObject]) != nil) { [objectsView addObject: o]; @@ -515,12 +514,12 @@ static NSImage *fileImage = nil; */ - (void) addConnector: (id)aConnector { - if ([[container connections] indexOfObjectIdenticalTo: aConnector] == NSNotFound) + if ([connections indexOfObjectIdenticalTo: aConnector] == NSNotFound) { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc postNotificationName: IBWillAddConnectorNotification object: aConnector]; - [[container connections] addObject: aConnector]; + [connections addObject: aConnector]; [nc postNotificationName: IBDidAddConnectorNotification object: aConnector]; } @@ -531,7 +530,7 @@ static NSImage *fileImage = nil; */ - (NSArray*) allConnectors { - return [NSArray arrayWithArray: [container connections]]; + return [NSArray arrayWithArray: connections]; } /** @@ -541,8 +540,7 @@ static NSImage *fileImage = nil; { GSNibItem *item = nil; - item = [[GormObjectProxy alloc] initWithClassName: @"NSFontManager" - frame: NSMakeRect(0,0,0,0)]; + item = [[GormObjectProxy alloc] initWithClassName: @"NSFontManager"]; [self setName: @"NSFont" forObject: item]; [self attachObject: item toParent: nil]; @@ -601,7 +599,7 @@ static NSImage *fileImage = nil; [anObject isKindOfClass: [GSNibItem class]]) { [objectsView addObject: anObject]; - [[container topLevelObjects] addObject: anObject]; + [topLevelObjects addObject: anObject]; if ([anObject isKindOfClass: [NSWindow class]]) { NSWindow *win = (NSWindow *)anObject; @@ -633,12 +631,12 @@ static NSImage *fileImage = nil; [anObject isKindOfClass: [NSView class]] == NO) { [objectsView addObject: anObject]; - [[container topLevelObjects] addObject: anObject]; + [topLevelObjects addObject: anObject]; } else if([anObject isKindOfClass: [NSView class]] && [anObject superview] == nil) { [objectsView addObject: anObject]; - [[container topLevelObjects] addObject: anObject]; + [topLevelObjects addObject: anObject]; } } /* @@ -692,7 +690,7 @@ static NSImage *fileImage = nil; { [self setName: @"NSMenu" forObject: menu]; [objectsView addObject: menu]; - [[container topLevelObjects] addObject: menu]; + [topLevelObjects addObject: menu]; isMainMenu = YES; } else @@ -983,7 +981,7 @@ static NSImage *fileImage = nil; ofClass: (Class)aConnectorClass { NSMutableArray *array = [NSMutableArray arrayWithCapacity: 16]; - NSEnumerator *enumerator = [[container connections] objectEnumerator]; + NSEnumerator *enumerator = [connections objectEnumerator]; id c; while ((c = [enumerator nextObject]) != nil) @@ -1013,7 +1011,7 @@ static NSImage *fileImage = nil; ofClass: (Class)aConnectorClass { NSMutableArray *array = [NSMutableArray arrayWithCapacity: 16]; - NSEnumerator *enumerator = [[container connections] objectEnumerator]; + NSEnumerator *enumerator = [connections objectEnumerator]; id c; while ((c = [enumerator nextObject]) != nil) @@ -1045,7 +1043,7 @@ static NSImage *fileImage = nil; */ - (BOOL) containsObjectWithName: (NSString*)aName forParent: (id)parent { - id obj = [[container nameTable] objectForKey: aName]; + id obj = [nameTable objectForKey: aName]; if (obj == nil) { @@ -1176,9 +1174,13 @@ static NSImage *fileImage = nil; RELEASE(imagesScrollView); RELEASE(filePrefsWindow); RELEASE(resourceManagers); - RELEASE(container); - - TEST_RELEASE(scmDirWrapper); + RELEASE(nameTable); + RELEASE(connections); + RELEASE(topLevelObjects); + RELEASE(visibleWindows); + RELEASE(deferredWindows); + + TEST_RELEASE(scmWrapper); [super dealloc]; } @@ -1249,14 +1251,14 @@ static NSImage *fileImage = nil; [parent selectObjects: [NSArray array]]; } - count = [[container connections] count]; + count = [connections count]; while (count-- > 0) { - id con = [[container connections] objectAtIndex: count]; + id con = [connections objectAtIndex: count]; if ([con destination] == anObject || [con source] == anObject) { - [[container connections] removeObjectAtIndex: count]; + [connections removeObjectAtIndex: count]; } } @@ -1268,15 +1270,15 @@ static NSImage *fileImage = nil; if ([anObject isKindOfClass: [NSWindow class]] || [anObject isKindOfClass: [NSMenu class]] - || [[container topLevelObjects] containsObject: anObject]) + || [topLevelObjects containsObject: anObject]) { [objectsView removeObject: anObject]; } // if it's in the top level items array, remove it. - if([[container topLevelObjects] containsObject: anObject]) + if([topLevelObjects containsObject: anObject]) { - [[container topLevelObjects] removeObject: anObject]; + [topLevelObjects removeObject: anObject]; } // eliminate it from being the windows/services menu, if it's being detached. @@ -1327,7 +1329,7 @@ static NSImage *fileImage = nil; [anObject removeFromSuperview]; } - [[container nameTable] removeObjectForKey: name]; + [nameTable removeObjectForKey: name]; // free... NSMapRemove(objToName, (void*)anObject); @@ -1506,7 +1508,7 @@ static NSImage *fileImage = nil; NSAssert([links count] < 2, NSInternalInconsistencyException); if ([links count] == 1) { - [[container connections] removeObjectIdenticalTo: [links objectAtIndex: 0]]; + [connections removeObjectIdenticalTo: [links objectAtIndex: 0]]; } /* @@ -1517,7 +1519,7 @@ static NSImage *fileImage = nil; NSAssert([links count] < 2, NSInternalInconsistencyException); if ([links count] == 1) { - [[container connections] removeObjectIdenticalTo: [links objectAtIndex: 0]]; + [connections removeObjectIdenticalTo: [links objectAtIndex: 0]]; } /* @@ -1572,7 +1574,7 @@ static NSImage *fileImage = nil; link = AUTORELEASE([[GormObjectToEditor alloc] init]); [link setSource: anObject]; [link setDestination: editor]; - [[container connections] addObject: link]; + [connections addObject: link]; if(![openEditors containsObject: editor] && editor != nil) { @@ -1595,7 +1597,7 @@ static NSImage *fileImage = nil; link = AUTORELEASE([[GormEditorToParent alloc] init]); [link setSource: editor]; [link setDestination: anEditor]; - [[container connections] addObject: link]; + [connections addObject: link]; } else { @@ -1632,7 +1634,7 @@ static NSImage *fileImage = nil; * Deactivate editors so they won't be archived. */ - enumerator = [[container connections] objectEnumerator]; + enumerator = [connections objectEnumerator]; while ((con = [enumerator nextObject]) != nil) { if ([con isKindOfClass: [GormObjectToEditor class]]) @@ -1655,22 +1657,19 @@ static NSImage *fileImage = nil; [con setDestination: name]; } } - [[container connections] removeObjectsInArray: savedEditors]; - - NSDebugLog(@"Custom Class Map = %@",[classManager customClassMap]); - [[container nameTable] setObject: [classManager customClassMap] forKey: GSCustomClassMap]; + [connections removeObjectsInArray: savedEditors]; /* * Remove objects and connections that shouldn't be archived. */ - NSMapRemove(objToName, (void*)[[container nameTable] objectForKey: @"NSOwner"]); - [[container nameTable] removeObjectForKey: @"NSOwner"]; - NSMapRemove(objToName, (void*)[[container nameTable] objectForKey: @"NSFirst"]); - [[container nameTable] removeObjectForKey: @"NSFirst"]; + NSMapRemove(objToName, (void*)[nameTable objectForKey: @"NSOwner"]); + [nameTable removeObjectForKey: @"NSOwner"]; + NSMapRemove(objToName, (void*)[nameTable objectForKey: @"NSFirst"]); + [nameTable removeObjectForKey: @"NSFirst"]; /* Add information about the NSOwner to the archive */ NSMapInsert(objToName, (void*)[filesOwner className], (void*)@"NSOwner"); - [[container nameTable] setObject: [filesOwner className] forKey: @"NSOwner"]; + [nameTable setObject: [filesOwner className] forKey: @"NSOwner"]; /* * Set the appropriate profile so that we save the right versions of @@ -1696,16 +1695,16 @@ static NSImage *fileImage = nil; /* * Restore removed objects. */ - [[container nameTable] setObject: filesOwner forKey: @"NSOwner"]; + [nameTable setObject: filesOwner forKey: @"NSOwner"]; NSMapInsert(objToName, (void*)filesOwner, (void*)@"NSOwner"); - [[container nameTable] setObject: firstResponder forKey: @"NSFirst"]; + [nameTable setObject: firstResponder forKey: @"NSFirst"]; NSMapInsert(objToName, (void*)firstResponder, (void*)@"NSFirst"); /* * Map all connector source and destination names to their objects. */ - enumerator = [[container connections] objectEnumerator]; + enumerator = [connections objectEnumerator]; while ((con = [enumerator nextObject]) != nil) { NSString *name; @@ -1720,7 +1719,7 @@ static NSImage *fileImage = nil; /* * Restore editor links and reactivate the editors. */ - [[container connections] addObjectsFromArray: savedEditors]; + [connections addObjectsFromArray: savedEditors]; enumerator = [savedEditors objectEnumerator]; while ((con = [enumerator nextObject]) != nil) { @@ -1740,7 +1739,7 @@ static NSImage *fileImage = nil; NSMutableArray *editors = [NSMutableArray array]; // remove the editor connections from the connection array... - enumerator = [[container connections] objectEnumerator]; + enumerator = [connections objectEnumerator]; while ((con = [enumerator nextObject]) != nil) { if ([con isKindOfClass: [GormObjectToEditor class]]) @@ -1752,7 +1751,7 @@ static NSImage *fileImage = nil; [editors addObject: con]; } } - [[container connections] removeObjectsInArray: editors]; + [connections removeObjectsInArray: editors]; [editors removeAllObjects]; // Close all of the editors & get all of the objects out. @@ -1789,14 +1788,13 @@ static NSImage *fileImage = nil; NSEnumerator *enumerator; id obj; - enumerator = [[container nameTable] objectEnumerator]; + enumerator = [nameTable objectEnumerator]; while ((obj = [enumerator nextObject]) != nil) { if ([obj isKindOfClass: [NSWindow class]]) { [obj setReleasedWhenClosed: YES]; [obj close]; - // RELEASE(obj); } } @@ -1833,7 +1831,7 @@ static NSImage *fileImage = nil; [[self window] orderOut: self]; } - enumerator = [[container nameTable] objectEnumerator]; + enumerator = [nameTable objectEnumerator]; while ((obj = [enumerator nextObject]) != nil) { if ([obj isKindOfClass: [NSMenu class]]) @@ -1985,9 +1983,7 @@ static NSImage *fileImage = nil; } else { - item = [[GormObjectProxy alloc] initWithClassName: object - frame: NSMakeRect(0,0,0,0)]; - + item = [[GormObjectProxy alloc] initWithClassName: object]; [self setName: nil forObject: item]; [self attachObject: item toParent: nil]; [self changeToViewWithTag: 0]; @@ -2017,7 +2013,7 @@ static NSImage *fileImage = nil; */ - (id) objectForName: (NSString*)name { - return [[container nameTable] objectForKey: name]; + return [nameTable objectForKey: name]; } /** @@ -2025,7 +2021,7 @@ static NSImage *fileImage = nil; */ - (NSArray*) objects { - return [[container nameTable] allValues]; + return [nameTable allValues]; } /** @@ -2075,97 +2071,6 @@ static NSImage *fileImage = nil; [classesView selectClass: className editClass: flag]; } -/** - * The sole purpose of this method is to clean up .gorm files from older - * versions of Gorm which might have some dangling references. This method - * may be added to as time goes on to make sure that it's possible - * to repair old .gorm files. - */ -- (void) _repairFile -{ - NSEnumerator *en = [[[container nameTable] allKeys] objectEnumerator]; - NSString *key = nil; - - NSRunAlertPanel(_(@"Warning"), - _(@"You are running with 'GormRepairFileOnLoad' set to YES."), - nil, nil, nil); - - while((key = [en nextObject]) != nil) - { - id obj = [[container nameTable] objectForKey: key]; - if([obj isKindOfClass: [NSMenu class]] && ![key isEqual: @"NSMenu"]) - { - id sm = [obj supermenu]; - if(sm == nil) - { - NSArray *menus = findAll(obj); - NSLog(@"Found and removed a dangling menu %@, %@.",obj,[self nameForObject: obj]); - [self detachObjects: menus]; - [self detachObject: obj]; - - // Since the menu is a top level object, it is not retained by - // anything else. When it was unarchived it was autoreleased, and - // the detach also does a release. Unfortunately, this causes a - // crash, so this extra retain is only here to stave off the - // release, so the autorelease can release the menu when it should. - RETAIN(obj); // extra retain to stave off autorelease... - } - } - - if([obj isKindOfClass: [NSMenuItem class]]) - { - id m = [obj menu]; - if(m == nil) - { - id sm = [obj submenu]; - - NSLog(@"Found and removed a dangling menu item %@, %@.",obj,[self nameForObject: obj]); - [self detachObject: obj]; - - // if there are any submenus, detach those as well. - if(sm != nil) - { - NSArray *menus = findAll(sm); - [self detachObjects: menus]; - } - } - } - - /** - * If it's a view and it does't have a window *AND* it's not a top level object - * then it's not a standalone view, it's an orphan. Delete it. - */ - if([obj isKindOfClass: [NSView class]]) - { - if([obj window] == nil && - [[container topLevelObjects] containsObject: obj] == NO && - [obj hasSuperviewKindOfClass: [NSTabView class]] == NO) - { - NSLog(@"Found and removed an orphan view %@, %@",obj,[self nameForObject: obj]); - [self detachObject: obj]; - } - } - } -} - -/** - * Private method. Determines if the document contains an instance of a given - * class or one of it's subclasses. - */ -- (BOOL) _containsKindOfClass: (Class)cls -{ - NSEnumerator *en = [[container nameTable] objectEnumerator]; - id obj = nil; - while((obj = [en nextObject]) != nil) - { - if([obj isKindOfClass: cls]) - { - return YES; - } - } - return NO; -} - /** * Build our reverse mapping information and other initialisation */ @@ -2178,10 +2083,10 @@ static NSImage *fileImage = nil; NSResetMapTable(objToName); NSMapInsert(objToName, (void*)filesOwner, (void*)@"NSOwner"); NSMapInsert(objToName, (void*)firstResponder, (void*)@"NSFirst"); - enumerator = [[[container nameTable] allKeys] objectEnumerator]; + enumerator = [[nameTable allKeys] objectEnumerator]; while ((name = [enumerator nextObject]) != nil) { - id obj = [[container nameTable] objectForKey: name]; + id obj = [nameTable objectForKey: name]; NSDebugLog(@"%@ --> %@",name, obj); @@ -2339,7 +2244,7 @@ static NSImage *fileImage = nil; [self touch]; // issue post notification.. - [[container connections] removeObjectIdenticalTo: aConnector]; + [connections removeObjectIdenticalTo: aConnector]; [nc postNotificationName: IBDidRemoveConnectorNotification object: aConnector]; RELEASE(aConnector); // NOW we can dealloc it. @@ -2353,7 +2258,7 @@ static NSImage *fileImage = nil; */ - (void) resignSelectionForEditor: (id)editor { - NSEnumerator *enumerator = [[container connections] objectEnumerator]; + NSEnumerator *enumerator = [connections objectEnumerator]; Class editClass = [GormObjectToEditor class]; id c; @@ -2429,7 +2334,7 @@ static NSImage *fileImage = nil; } aName = [base stringByAppendingFormat: @"(%u)", i]; - while ([[container nameTable] objectForKey: aName] != nil) + while ([nameTable objectForKey: aName] != nil) { aName = [base stringByAppendingFormat: @"(%u)", ++i]; } @@ -2441,7 +2346,7 @@ static NSImage *fileImage = nil; } else // user supplied a name... { - oldObject = [[container nameTable] objectForKey: aName]; + oldObject = [nameTable objectForKey: aName]; if (oldObject != nil) { NSDebugLog(@"Attempt to re-use name '%@'", aName); @@ -2454,18 +2359,18 @@ static NSImage *fileImage = nil; { return; /* Already have this name ... nothing to do */ } - [[container nameTable] removeObjectForKey: oldName]; + [nameTable removeObjectForKey: oldName]; NSMapRemove(objToName, (void*)object); } } // add it to the dictionary. - [[container nameTable] setObject: object forKey: aName]; + [nameTable setObject: object forKey: aName]; NSMapInsert(objToName, (void*)object, (void*)aName); if (oldName != nil) { RETAIN(oldName); // hold on to this temporarily... - [[container nameTable] removeObjectForKey: oldName]; + [nameTable removeObjectForKey: oldName]; } if ([objectsView containsObject: object]) { @@ -2496,24 +2401,13 @@ static NSImage *fileImage = nil; */ - (void) setObject: (id)anObject isVisibleAtLaunch: (BOOL)flag { - NSMutableArray *a = [[container nameTable] objectForKey: @"NSVisible"]; - if (flag) { - if (a == nil) - { - a = [[NSMutableArray alloc] init]; - [[container nameTable] setObject: a forKey: @"NSVisible"]; - RELEASE(a); - } - if ([a containsObject: anObject] == NO) - { - [a addObject: anObject]; - } + [visibleWindows addObject: anObject]; } else { - [a removeObject: anObject]; + [visibleWindows removeObject: anObject]; } } @@ -2522,7 +2416,7 @@ static NSImage *fileImage = nil; */ - (BOOL) objectIsVisibleAtLaunch: (id)anObject { - return [[[container nameTable] objectForKey: @"NSVisible"] containsObject: anObject]; + return [visibleWindows containsObject: anObject]; } /** @@ -2530,24 +2424,13 @@ static NSImage *fileImage = nil; */ - (void) setObject: (id)anObject isDeferred: (BOOL)flag { - NSMutableArray *a = [[container nameTable] objectForKey: @"NSDeferred"]; - if (flag) { - if (a == nil) - { - a = [[NSMutableArray alloc] init]; - [[container nameTable] setObject: a forKey: @"NSDeferred"]; - RELEASE(a); - } - if ([a containsObject: anObject] == NO) - { - [a addObject: anObject]; - } + [deferredWindows addObject: anObject]; } else { - [a removeObject: anObject]; + [deferredWindows removeObject: anObject]; } } @@ -2556,7 +2439,7 @@ static NSImage *fileImage = nil; */ - (BOOL) objectIsDeferred: (id)anObject { - return [[[container nameTable] objectForKey: @"NSDeferred"] containsObject: anObject]; + return [deferredWindows containsObject: anObject]; } // windows / services menus... @@ -2568,11 +2451,11 @@ static NSImage *fileImage = nil; { if(anObject != nil) { - [[container nameTable] setObject: anObject forKey: @"NSWindowsMenu"]; + [nameTable setObject: anObject forKey: @"NSWindowsMenu"]; } else { - [[container nameTable] removeObjectForKey: @"NSWindowsMenu"]; + [nameTable removeObjectForKey: @"NSWindowsMenu"]; } } @@ -2581,7 +2464,7 @@ static NSImage *fileImage = nil; */ - (NSMenu *) windowsMenu { - return [[container nameTable] objectForKey: @"NSWindowsMenu"]; + return [nameTable objectForKey: @"NSWindowsMenu"]; } /** @@ -2591,11 +2474,11 @@ static NSImage *fileImage = nil; { if(anObject != nil) { - [[container nameTable] setObject: anObject forKey: @"NSServicesMenu"]; + [nameTable setObject: anObject forKey: @"NSServicesMenu"]; } else { - [[container nameTable] removeObjectForKey: @"NSServicesMenu"]; + [nameTable removeObjectForKey: @"NSServicesMenu"]; } } @@ -2604,64 +2487,7 @@ static NSImage *fileImage = nil; */ - (NSMenu *) servicesMenu { - return [[container nameTable] objectForKey: @"NSServicesMenu"]; -} - -/** - * Private method which iterates through the list of custom classes and instructs - * the archiver to replace the actual object with template during the archiving - * process. - */ -- (void) _replaceObjectsWithTemplates: (NSArchiver *)archiver -{ - NSEnumerator *en = [[container nameTable] keyEnumerator]; - id key = nil; - - // loop through all custom objects and windows - while((key = [en nextObject]) != nil) - { - id customClass = [classManager customClassForName: key]; - id object = [self objectForName: key]; - id template = nil; - if(customClass != nil) - { - NSString *superClass = [classManager nonCustomSuperClassOf: customClass]; - template = [GSTemplateFactory templateForObject: object - withClassName: customClass - withSuperClassName: superClass]; - } - else if([object isKindOfClass: [NSWindow class]] - && [filePrefsManager versionOfClass: @"GSWindowTemplate"] > 0) - { - template = [GSTemplateFactory templateForObject: object - withClassName: [object className] - withSuperClassName: [object className]]; - - } - - // if the template has been created, replace the object with it. - if(template != nil) - { - // if the object is deferrable, then set the flag appropriately. - if([template respondsToSelector: @selector(setDeferFlag:)]) - { - [template setDeferFlag: [self objectIsDeferred: object]]; - } - - // if the object can accept autoposition information - if([object respondsToSelector: @selector(autoPositionMask)]) - { - int mask = [object autoPositionMask]; - if([template respondsToSelector: @selector(setAutoPositionMask:)]) - { - [template setAutoPositionMask: mask]; - } - } - - // replace the object with the template. - [archiver replaceObject: object withObject: template]; - } - } + return [nameTable objectForKey: @"NSServicesMenu"]; } /** @@ -2678,7 +2504,7 @@ static NSImage *fileImage = nil; // stop all connection activities. [(id)NSApp stopConnecting]; - enumerator = [[container nameTable] objectEnumerator]; + enumerator = [nameTable objectEnumerator]; if (flag) { GormDocument *document = (GormDocument*)[(id)NSApp activeDocument]; @@ -2861,14 +2687,6 @@ static NSImage *fileImage = nil; return [winController window]; } -/** - * Return the container object associated with this document. - */ -- (id) container -{ - return container; -} - /** * Removes all connections given action or outlet with the specified label * (paramter name) class name (parameter className). @@ -2877,7 +2695,7 @@ static NSImage *fileImage = nil; forClassNamed: (NSString *)className isAction: (BOOL)action { - NSEnumerator *en = [[container connections] objectEnumerator]; + NSEnumerator *en = [connections objectEnumerator]; NSMutableArray *removedConnections = [NSMutableArray array]; id c = nil; BOOL removed = YES; @@ -2994,7 +2812,7 @@ static NSImage *fileImage = nil; NSMutableArray *removedConnections = [NSMutableArray array]; // first find all of the connections... - en = [[container connections] objectEnumerator]; + en = [connections objectEnumerator]; while ((c = [en nextObject]) != nil) { NSString *srcClass = [[c source] className]; @@ -3029,7 +2847,7 @@ static NSImage *fileImage = nil; - (BOOL) renameConnectionsForClassNamed: (NSString *)className toName: (NSString *)newName { - NSEnumerator *en = [[container connections] objectEnumerator]; + NSEnumerator *en = [connections objectEnumerator]; id c = nil; BOOL renamed = YES; int retval = -1; @@ -3082,9 +2900,9 @@ static NSImage *fileImage = nil; */ - (void) printAllEditors { - NSMutableSet *set = [NSMutableSet setWithCapacity: 16]; - NSEnumerator *enumerator = [[container connections] objectEnumerator]; - id c; + NSMutableSet *set = [NSMutableSet setWithCapacity: 16]; + NSEnumerator *enumerator = [connections objectEnumerator]; + id c; while ((c = [enumerator nextObject]) != nil) { @@ -3171,7 +2989,7 @@ static NSImage *fileImage = nil; return [NSString stringWithFormat: @"<%s: %lx> = %@", GSClassNameFromObject(self), (unsigned long)self, - [container nameTable]]; + nameTable]; } /** @@ -3179,7 +2997,7 @@ static NSImage *fileImage = nil; */ - (BOOL) isTopLevelObject: (id)obj { - return [[container topLevelObjects] containsObject: obj]; + return [topLevelObjects containsObject: obj]; } /** @@ -3277,8 +3095,8 @@ static NSImage *fileImage = nil; */ - (NSMutableArray *) _collectAllObjects { - NSMutableArray *allObjects = [NSMutableArray arrayWithArray: [[container topLevelObjects] allObjects]]; - NSEnumerator *en = [[container topLevelObjects] objectEnumerator]; + NSMutableArray *allObjects = [NSMutableArray arrayWithArray: [topLevelObjects allObjects]]; + NSEnumerator *en = [topLevelObjects objectEnumerator]; NSMutableArray *removeObjects = [NSMutableArray array]; id obj = nil; @@ -3557,15 +3375,6 @@ static NSImage *fileImage = nil; } } -- (void) saveSCMDirectory: (NSDictionary *) fileWrappers -{ - ASSIGN(scmDirWrapper, [fileWrappers objectForKey: @".svn"]); - if(scmDirWrapper == nil) - { - ASSIGN(scmDirWrapper, [fileWrappers objectForKey: @"CVS"]); - } -} - /** * The window nib for the document class... */ @@ -3574,20 +3383,14 @@ static NSImage *fileImage = nil; return @"GormDocument"; } +/** + * Call the builder and create the file wrapper to save the appropriate format. + */ - (NSFileWrapper *)fileWrapperRepresentationOfType: (NSString *)type { - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - NSArchiver *archiver = nil; - NSMutableData *archiverData = nil; - NSString *gormPath = @"objects.gorm"; - NSString *classesPath = @"data.classes"; - NSString *infoPath = @"data.info"; - GormPalettesManager *palettesManager = [(id)NSApp palettesManager]; - NSDictionary *substituteClasses = [palettesManager substituteClasses]; - NSEnumerator *en = [substituteClasses keyEnumerator]; - NSString *subClassName = nil; - NSFileWrapper *fileWrapper = nil; - NSMutableDictionary *fileWrappers = [NSMutableDictionary dictionary]; + id builder = [[GormWrapperBuilderFactory sharedWrapperBuilderFactory] + wrapperBuilderForType: type]; + NSFileWrapper *result = nil; /* * Warn the user, if we are about to upgrade the package. @@ -3614,344 +3417,43 @@ static NSImage *fileImage = nil; /* * Notify the world that we are saving... */ - [nc postNotificationName: IBWillSaveDocumentNotification - object: self]; + [[NSNotificationCenter defaultCenter] + postNotificationName: IBWillSaveDocumentNotification + object: self]; - /* - * Set up archiving... - */ [self beginArchiving]; - archiverData = [NSMutableData dataWithCapacity: 0]; - archiver = [[NSArchiver alloc] initForWritingWithMutableData: archiverData]; - - /* Special gorm classes to their archive equivalents. */ - [archiver encodeClassName: @"GormObjectProxy" - intoClassName: @"GSNibItem"]; - [archiver encodeClassName: @"GormCustomView" - intoClassName: @"GSCustomView"]; - - while((subClassName = [en nextObject]) != nil) - { - NSString *realClassName = [substituteClasses objectForKey: subClassName]; - [archiver encodeClassName: subClassName - intoClassName: realClassName]; - } - - /* Initialize templates */ - [self _replaceObjectsWithTemplates: archiver]; - [archiver encodeRootObject: container]; + result = [builder buildFileWrapperWithDocument: self]; [self endArchiving]; - RELEASE(archiver); // We're done with the archiver here.. - // - // Add the gorm, info and classes files to the package. - // - fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: archiverData]; - [fileWrappers setObject: fileWrapper forKey: gormPath]; - RELEASE(fileWrapper); - fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: [classManager data]]; - [fileWrappers setObject: fileWrapper forKey: classesPath]; - RELEASE(fileWrapper); - fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: [filePrefsManager data]]; - [fileWrappers setObject: fileWrapper forKey: infoPath]; - RELEASE(fileWrapper); - - // - // Add the SCM wrapper to the wrapper, if it's present. - // - if(scmDirWrapper != nil) + if(result) { - NSString *name = [[scmDirWrapper filename] lastPathComponent]; - [fileWrappers setObject: scmDirWrapper forKey: name]; + /* + * This is the last thing we should do... + */ + [[NSNotificationCenter defaultCenter] + postNotificationName: IBDidSaveDocumentNotification + object: self]; } - - // - // Copy resources into the new folder... - // Gorm doesn't copy these into the folder right away since the folder may - // not yet exist. This allows the user to add/delete resources as they see fit - // but only those which they end up with will actually be put into the wrapper - // when the model/document is saved. - // - NSArray *resources = [sounds arrayByAddingObjectsFromArray: images]; - id object = nil; - en = [resources objectEnumerator]; - while ((object = [en nextObject]) != nil) - { - if([object isSystemResource] == NO) - { - NSString *path = [object path]; - NSString *resName = nil; - NSData *resData = nil; - - if([object isInWrapper]) - { - resName = [object filename]; - resData = [object data]; - } - else - { - resName = [path lastPathComponent]; - resData = [NSData dataWithContentsOfFile: path]; - [object setData: resData]; - [object setInWrapper: YES]; - } - - fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: resData]; - [fileWrappers setObject: fileWrapper forKey: resName]; - RELEASE(fileWrapper); - } - } - - // notify everyone of the save. - [nc postNotificationName: IBDidSaveDocumentNotification - object: self]; - - return [[NSFileWrapper alloc] initDirectoryWithFileWrappers: fileWrappers]; + + return result; } + - (BOOL)loadFileWrapperRepresentation: (NSFileWrapper *)wrapper ofType: (NSString *)type { - NS_DURING + id loader = [[GormWrapperLoaderFactory sharedWrapperLoaderFactory] + wrapperLoaderForType: type]; + BOOL result = [loader loadFileWrapper: wrapper withDocument: self]; + + if(result) { - NSMutableDictionary *nt = nil; - NSMutableDictionary *cc = nil; - NSData *data = nil; - NSData *classes = nil; - NSUnarchiver *u = nil; - NSEnumerator *enumerator = nil; - id con = nil; - NSString *ownerClass, *key = nil; - BOOL repairFile = [[NSUserDefaults standardUserDefaults] boolForKey: @"GormRepairFileOnLoad"]; - GormPalettesManager *palettesManager = [(id)NSApp palettesManager]; - NSDictionary *substituteClasses = [palettesManager substituteClasses]; - NSEnumerator *en = [substituteClasses keyEnumerator]; - NSString *subClassName = nil; - unsigned int version = NSNotFound; - NSDictionary *fileWrappers = nil; - - if ([wrapper isDirectory]) - { - NSArray *imageFileTypes = [NSImage imageFileTypes]; - NSArray *soundFileTypes = [NSSound soundUnfilteredFileTypes]; - - // initialize arrays for sounds/images. - images = [[NSMutableArray alloc] init]; - sounds = [[NSMutableArray alloc] init]; - - key = nil; - fileWrappers = [wrapper fileWrappers]; - - [self saveSCMDirectory: fileWrappers]; - - enumerator = [fileWrappers keyEnumerator]; - while((key = [enumerator nextObject]) != nil) - { - NSFileWrapper *fw = [fileWrappers objectForKey: key]; - if([fw isRegularFile]) - { - NSData *fileData = [fw regularFileContents]; - if([key isEqual: @"objects.gorm"]) - { - data = fileData; - } - else if([key isEqual: @"data.info"]) - { - ASSIGN(infoData, fileData); - } - else if([key isEqual: @"data.classes"]) - { - classes = fileData; - - // load the custom classes... - if (![classManager loadCustomClassesWithData: classes]) - { - NSRunAlertPanel(_(@"Problem Loading"), - _(@"Could not open the associated classes file.\n" - @"You won't be able to edit connections on custom classes"), - _(@"OK"), nil, nil); - } - } - else if ([imageFileTypes containsObject: [key pathExtension]]) - { - [images addObject: [GormImage imageForData: fileData withFileName: key inWrapper: YES]]; - } - else if ([soundFileTypes containsObject: [key pathExtension]]) - { - [sounds addObject: [GormSound soundForData: fileData withFileName: key inWrapper: YES]]; - } - } - } - } - else - { - return NO; - } - - // check the data... - if (data == nil || infoData == nil || classes == nil) - { - return NO; - } - - /* - * Create an unarchiver, and use it to unarchive the gorm file while - * handling class replacement so that standard objects understood - * by the gui library are converted to their Gorm internal equivalents. - */ - u = [[NSUnarchiver alloc] initForReadingWithData: data]; - - /* - * Special internal classes - */ - [u decodeClassName: @"GSNibItem" - asClassName: @"GormObjectProxy"]; - [u decodeClassName: @"GSCustomView" - asClassName: @"GormCustomView"]; - - /* - * Substitute any classes specified by the palettes... - */ - while((subClassName = [en nextObject]) != nil) - { - NSString *realClassName = [substituteClasses objectForKey: subClassName]; - [u decodeClassName: realClassName - asClassName: subClassName]; - } - - // turn off custom classes. - [GSClassSwapper setIsInInterfaceBuilder: YES]; - ASSIGN(container, [u decodeObject]); - if (container == nil || [container isKindOfClass: [GSNibContainer class]] == NO) - { - return NO; - } - // turn on custom classes. - [GSClassSwapper setIsInInterfaceBuilder: NO]; - - /* - * Retrieve the custom class data and refresh the classes view... - */ - cc = [[container nameTable] objectForKey: GSCustomClassMap]; - if (cc == nil) - { - cc = [NSMutableDictionary dictionary]; // create an empty one. - [[container nameTable] setObject: cc forKey: GSCustomClassMap]; - } - - [classManager setCustomClassMap: cc]; - NSDebugLog(@"cc = %@", cc); - NSDebugLog(@"customClasses = %@", [classManager customClassMap]); - [classesView reloadData]; - - /* - * In the newly loaded nib container, we change all the connectors - * to hold the objects rather than their names (using our own dummy - * object as the 'NSOwner'. - */ - ownerClass = [[container nameTable] objectForKey: @"NSOwner"]; - if (ownerClass) - { - [filesOwner setClassName: ownerClass]; - } - [[container nameTable] setObject: filesOwner forKey: @"NSOwner"]; - [[container nameTable] setObject: firstResponder forKey: @"NSFirst"]; - - /* Iterate over the contents of nameTable and create the connections */ - nt = [container nameTable]; - enumerator = [[container connections] objectEnumerator]; - while ((con = [enumerator nextObject]) != nil) - { - NSString *name; - id obj; - - name = (NSString*)[con source]; - obj = [nt objectForKey: name]; - [con setSource: obj]; - name = (NSString*)[con destination]; - obj = [nt objectForKey: name]; - [con setDestination: obj]; - } - - /* - * If the GSNibContainer version is 0, we need to add the top level objects - * to the list so that they can be properly processed. - */ - if([u versionForClassName: NSStringFromClass([GSNibContainer class])] == 0) - { - id obj; - NSEnumerator *en = [nt objectEnumerator]; - - // get all of the GSNibItem subclasses which could be top level objects - while((obj = [en nextObject]) != nil) - { - if([obj isKindOfClass: [GSNibItem class]] && - [obj isKindOfClass: [GSCustomView class]] == NO) - { - [[container topLevelObjects] addObject: obj]; - } - } - isOlderArchive = YES; - } - - /* - * If the GSWindowTemplate version is 0, we need to let Gorm know that this is - * an older archive. Also, if the window template is not in the archive we know - * it was made by an older version of Gorm. - */ - version = [u versionForClassName: NSStringFromClass([GSWindowTemplate class])]; - if(version == NSNotFound && [self _containsKindOfClass: [NSWindow class]]) - { - isOlderArchive = YES; - } - - /* - * repair the .gorm file, if needed. - */ - if(repairFile) - { - [self _repairFile]; - } - - /* - * Rebuild the mapping from object to name for the nameTable... - */ - [self rebuildObjToNameMapping]; - - NSDebugLog(@"nameTable = %@",[container nameTable]); - - // awaken all elements after the load is completed. - enumerator = [[container nameTable] keyEnumerator]; - while ((key = [enumerator nextObject]) != nil) - { - id o = [[container nameTable] objectForKey: key]; - if ([o respondsToSelector: @selector(awakeFromDocument:)]) - { - [o awakeFromDocument: self]; - } - } - // this is the last thing we should do... [[NSNotificationCenter defaultCenter] postNotificationName: IBDidOpenDocumentNotification object: self]; - - // document opened... - isDocumentOpen = YES; - - // release the unarchiver.. now that we're all done... - RELEASE(u); } - NS_HANDLER - { - NSRunAlertPanel(_(@"Problem Loading"), - [NSString stringWithFormat: @"Failed to load file. Exception: %@",[localException reason]], - _(@"OK"), nil, nil); - return NO; - } - NS_ENDHANDLER; - - // if we made it here, then it was a success.... - return YES; + + return result; } - (BOOL) keepBackupFile @@ -3972,6 +3474,170 @@ static NSImage *fileImage = nil; } } +/** + * All of the objects and corresponding names. + */ +- (NSMutableDictionary *) nameTable +{ + return nameTable; +} + +/** + * All of the connections... + */ +- (NSMutableArray *) connections +{ + return connections; +} + +/** + * All top level objects. + */ +- (NSMutableSet *) topLevelObjects +{ + return topLevelObjects; +} + +/** + * All windows marked, visible at launch. + */ +- (NSSet *) visibleWindows +{ + return visibleWindows; +} + +/** + * All windows marked, deferred. + */ +- (NSSet *) deferredWindows +{ + return deferredWindows; +} + +- (NSFileWrapper *) scmWrapper +{ + return scmWrapper; +} + +- (void) setSCMWrapper: (NSFileWrapper *)wrapper +{ + ASSIGN(scmWrapper, wrapper); +} + +/** + * Images + */ +- (NSArray *) images +{ + return [imagesView objects]; +} + +/** + * Sounds + */ +- (NSArray *) sounds +{ + return [soundsView objects]; +} + +/** + * Sounds + */ +- (void) setSounds: (NSArray *)snds +{ + ASSIGN(sounds,snds); +} + +/** + * Images + */ +- (void) setImages: (NSArray *)imgs +{ + ASSIGN(images,imgs); +} + +/** + * File's owner... + */ +- (GormFilesOwner *) filesOwner +{ + return filesOwner; +} + +/** + * Gorm file prefs manager. + */ +- (GormFilePrefsManager *) filePrefsManager +{ + return filePrefsManager; +} + +- (void) setDocumentOpen: (BOOL) flag +{ + isDocumentOpen = flag; +} + +- (BOOL) isDocumentOpen +{ + return isDocumentOpen; +} + +- (void) setInfoData: (NSData *)data +{ + ASSIGN(infoData, data); +} + +- (NSData *) infoData +{ + return infoData; +} + +- (void) setOlderArchive: (BOOL)flag +{ + isOlderArchive = flag; +} + +- (BOOL) isOlderArchive +{ + return isOlderArchive; +} + +- (void) encodeWithCoder: (NSCoder *)coder +{ + [coder encodeObject: nameTable]; + [coder encodeObject: visibleWindows]; + [coder encodeObject: connections]; +} + +- (id) initWithCoder: (NSCoder *)coder +{ + ASSIGN(nameTable, [coder decodeObject]); + ASSIGN(visibleWindows, [coder decodeObject]); + ASSIGN(connections, [coder decodeObject]); + + return self; +} + +- (void) awakeWithContext: (NSDictionary *)context +{ + NSEnumerator *en = [connections objectEnumerator]; + id o = nil; + while((o = [en nextObject]) != nil) + { + id src = [nameTable objectForKey: [o source]]; + id dst = [nameTable objectForKey: [o destination]]; + [o setSource: src]; + [o setDestination: dst]; + [o establishConnection]; + } + + en = [visibleWindows objectEnumerator]; + o = nil; + while((o = [en nextObject]) != nil) + { + [o orderFront: self]; + } +} @end @implementation GormDocument (MenuValidation) diff --git a/GormCore/GormDocumentController.m b/GormCore/GormDocumentController.m index 262c62b4..9824f31b 100644 --- a/GormCore/GormDocumentController.m +++ b/GormCore/GormDocumentController.m @@ -188,7 +188,6 @@ // set the filetype and touch the document. [doc setFileType: @"GSGormFileType"]; - [doc touch]; } @end diff --git a/GormCore/GormGormWrapperBuilder.m b/GormCore/GormGormWrapperBuilder.m new file mode 100644 index 00000000..9341f081 --- /dev/null +++ b/GormCore/GormGormWrapperBuilder.m @@ -0,0 +1,195 @@ +/* GormWrapperBuilder + * + * This class is a subclass of the NSDocumentController + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +@interface GSNibContainer (BuilderAdditions) +- (id) initWithDocument: (GormDocument *)document; +@end; + +@implementation GSNibContainer (BuilderAdditions) +- (id) initWithDocument: (GormDocument *)document +{ + if((self = [self init]) != nil) + { + NSMutableArray *visible = [nameTable objectForKey: @"NSVisible"]; + NSMutableArray *deferred = [nameTable objectForKey: @"NSDeferred"]; + + // Create the container for the .gorm file... + [nameTable addEntriesFromDictionary: [document nameTable]]; + [topLevelObjects addObjectsFromArray: [[document topLevelObjects] allObjects]]; + [visible addObjectsFromArray: [[document visibleWindows] allObjects]]; + [deferred addObjectsFromArray: [[document deferredWindows] allObjects]]; + } + return self; +} +@end + +@interface GormGormWrapperBuilder : GormWrapperBuilder +@end + +@implementation GormGormWrapperBuilder ++ (NSString *) type +{ + return @"GSGormFileType"; +} + +/** + * Private method which iterates through the list of custom classes and instructs + * the archiver to replace the actual object with template during the archiving + * process. + */ +- (void) _replaceObjectsWithTemplates: (NSArchiver *)archiver +{ + NSEnumerator *en = [[document nameTable] keyEnumerator]; + GormClassManager *classManager = [document classManager]; + GormFilePrefsManager *filePrefsManager = [document filePrefsManager]; + id key = nil; + + // loop through all custom objects and windows + while((key = [en nextObject]) != nil) + { + id customClass = [classManager customClassForName: key]; + id object = [document objectForName: key]; + id template = nil; + if(customClass != nil) + { + NSString *superClass = [classManager nonCustomSuperClassOf: customClass]; + template = [GSTemplateFactory templateForObject: object + withClassName: customClass + withSuperClassName: superClass]; + } + else if([object isKindOfClass: [NSWindow class]] + && [filePrefsManager versionOfClass: @"GSWindowTemplate"] > 0) + { + template = [GSTemplateFactory templateForObject: object + withClassName: [object className] + withSuperClassName: [object className]]; + + } + + // if the template has been created, replace the object with it. + if(template != nil) + { + // if the object is deferrable, then set the flag appropriately. + if([template respondsToSelector: @selector(setDeferFlag:)]) + { + [template setDeferFlag: [document objectIsDeferred: object]]; + } + + // if the object can accept autoposition information + if([object respondsToSelector: @selector(autoPositionMask)]) + { + int mask = [object autoPositionMask]; + if([template respondsToSelector: @selector(setAutoPositionMask:)]) + { + [template setAutoPositionMask: mask]; + } + } + + // replace the object with the template. + [archiver replaceObject: object withObject: template]; + } + } +} + +- (NSMutableDictionary *)buildFileWrapperDictionaryWithDocument: (GormDocument *)doc +{ + NSArchiver *archiver = nil; + NSMutableData *archiverData = nil; + NSString *gormPath = @"objects.gorm"; + NSString *classesPath = @"data.classes"; + NSString *infoPath = @"data.info"; + GormPalettesManager *palettesManager = [(id)NSApp palettesManager]; + NSDictionary *substituteClasses = [palettesManager substituteClasses]; + NSEnumerator *en = [substituteClasses keyEnumerator]; + NSString *subClassName = nil; + NSFileWrapper *fileWrapper = nil; + NSMutableDictionary *fileWrappers = [super buildFileWrapperDictionaryWithDocument: doc]; + + if(fileWrappers) + { + GormClassManager *classManager = [document classManager]; + GormFilePrefsManager *filePrefsManager = [document filePrefsManager]; + GSNibContainer *container = [[GSNibContainer alloc] initWithDocument: document]; + + /* + * Set up archiving... + */ + archiverData = [NSMutableData dataWithCapacity: 0]; + archiver = [[NSArchiver alloc] initForWritingWithMutableData: archiverData]; + + /* + * Special gorm classes to their archive equivalents. + */ + [archiver encodeClassName: @"GormObjectProxy" + intoClassName: @"GSNibItem"]; + [archiver encodeClassName: @"GormCustomView" + intoClassName: @"GSCustomView"]; + + + while((subClassName = [en nextObject]) != nil) + { + NSString *realClassName = [substituteClasses objectForKey: subClassName]; + [archiver encodeClassName: subClassName + intoClassName: realClassName]; + } + + /* + * Initialize templates + */ + [self _replaceObjectsWithTemplates: archiver]; + [archiver encodeRootObject: container]; + RELEASE(archiver); // We're done with the archiver here.. + + /* + * Add the gorm, info and classes files to the package. + */ + fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: archiverData]; + [fileWrappers setObject: fileWrapper forKey: gormPath]; + RELEASE(fileWrapper); + fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: [classManager data]]; + [fileWrappers setObject: fileWrapper forKey: classesPath]; + RELEASE(fileWrapper); + fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: [filePrefsManager data]]; + [fileWrappers setObject: fileWrapper forKey: infoPath]; + RELEASE(fileWrapper); + + // release the container... + RELEASE(container); + } + + return fileWrappers; +} +@end diff --git a/GormCore/GormGormWrapperLoader.m b/GormCore/GormGormWrapperLoader.m new file mode 100644 index 00000000..e2b3c414 --- /dev/null +++ b/GormCore/GormGormWrapperLoader.m @@ -0,0 +1,410 @@ +/* GormDocumentController.m + * + * This class is a subclass of the NSDocumentController + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +@interface GormGormWrapperLoader : GormWrapperLoader +@end + +@implementation GormGormWrapperLoader ++ (NSString *) type +{ + return @"GSGormFileType"; +} + +/** + * The sole purpose of this method is to clean up .gorm files from older + * versions of Gorm which might have some dangling references. This method + * may be added to as time goes on to make sure that it's possible + * to repair old .gorm files. + */ +- (void) _repairFile +{ + NSEnumerator *en = [[[document nameTable] allKeys] objectEnumerator]; + NSString *key = nil; + + NSRunAlertPanel(_(@"Warning"), + _(@"You are running with 'GormRepairFileOnLoad' set to YES."), + nil, nil, nil); + + while((key = [en nextObject]) != nil) + { + id obj = [[document nameTable] objectForKey: key]; + if([obj isKindOfClass: [NSMenu class]] && ![key isEqual: @"NSMenu"]) + { + id sm = [obj supermenu]; + if(sm == nil) + { + NSArray *menus = findAll(obj); + NSLog(@"Found and removed a dangling menu %@, %@.",obj,[document nameForObject: obj]); + [document detachObjects: menus]; + [document detachObject: obj]; + + // Since the menu is a top level object, it is not retained by + // anything else. When it was unarchived it was autoreleased, and + // the detach also does a release. Unfortunately, this causes a + // crash, so this extra retain is only here to stave off the + // release, so the autorelease can release the menu when it should. + RETAIN(obj); // extra retain to stave off autorelease... + } + } + + if([obj isKindOfClass: [NSMenuItem class]]) + { + id m = [obj menu]; + if(m == nil) + { + id sm = [obj submenu]; + + NSLog(@"Found and removed a dangling menu item %@, %@.",obj,[document nameForObject: obj]); + [document detachObject: obj]; + + // if there are any submenus, detach those as well. + if(sm != nil) + { + NSArray *menus = findAll(sm); + [document detachObjects: menus]; + } + } + } + + /** + * If it's a view and it does't have a window *AND* it's not a top level object + * then it's not a standalone view, it's an orphan. Delete it. + */ + if([obj isKindOfClass: [NSView class]]) + { + if([obj window] == nil && + [[document topLevelObjects] containsObject: obj] == NO && + [obj hasSuperviewKindOfClass: [NSTabView class]] == NO) + { + NSLog(@"Found and removed an orphan view %@, %@",obj,[document nameForObject: obj]); + [document detachObject: obj]; + } + } + } +} + +/** + * Private method. Determines if the document contains an instance of a given + * class or one of it's subclasses. + */ +- (BOOL) _containsKindOfClass: (Class)cls +{ + NSEnumerator *en = [[document nameTable] objectEnumerator]; + id obj = nil; + while((obj = [en nextObject]) != nil) + { + if([obj isKindOfClass: cls]) + { + return YES; + } + } + return NO; +} + +- (BOOL) loadFileWrapper: (NSFileWrapper *)wrapper withDocument: (GormDocument *) doc +{ + NS_DURING + { + NSMutableDictionary *cc = nil; + NSData *data = nil; + NSData *classes = nil; + NSUnarchiver *u = nil; + NSEnumerator *enumerator = nil; + id con = nil; + NSString *ownerClass, *key = nil; + BOOL repairFile = [[NSUserDefaults standardUserDefaults] boolForKey: @"GormRepairFileOnLoad"]; + GormPalettesManager *palettesManager = [(id)NSApp palettesManager]; + NSDictionary *substituteClasses = [palettesManager substituteClasses]; + NSEnumerator *en = [substituteClasses keyEnumerator]; + NSString *subClassName = nil; + unsigned int version = NSNotFound; + NSDictionary *fileWrappers = nil; + + if ([super loadFileWrapper: wrapper withDocument: doc]) + { + GormClassManager *classManager = [document classManager]; + NSArray *imageFileTypes = [NSImage imageFileTypes]; + NSArray *soundFileTypes = [NSSound soundUnfilteredFileTypes]; + NSMutableArray *images = [[NSMutableArray alloc] init]; + NSMutableArray *sounds = [[NSMutableArray alloc] init]; + + key = nil; + fileWrappers = [wrapper fileWrappers]; + + // [ saveSCMDirectory: fileWrappers]; + + enumerator = [fileWrappers keyEnumerator]; + while((key = [enumerator nextObject]) != nil) + { + NSFileWrapper *fw = [fileWrappers objectForKey: key]; + if([fw isRegularFile]) + { + NSData *fileData = [fw regularFileContents]; + if([key isEqual: @"objects.gorm"]) + { + data = fileData; + } + else if([key isEqual: @"data.info"]) + { + [document setInfoData: fileData]; + } + else if([key isEqual: @"data.classes"]) + { + classes = fileData; + + // load the custom classes... + if (![classManager loadCustomClassesWithData: classes]) + { + NSRunAlertPanel(_(@"Problem Loading"), + _(@"Could not open the associated classes file.\n" + @"You won't be able to edit connections on custom classes"), + _(@"OK"), nil, nil); + } + } + else if ([imageFileTypes containsObject: [key pathExtension]]) + { + [images addObject: [GormImage imageForData: fileData withFileName: key inWrapper: YES]]; + } + else if ([soundFileTypes containsObject: [key pathExtension]]) + { + [sounds addObject: [GormSound soundForData: fileData withFileName: key inWrapper: YES]]; + } + } + } + + // check the data... + if (data == nil || [document infoData] == nil || classes == nil) + { + return NO; + } + + /* + * Create an unarchiver, and use it to unarchive the gorm file while + * handling class replacement so that standard objects understood + * by the gui library are converted to their Gorm internal equivalents. + */ + u = [[NSUnarchiver alloc] initForReadingWithData: data]; + + /* + * Special internal classes + */ + [u decodeClassName: @"GSNibItem" + asClassName: @"GormObjectProxy"]; + [u decodeClassName: @"GSCustomView" + asClassName: @"GormCustomView"]; + + /* + * Substitute any classes specified by the palettes... + */ + while((subClassName = [en nextObject]) != nil) + { + NSString *realClassName = [substituteClasses objectForKey: subClassName]; + [u decodeClassName: realClassName + asClassName: subClassName]; + } + + // turn off custom classes. + [GSClassSwapper setIsInInterfaceBuilder: YES]; + GSNibContainer *container = [u decodeObject]; + if (container == nil || [container isKindOfClass: [GSNibContainer class]] == NO) + { + return NO; + } + // turn on custom classes. + [GSClassSwapper setIsInInterfaceBuilder: NO]; + + /* + * Retrieve the custom class data and refresh the classes view... + */ + NSMutableDictionary *nt = [container nameTable]; + + cc = [nt objectForKey: @"GSCustomClassMap"]; + if (cc == nil) + { + cc = [NSMutableDictionary dictionary]; // create an empty one. + [nt setObject: cc forKey: @"GSCustomClassMap"]; + } + [classManager setCustomClassMap: cc]; + [nt removeObjectForKey: @"GSCustomClassMap"]; + + // + // Get all of the visible objects... + // + NSArray *visible = [nt objectForKey: @"NSVisible"]; + id visObj = nil; + enumerator = [visible objectEnumerator]; + while((visObj = [enumerator nextObject]) != nil) + { + [document setObject: visObj isVisibleAtLaunch: YES]; + } + [nt removeObjectForKey: @"NSVisible"]; + + // + // Get all of the deferred objects... + // + NSArray *deferred = [nt objectForKey: @"NSDeferred"]; + id defObj = nil; + enumerator = [deferred objectEnumerator]; + while((defObj = [enumerator nextObject]) != nil) + { + [document setObject: defObj isDeferred: YES]; + } + [nt removeObjectForKey: @"NSDeferred"]; + + /* + * In the newly loaded nib container, we change all the connectors + * to hold the objects rather than their names (using our own dummy + * object as the 'NSOwner'. + */ + ownerClass = [nt objectForKey: @"NSOwner"]; + if (ownerClass) + { + [[document filesOwner] setClassName: ownerClass]; + } + [[container nameTable] removeObjectForKey: @"NSOwner"]; + [[container nameTable] removeObjectForKey: @"NSFirst"]; + + // + // Add entries... + // + [[document nameTable] addEntriesFromDictionary: nt]; + + // + // Add top level items... + // + NSArray *objs = [[container topLevelObjects] allObjects]; + [[document topLevelObjects] addObjectsFromArray: objs]; + + + /* Iterate over the contents of nameTable and create the connections */ + nt = [document nameTable]; + enumerator = [[container connections] objectEnumerator]; + while ((con = [enumerator nextObject]) != nil) + { + NSString *name; + id obj; + + name = (NSString*)[con source]; + obj = [nt objectForKey: name]; + [con setSource: obj]; + name = (NSString*)[con destination]; + obj = [nt objectForKey: name]; + [con setDestination: obj]; + } + + /* + * If the GSNibContainer version is 0, we need to add the top level objects + * to the list so that they can be properly processed. + */ + if([u versionForClassName: NSStringFromClass([GSNibContainer class])] == 0) + { + id obj; + NSEnumerator *en = [nt objectEnumerator]; + + // get all of the GSNibItem subclasses which could be top level objects + while((obj = [en nextObject]) != nil) + { + if([obj isKindOfClass: [GSNibItem class]] && + [obj isKindOfClass: [GSCustomView class]] == NO) + { + [[container topLevelObjects] addObject: obj]; + } + } + [document setOlderArchive: YES]; + } + + /* + * If the GSWindowTemplate version is 0, we need to let Gorm know that this is + * an older archive. Also, if the window template is not in the archive we know + * it was made by an older version of Gorm. + */ + version = [u versionForClassName: NSStringFromClass([GSWindowTemplate class])]; + if(version == NSNotFound && [self _containsKindOfClass: [NSWindow class]]) + { + [document setOlderArchive: YES]; + } + + /* + * repair the .gorm file, if needed. + */ + if(repairFile) + { + [self _repairFile]; + } + + /* + * Rebuild the mapping from object to name for the nameTable... + */ + [document rebuildObjToNameMapping]; + + NSDebugLog(@"nameTable = %@",[container nameTable]); + + // awaken all elements after the load is completed. + enumerator = [nt keyEnumerator]; + while ((key = [enumerator nextObject]) != nil) + { + id o = [nt objectForKey: key]; + if ([o respondsToSelector: @selector(awakeFromDocument:)]) + { + [o awakeFromDocument: document]; + } + } + + // document opened... + [document setDocumentOpen: YES]; + + // release the unarchiver.. + RELEASE(u); + } + else + { + return NO; + } + } + NS_HANDLER + { + NSRunAlertPanel(_(@"Problem Loading"), + [NSString stringWithFormat: @"Failed to load file. Exception: %@",[localException reason]], + _(@"OK"), nil, nil); + return NO; + } + NS_ENDHANDLER; + + // if we made it here, then it was a success.... + return YES; +} +@end diff --git a/GormCore/GormPrivate.h b/GormCore/GormPrivate.h index 8859c588..b60897fc 100644 --- a/GormCore/GormPrivate.h +++ b/GormCore/GormPrivate.h @@ -51,7 +51,8 @@ extern NSString *GormResizeCellNotification; // templates @interface GSNibItem (GormAdditions) -- initWithClassName: (NSString*)className frame: (NSRect)frame; +- (id) initWithClassName: (NSString*)className; +- (id) initWithClassName: (NSString*)className frame: (NSRect)frame; - (NSString*) className; @end diff --git a/GormCore/GormPrivate.m b/GormCore/GormPrivate.m index 1801dd29..031a292c 100644 --- a/GormCore/GormPrivate.m +++ b/GormCore/GormPrivate.m @@ -49,15 +49,23 @@ static BOOL _isInInterfaceBuilder = NO; #include "GormViewWithContentViewEditor.h" @implementation GSNibItem (GormAdditions) -- initWithClassName: (NSString*)className frame: (NSRect)frame +- (id) initWithClassName: (NSString*)className frame: (NSRect)frame { - self = [super init]; - - theClass = [className copy]; - theFrame = frame; - + if((self = [super init]) != nil) + { + theClass = [className copy]; + theFrame = frame; + } return self; } + +- (id) initWithClassName: (NSString*)className +{ + return [self initWithClassName: className + frame: NSMakeRect(0,0,0,0)]; +} + + - (NSString*) className { return theClass; @@ -109,42 +117,50 @@ static BOOL _isInInterfaceBuilder = NO; */ - (id) initWithCoder: (NSCoder*)aCoder { - int version = [aCoder versionForClassName: - NSStringFromClass([GSNibItem class])]; - - if (version == NSNotFound) + if([aCoder allowsKeyedCoding]) { - NSLog(@"no GSNibItem"); - version = [aCoder versionForClassName: - NSStringFromClass([GormObjectProxy class])]; - } - if (version == 0) - { - // do not decode super (it would try to morph into theClass ! ) - [aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; - theFrame = [aCoder decodeRect]; - RETAIN(theClass); // release in dealloc of GSNibItem... - - return self; - } - else if (version == 1) - { - // do not decode super (it would try to morph into theClass ! ) - [aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; - theFrame = [aCoder decodeRect]; - [aCoder decodeValueOfObjCType: @encode(unsigned int) - at: &autoresizingMask]; - RETAIN(theClass); // release in dealloc of GSNibItem... - - return self; } else { - NSLog(@"no initWithCoder for version %d", version); - RELEASE(self); - return nil; + int version = [aCoder versionForClassName: + NSStringFromClass([GSNibItem class])]; + + if (version == NSNotFound) + { + NSLog(@"no GSNibItem"); + version = [aCoder versionForClassName: + NSStringFromClass([GormObjectProxy class])]; + } + + if (version == 0) + { + // do not decode super (it would try to morph into theClass ! ) + [aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; + theFrame = [aCoder decodeRect]; + RETAIN(theClass); // release in dealloc of GSNibItem... + + return self; + } + else if (version == 1) + { + // do not decode super (it would try to morph into theClass ! ) + [aCoder decodeValueOfObjCType: @encode(id) at: &theClass]; + theFrame = [aCoder decodeRect]; + [aCoder decodeValueOfObjCType: @encode(unsigned int) + at: &autoresizingMask]; + RETAIN(theClass); // release in dealloc of GSNibItem... + + return self; + } + else + { + NSLog(@"no initWithCoder for version %d", version); + RELEASE(self); + return nil; + } } + return nil; } - (NSString*) inspectorClassName diff --git a/GormCore/GormWrapperBuilder.h b/GormCore/GormWrapperBuilder.h new file mode 100644 index 00000000..3637f248 --- /dev/null +++ b/GormCore/GormWrapperBuilder.h @@ -0,0 +1,51 @@ +/* GormWrapperBuilder + * + * This class is a subclass of the NSDocumentController + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#ifndef INCLUDED_GormWrapperBuilder_h +#define INCLUDED_GormWrapperBuilder_h + +#include + +@class NSFileWrapper, GormDocument, NSString, NSMutableDictionary; + +@protocol GormWrapperBuilder +- (NSMutableDictionary *) buildFileWrapperDictionaryWithDocument: (GormDocument *)document; +- (NSFileWrapper *) buildFileWrapperWithDocument: (GormDocument *)document; +@end + +@interface GormWrapperBuilder : NSObject +{ + GormDocument *document; +} +@end + +@interface GormWrapperBuilderFactory : NSObject ++ (GormWrapperBuilderFactory *) sharedWrapperBuilderFactory; ++ (void) registerWrapperBuilderClass: (Class) aClass; +- (id) wrapperBuilderForType: (NSString *) type; +@end + +#endif diff --git a/GormCore/GormWrapperBuilder.m b/GormCore/GormWrapperBuilder.m new file mode 100644 index 00000000..26f69a97 --- /dev/null +++ b/GormCore/GormWrapperBuilder.m @@ -0,0 +1,165 @@ +/* GormWrapperBuilder + * + * These classes handle loading different formats into the + * document's data structures. + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static NSMutableDictionary *_wrapperBuilderMap = nil; +static GormWrapperBuilderFactory *_sharedWrapperBuilderFactory = nil; + +@implementation GormWrapperBuilder ++ (NSString *) type +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (NSFileWrapper *) buildFileWrapperWithDocument: (GormDocument *)doc +{ + return [[NSFileWrapper alloc] initDirectoryWithFileWrappers: + [self buildFileWrapperDictionaryWithDocument: doc]]; +} + +- (NSMutableDictionary *) buildFileWrapperDictionaryWithDocument: (GormDocument *)doc +{ + NSMutableDictionary *fileWrappers = [NSMutableDictionary dictionary]; + NSFileWrapper *scmDirWrapper = nil; + + // Assign document and don't retain... + document = doc; + + // + // Add the SCM wrapper to the wrapper, if it's present. + // + scmDirWrapper = [document scmWrapper]; + if(scmDirWrapper != nil) + { + NSString *name = [[scmDirWrapper filename] lastPathComponent]; + [fileWrappers setObject: scmDirWrapper forKey: name]; + } + + // + // Copy resources into the new folder... + // Gorm doesn't copy these into the folder right away since the folder may + // not yet exist. This allows the user to add/delete resources as they see fit + // but only those which they end up with will actually be put into the wrapper + // when the model/document is saved. + // + NSArray *resources = [[document sounds] arrayByAddingObjectsFromArray: + [document images]]; + id object = nil; + NSEnumerator *en = [resources objectEnumerator]; + while ((object = [en nextObject]) != nil) + { + if([object isSystemResource] == NO) + { + NSString *path = [object path]; + NSString *resName = nil; + NSData *resData = nil; + NSFileWrapper *fileWrapper = nil; + + if([object isInWrapper]) + { + resName = [object filename]; + resData = [object data]; + } + else + { + resName = [path lastPathComponent]; + resData = [NSData dataWithContentsOfFile: path]; + [object setData: resData]; + [object setInWrapper: YES]; + } + + fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: resData]; + [fileWrappers setObject: fileWrapper forKey: resName]; + RELEASE(fileWrapper); + } + } + + return fileWrappers; +} +@end + +@implementation GormWrapperBuilderFactory ++ (void) initialize +{ + NSArray *classes = GSObjCAllSubclassesOfClass([GormWrapperBuilder class]); + NSEnumerator *en = [classes objectEnumerator]; + Class cls = nil; + + while((cls = [en nextObject]) != nil) + { + [self registerWrapperBuilderClass: cls]; + } +} + ++ (void) registerWrapperBuilderClass: (Class)aClass +{ + if(_wrapperBuilderMap == nil) + { + _wrapperBuilderMap = [[NSMutableDictionary alloc] initWithCapacity: 5]; + } + + [_wrapperBuilderMap setObject: aClass forKey: (NSString *)[aClass type]]; +} + ++ (GormWrapperBuilderFactory *) sharedWrapperBuilderFactory +{ + if(_sharedWrapperBuilderFactory == nil) + { + _sharedWrapperBuilderFactory = [[self alloc] init]; + } + return _sharedWrapperBuilderFactory; +} + +- (id) init +{ + if((self = [super init]) != nil) + { + if(_sharedWrapperBuilderFactory == nil) + { + _sharedWrapperBuilderFactory = self; + } + } + return self; +} + +- (id) wrapperBuilderForType: (NSString *) type +{ + Class cls = [_wrapperBuilderMap objectForKey: type]; + id obj = AUTORELEASE([[cls alloc] init]); + return obj; +} +@end + diff --git a/GormCore/GormWrapperLoader.h b/GormCore/GormWrapperLoader.h new file mode 100644 index 00000000..10ee9dad --- /dev/null +++ b/GormCore/GormWrapperLoader.h @@ -0,0 +1,51 @@ +/* GormWrapperLoader + * + * This class is a subclass of the NSDocumentController + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#ifndef INCLUDED_GormWrapperLoader_h +#define INCLUDED_GormWrapperLoader_h + +#include + +@class NSFileWrapper, GormDocument, NSString; + +@protocol GormWrapperLoader +- (BOOL) loadFileWrapper: (NSFileWrapper *)wrapper withDocument: (GormDocument *)document; +@end + +@interface GormWrapperLoader : NSObject +{ + GormDocument *document; +} +- (void) saveSCMDirectory: (NSDictionary *) fileWrappers; +@end + +@interface GormWrapperLoaderFactory : NSObject ++ (GormWrapperLoaderFactory *) sharedWrapperLoaderFactory; ++ (void) registerWrapperLoaderClass: (Class) aClass; +- (id) wrapperLoaderForType: (NSString *) type; +@end + +#endif diff --git a/GormCore/GormWrapperLoader.m b/GormCore/GormWrapperLoader.m new file mode 100644 index 00000000..8bdb4f8b --- /dev/null +++ b/GormCore/GormWrapperLoader.m @@ -0,0 +1,157 @@ +/* GormWrapperLoader + * + * These classes handle loading different formats into the + * document's data structures. + * + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * Author: Gregory John Casamento + * Date: 2006 + * + * This file is part of GNUstep. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static NSMutableDictionary *_wrapperLoaderMap = nil; +static GormWrapperLoaderFactory *_sharedWrapperLoaderFactory = nil; + +@implementation GormWrapperLoader ++ (NSString *) type +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void) saveSCMDirectory: (NSDictionary *) fileWrappers +{ + [document setSCMWrapper: [fileWrappers objectForKey: @".svn"]]; + if([document scmWrapper] == nil) + { + [document setSCMWrapper: [fileWrappers objectForKey: @"CVS"]]; + } +} + +- (BOOL) loadFileWrapper: (NSFileWrapper *)wrapper withDocument: (GormDocument *)doc +{ + if ([wrapper isDirectory]) + { + NSDictionary *fileWrappers = nil; + NSString *key = nil; + NSArray *imageFileTypes = [NSImage imageFileTypes]; + NSArray *soundFileTypes = [NSSound soundUnfilteredFileTypes]; + NSMutableArray *images = [NSMutableArray array]; + NSMutableArray *sounds = [NSMutableArray array]; + NSData *fileData = nil; + + document = doc; // don't retain... + key = nil; + fileWrappers = [wrapper fileWrappers]; + + [self saveSCMDirectory: fileWrappers]; + + NSEnumerator *enumerator = [fileWrappers keyEnumerator]; + while((key = [enumerator nextObject]) != nil) + { + NSFileWrapper *fw = [fileWrappers objectForKey: key]; + if([fw isRegularFile]) + { + if ([imageFileTypes containsObject: [key pathExtension]]) + { + [images addObject: [GormImage imageForData: fileData + withFileName: key + inWrapper: YES]]; + } + else if ([soundFileTypes containsObject: [key pathExtension]]) + { + [sounds addObject: [GormSound soundForData: fileData + withFileName: key + inWrapper: YES]]; + } + } + } + + [document setSounds: sounds]; + [document setImages: images]; + } + else + { + return NO; + } + + return YES; +} +@end + +@implementation GormWrapperLoaderFactory ++ (void) initialize +{ + NSArray *classes = GSObjCAllSubclassesOfClass([GormWrapperLoader class]); + NSEnumerator *en = [classes objectEnumerator]; + Class cls = nil; + + while((cls = [en nextObject]) != nil) + { + [self registerWrapperLoaderClass: cls]; + } +} + ++ (void) registerWrapperLoaderClass: (Class)aClass +{ + if(_wrapperLoaderMap == nil) + { + _wrapperLoaderMap = [[NSMutableDictionary alloc] initWithCapacity: 5]; + } + + [_wrapperLoaderMap setObject: aClass forKey: (NSString *)[aClass type]]; +} + ++ (GormWrapperLoaderFactory *) sharedWrapperLoaderFactory +{ + if(_sharedWrapperLoaderFactory == nil) + { + _sharedWrapperLoaderFactory = [[self alloc] init]; + } + return _sharedWrapperLoaderFactory; +} + +- (id) init +{ + if((self = [super init]) != nil) + { + if(_sharedWrapperLoaderFactory == nil) + { + _sharedWrapperLoaderFactory = self; + } + } + return self; +} + +- (id) wrapperLoaderForType: (NSString *) type +{ + Class cls = [_wrapperLoaderMap objectForKey: type]; + id obj = AUTORELEASE([[cls alloc] init]); + return obj; +} +@end +