commit b24b1706c8af49941082593eda671e6240952a62 Author: Richard Frith-MacDonald Date: Wed Dec 8 15:04:57 1999 +0000 Gorm source git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@5409 72102866-910b-0410-8b05-ffd578937521 diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..f757639b --- /dev/null +++ b/ChangeLog @@ -0,0 +1,6 @@ +Sat Nov 27 05:25:15 1999 Nicola Pero + + * KeyboardInput-test/KeyboardInput-test.m ([inputTestView + -drawRect:]): Fixed bug. + * KeyboardInput-test/KeyboardInput-test.m ([KeyboardInputTest + -init]): Moved typing view to top. diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 00000000..14cbf82a --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,82 @@ +# GNUmakefile: main makefile for GNUstep Object Relationship Modeller +# +# Copyright (C) 1999 Free Software Foundation, Inc. +# +# Author: Richard Frith-Macdonald +# Date: 1999 +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA +# + +include $(GNUSTEP_MAKEFILES)/common.make + +# +# Each palette is a subproject +# +SUBPROJECTS = \ + Menu \ + Text \ + View \ + Window + +# +# MAIN APP +# +APP_NAME = Gorm +Gorm_APPLICATION_ICON=Gorm.tiff +Gorm_RESOURCE_FILES = \ + Menu/Menu.palette \ + Text/Text.palette \ + View/View.palette \ + Window/Window.palette \ + Images/GormClass.tiff \ + Images/GormFilesOwner.tiff \ + Images/GormFirstResponder.tiff \ + Images/GormFontManager.tiff \ + Images/GormImage.tiff \ + Images/GormWindow.tiff \ + Images/GormMenu.tiff \ + Images/GormObject.tiff \ + Images/GormSound.tiff \ + Images/Gorm.tiff \ + Images/GormLinkImage.tiff + +Gorm_HEADERS = \ + Gorm.h \ + GormPrivate.h + +Gorm_OBJC_FILES = \ + Gorm.m \ + GormDocument.m \ + GormEditors.m \ + IBInspector.m \ + IBPalette.m \ + InfoPanel.m \ + GormInspectorsManager.m \ + GormPalettesManager.m \ + GormResourcesManager.m + +-include GNUmakefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/aggregate.make +include $(GNUSTEP_MAKEFILES)/application.make +include $(GNUSTEP_MAKEFILES)/bundle.make + +-include GNUmakefile.postamble + diff --git a/Gorm.h b/Gorm.h new file mode 100644 index 00000000..89971fc6 --- /dev/null +++ b/Gorm.h @@ -0,0 +1,205 @@ +#ifndef GORM_H +#define GORM_H + +#include +#include +#include +#include + +/* + * Positions of handles for resizing items. + */ +enum IBKnowPosition { + IBBottomLeftKnobPosition, + IBMiddleLeftKnobPosition, + IBTopLeftKnobPosition, + IBTopMiddleKnobPosition, + IBTopRightKnobPosition, + IBMiddleRightKnobPosition, + IBBottomRightKnobPosition, + IBBottomMiddleKnobPosition +}; + +/* + * Pasteboard types used for DnD when views are dragged out of a palette + * window into another window in Gorm (or, in the case of IBWindowPboardType + * onto the desktop). + */ +extern NSString *IBCellPboardType; +extern NSString *IBMenuPboardType; +extern NSString *IBMenuCellPboardType; +extern NSString *IBObjectPboardType; +extern NSString *IBViewPboardType; +extern NSString *IBWindowPboardType; + +/* + * Notification for editing and inspecting the objects etc. + */ +extern NSString *IBAttributesChangedNotification; +extern NSString *IBInspectorDidModifyObjectNotification; +extern NSString *IBSelectionChangedNotification; +extern NSString *IBWillBeginTestingInterfaceNotification; +extern NSString *IBDidBeginTestingInterfaceNotification; +extern NSString *IBWillEndTestingInterfaceNotification; +extern NSString *IBDidEndTestingInterfaceNotification; + + + + + +/* + * Connector objects are used to record connections between nib objects. + */ +@protocol IBConnectors +- (id) destination; +- (void) establishConnection; +- (NSString*) label; +- (void) replaceObject: (id)anObject withObject: (id)anotherObject; +- (id) source; +- (void) setDestination: (id)anObject; +- (void) setLabel: (NSString*)label; +- (void) setSource: (id)anObject; +@end + +@protocol IBDocuments +- (void) addConnector: (id)aConnector; +- (NSArray*) allConnectors; +- (void) attachObject: (id)anObject toParent: (id)aParent; +- (void) attachObjects: (NSArray*)anArray toParent: (id)aParent; +- (NSArray*) connectorsForDestination: (id)destination; +- (NSArray*) connectorsForDestination: (id)destination + ofClass: (Class)aConnectorClass; +- (NSArray*) connectorsForSource: (id)source; +- (NSArray*) connectorsForSource: (id)source + ofClass: (Class)aConnectorClass; +- (BOOL) containsObject: (id)anObject; +- (BOOL) containsObjectWithName: (NSString*)aName forParent: (id)parent; +- (BOOL) copyObject: (id)anObject + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard; +- (BOOL) copyObjects: (NSArray*)anArray + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard; +- (void) detachObject: (id)anObject; +- (void) detachObjects: (NSArray*)anArray; +- (NSString*) documentPath; +- (BOOL) documentShouldClose; +- (void) documentWillClose; +- (NSString*) nameForObject: (id)anObject; +- (NSArray*) objects; +- (id) parentOfObject: (id)anObject; +- (NSArray*) pasteType: (NSString*)aType + fromPasteboard: (NSPasteboard*)aPasteboard + parent: (id)parent; +- (void) removeConnector: (id)aConnector; +- (void) setName: (NSString*)aName forObject: (id)object; +- (void) touch; /* Mark document as having been changed. */ +@end + +@protocol IBSelectionOwners +- (unsigned) selectionCount; +- (NSArray*) selection; +- (void) drawSelection; +@end + +@protocol IB +- (id) activeDocument; +- (BOOL) isTestingInterface; +- (id) selectionOwner; +- (id) selectedObject; +@end + +@interface IBPalette : NSObject +{ + NSWindow *window; + NSImage *icon; +} +/* + * For internal use only - these class methods return the information + * associated with a particular view. + */ ++ (id) objectForView: (NSView*)aView; ++ (NSString*) typeForView: (NSView*)aView; + +/* + * Associate a particular object and DnD type with a view - so that + * Gorm knows to initiate a DnD session with the specified object + * and type rather than an archived copy of the view itsself and + * the default type (IBViewPboardType). + */ +- (void) associateObject: (id)anObject + type: (NSString*)aType + with: (NSView*)aView; + +/* + * Method called by Gorm when a new palette has been created and its nib + * (if any) has been loaded. Any palette initialisation should be done here. + */ +- (void) finishInstantiate; + +/* + * Return the icon representing the palette. + */ +- (NSImage*) paletteIcon; + +/* + * Return the window containing the views that may be dragged from the + * palette. + */ +- (NSWindow*) originalWindow; +@end + +/* + * How to get the inspector for a particular object. + */ +@interface NSObject (IBInspectorClassNames) +- (NSString*) inspectorClassName; +- (NSString*) connectInspectorClassName; +- (NSString*) sizeInspectorClassName; +- (NSString*) helpInspectorClassName; +- (NSString*) classInspectorClassName; +@end + +@interface IBInspector : NSObject +{ + id object; + NSWindow *window; + NSButton *okButton; + NSButton *revertButton; +} +- (id) object; +- (void) ok: (id)sender; +- (NSButton*) okButton; +- (void) revert: (id)sender; +- (NSButton*) revertButton; +- (void) touch: (id)sender; +- (BOOL) wantsButtons; +- (NSWindow*) window; +@end + +@interface NSObject (IBEditorSpecification) +- (NSString*) editorClassName; +@end + +@protocol IBEditors +- (BOOL) acceptsTypeFromArray: (NSArray*)types; +- (BOOL) activate; +- (id) initWithObject: (id)anObject inDocument: (id)aDocument; +- (void) close; +- (void) closeSubeditors; +- (void) copySelection; +- (void) deleteSelection; +- (id) document; +- (id) editedObject; +- (void) makeSelectionVisible: (BOOL)flag; +- (id) openSubeditorForObject: (id)anObject; +- (void) orderFront; +- (void) pasteInSelection; +- (void) resetObject: (id)anObject; +- (void) selectObjects: (NSArray*)objects; +- (void) validateEditing; +- (BOOL) wantsSelection; +- (NSWindow*) window; +@end + +#endif diff --git a/Gorm.m b/Gorm.m new file mode 100644 index 00000000..ce6841c0 --- /dev/null +++ b/Gorm.m @@ -0,0 +1,324 @@ +/* Gorm.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + +@class InfoPanel; + +@implementation Gorm + +- (id) activeDocument +{ + return (id)[documents lastObject]; +} + +- (BOOL) applicationShouldTerminate: (NSApplication*)sender +{ + NSEnumerator *enumerator = [documents objectEnumerator]; + GormDocument *doc; + BOOL edited = NO; + + while ((doc = [enumerator nextObject]) != nil) + { + if ([[[doc resourcesManager] window] isDocumentEdited] == YES) + { + edited = YES; + } + } + if (edited == YES) + { + int result; + + result = NSRunAlertPanel(NULL, @"There are edited windows", + @"Review Unsaved", @"Cancel", @"Quit Anyway"); + if (result == NSAlertAlternateReturn) + { + return NO; + } + else if (result != NSAlertOtherReturn) + { + enumerator = [documents objectEnumerator]; + while ((doc = [enumerator nextObject]) != nil) + { + NSWindow *win = [[doc resourcesManager] window]; + + if ([win isDocumentEdited] == YES) + { + [win performClose: self]; + } + } + } + } + return YES; +} + +- (void) dealloc +{ + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + [nc removeObserver: self]; + RELEASE(infoPanel); + RELEASE(inspectorsManager); + RELEASE(palettesManager); + RELEASE(documents); + [super dealloc]; +} + +- (id) init +{ + self = [super init]; + if (self != nil) + { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + documents = [NSMutableArray new]; + [nc addObserver: self + selector: @selector(selectionChanged:) + name: IBSelectionChangedNotification + object: nil]; + } + return self; +} + +- (GormInspectorsManager*) inspectorsManager +{ + if (inspectorsManager == nil) + { + inspectorsManager = [GormInspectorsManager new]; + } + return inspectorsManager; +} + +- (id) makeNewDocument: (id) sender +{ + id doc = [GormDocument new]; + + [documents addObject: doc]; + [doc setDocumentActive: YES]; + RELEASE(doc); + return doc; +} + +- (id) openDocument: (id) sender +{ + GormDocument *doc = [GormDocument new]; + + [documents addObject: doc]; + RELEASE(doc); + if ([doc openDocument: sender] == nil) + { + [documents removeObjectIdenticalTo: doc]; + doc = nil; + } + else + { + [doc setDocumentActive: YES]; + } + return doc; +} + +- (id) openPalette: (id) sender +{ + return [[self palettesManager] openPalette: sender]; +} + +- (GormPalettesManager*) palettesManager +{ + if (palettesManager == nil) + { + palettesManager = [GormPalettesManager new]; + } + return palettesManager; +} + +- (id) runInfoPanel: (id) sender +{ + if (infoPanel == nil) + { + infoPanel = [InfoPanel new]; + } + [infoPanel orderFront: nil]; + return self; +} + +- (id) runGormInspectors: (id) sender +{ + [[[self inspectorsManager] panel] orderFront: nil]; + return self; +} + +- (id) runGormPalettes: (id) sender +{ + [[[self palettesManager] panel] orderFront: self]; + return self; +} + +- (id) saveAsDocument: (id)sender +{ + return [[documents lastObject] saveAsDocument: sender]; +} + +- (id) saveDocument: (id)sender +{ + return [[documents lastObject] saveDocument: sender]; +} + +- (void) selectionChanged: (NSNotification*)notification +{ + selectionOwner = [notification object]; +} + +- (id) selectionOwner +{ + return selectionOwner; +} + +- (id) selectedObject +{ + return [[selectionOwner selection] lastObject]; +} +@end + +int +main(void) +{ + NSAutoreleasePool *pool; + NSMenu *aMenu; + NSMenu *mainMenu; + NSMenu *windowsMenu; + NSMenuItem *menuItem; + + pool = [NSAutoreleasePool new]; + initialize_gnustep_backend (); + + /* + * Install an instance of Gorm as the application so that the app + * can conform to the IB protocol + */ + NSApp = [Gorm new]; + + mainMenu = [[NSMenu alloc] initWithTitle: @"Gorm"]; + + /* + * Set up info menu. + */ + aMenu = [NSMenu new]; + [aMenu addItemWithTitle: @"Info Panel..." + action: @selector(runInfoPanel:) + keyEquivalent: @""]; + [aMenu addItemWithTitle: @"Help..." + action: NULL + keyEquivalent: @"?"]; + menuItem = [mainMenu addItemWithTitle: @"Info" + action: NULL + keyEquivalent: @""]; + [mainMenu setSubmenu: aMenu forItem: menuItem]; + RELEASE(aMenu); + + /* + * Set up document menu. + */ + aMenu = [NSMenu new]; + [aMenu addItemWithTitle: @"Open..." + action: @selector(openDocument:) + keyEquivalent: @"o"]; + [aMenu addItemWithTitle: @"New Application" + action: @selector(makeNewDocument:) + keyEquivalent: @"n"]; + [aMenu addItemWithTitle: @"Save" + action: @selector(saveDocument:) + keyEquivalent: @"s"]; + [aMenu addItemWithTitle: @"Save As..." + action: @selector(saveAsDocument:) + keyEquivalent: @"S"]; + menuItem = [mainMenu addItemWithTitle: @"Document" + action: NULL + keyEquivalent: @""]; + [mainMenu setSubmenu: aMenu forItem: menuItem]; + RELEASE(aMenu); + + /* + * Set up tools menu. + */ + aMenu = [NSMenu new]; + [aMenu addItemWithTitle: @"Inspector..." + action: @selector(runGormInspectors:) + keyEquivalent: @""]; + [aMenu addItemWithTitle: @"Palettes..." + action: @selector(runGormPalettes:) + keyEquivalent: @""]; + [aMenu addItemWithTitle: @"Load Palette..." + action: @selector(openPalette:) + keyEquivalent: @""]; + menuItem = [mainMenu addItemWithTitle: @"Tools" + action: NULL + keyEquivalent: @""]; + [mainMenu setSubmenu: aMenu forItem: menuItem]; + RELEASE(aMenu); + + /* + * Set up Windows menu + */ + windowsMenu = [NSMenu new]; + [windowsMenu addItemWithTitle: @"Arrange" + action: @selector(arrangeInFront:) + keyEquivalent: @""]; + [windowsMenu addItemWithTitle: @"Miniaturize" + action: @selector(performMiniaturize:) + keyEquivalent: @"m"]; + [windowsMenu addItemWithTitle: @"Close" + action: @selector(performClose:) + keyEquivalent: @"w"]; + menuItem = [mainMenu addItemWithTitle: @"Windows" + action: NULL + keyEquivalent: @""]; + [mainMenu setSubmenu: windowsMenu forItem: menuItem]; + RELEASE(windowsMenu); + + [mainMenu addItemWithTitle: @"Quit" + action: @selector(terminate:) + keyEquivalent: @"q"]; + + + [NSApp setMainMenu: mainMenu]; + [NSApp setWindowsMenu: windowsMenu]; + [mainMenu display]; + +{ + extern BOOL NSImageDoesCaching; + extern BOOL NSImageForceCaching; + + NSImageDoesCaching = YES; +//[NSObject enableDoubleReleaseCheck: YES]; +} + + /* + * Set Gorm up as its own delegate + */ + [NSApp setDelegate: NSApp]; + [NSApp run]; + [pool release]; + return 0; +} + diff --git a/GormDocument.h b/GormDocument.h new file mode 100644 index 00000000..df4bdc55 --- /dev/null +++ b/GormDocument.h @@ -0,0 +1,51 @@ +#ifndef GORMDOCUMENT_H +#define GORMDOCUMENT_H + +@interface GormDocument : GSNibContainer +{ + GormResourcesManager *resourcesManager; + NSString *documentPath; + NSMapTable *objToName; + id owner; /* Dummy object */ +} +- (void) addConnector: (id)aConnector; +- (NSArray*) allConnectors; +- (void) attachObject: (id)anObject toParent: (id)aParent; +- (void) attachObjects: (NSArray*)anArray toParent: (id)aParent; +- (NSArray*) connectorsForDestination: (id)destination; +- (NSArray*) connectorsForDestination: (id)destination + ofClass: (Class)aConnectorClass; +- (NSArray*) connectorsForSource: (id)source; +- (NSArray*) connectorsForSource: (id)source + ofClass: (Class)aConnectorClass; +- (BOOL) containsObject: (id)anObject; +- (BOOL) containsObjectWithName: (NSString*)aName forParent: (id)parent; +- (BOOL) copyObject: (id)anObject + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard; +- (BOOL) copyObjects: (NSArray*)anArray + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard; +- (void) detachObject: (id)anObject; +- (void) detachObjects: (NSArray*)anArray; +- (NSString*) documentPath; +- (BOOL) documentShouldClose; +- (void) documentWillClose; +- (NSString*) nameForObject: (id)anObject; +- (id) objectForName: (NSString*)aString; +- (NSArray*) objects; +- (id) openDocument: (id)sender; +- (id) parentOfObject: (id)anObject; +- (NSArray*) pasteType: (NSString*)aType + fromPasteboard: (NSPasteboard*)aPasteboard + parent: (id)parent; +- (GormResourcesManager*) resourcesManager; +- (void) removeConnector: (id)aConnector; +- (id) saveAsDocument: (id)sender; +- (id) saveDocument: (id)sender; +- (void) setDocumentActive: (BOOL)flag; +- (void) setName: (NSString*)aName forObject: (id)object; +- (void) touch; /* Mark document as having been changed. */ +@end + +#endif diff --git a/GormDocument.m b/GormDocument.m new file mode 100644 index 00000000..8abb0ac1 --- /dev/null +++ b/GormDocument.m @@ -0,0 +1,722 @@ +/* GormDocument.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + +/* + * A private connector for child->parent relationships. + */ +@interface GormConnector : NSNibConnector +@end + +@implementation GormConnector +@end + + +@implementation GormDocument + +- (void) addConnector: (id)aConnector +{ + if ([connections indexOfObjectIdenticalTo: aConnector] == NSNotFound) + { + [connections addObject: aConnector]; + } +} + +- (NSArray*) allConnectors +{ + return AUTORELEASE([connections copy]); +} + +- (void) attachObject: (id)anObject toParent: (id)aParent +{ + NSArray *old; + + /* + * Create a connector that links this object to its parent. + * A nil parent is the root of the hierarchy so we use a dummy object for it. + */ + if (aParent == nil) + { + aParent = owner; + } + old = [self connectorsForSource: anObject ofClass: [GormConnector class]]; + if ([old count] > 0) + { + [[old objectAtIndex: 0] setDestination: aParent]; + } + else + { + GormConnector *con = [GormConnector new]; + + [con setSource: anObject]; + [con setDestination: aParent]; + [self addConnector: (id)con]; + RELEASE(con); + } + [self setName: nil forObject: anObject]; + + if ([anObject isKindOfClass: [NSWindow class]] == YES) + { + [resourcesManager addObject: anObject]; + } + else if ([anObject isKindOfClass: [NSMenu class]] == YES) + { + [resourcesManager addObject: anObject]; + } +} + +- (void) attachObjects: (NSArray*)anArray toParent: (id)aParent +{ + NSEnumerator *enumerator = [anArray objectEnumerator]; + NSObject *obj; + + while ((obj = [enumerator nextObject]) != nil) + { + [self attachObject: obj toParent: aParent]; + } +} + +- (NSArray*) connectorsForDestination: (id)destination +{ + return [self connectorsForDestination: destination ofClass: 0]; +} + +- (NSArray*) connectorsForDestination: (id)destination + ofClass: (Class)aConnectorClass +{ + NSMutableArray *array = [NSMutableArray arrayWithCapacity: 16]; + NSEnumerator *enumerator = [connections objectEnumerator]; + id c; + + while ((c = [enumerator nextObject]) != nil) + { + if ([c destination] == destination + && (aConnectorClass == 0 || aConnectorClass == [c class])) + { + [array addObject: c]; + } + } + return array; +} + +- (NSArray*) connectorsForSource: (id)source +{ + return [self connectorsForSource: source ofClass: 0]; +} + +- (NSArray*) connectorsForSource: (id)source + ofClass: (Class)aConnectorClass +{ + NSMutableArray *array = [NSMutableArray arrayWithCapacity: 16]; + NSEnumerator *enumerator = [connections objectEnumerator]; + id c; + + while ((c = [enumerator nextObject]) != nil) + { + if ([c source] == source + && (aConnectorClass == 0 || aConnectorClass == [c class])) + { + [array addObject: c]; + } + } + return array; +} + +- (BOOL) containsObject: (id)anObject +{ + if ([self nameForObject: anObject] == nil) + { + return NO; + } + return YES; +} + +- (BOOL) containsObjectWithName: (NSString*)aName forParent: (id)parent +{ + id obj = [nameTable objectForKey: aName]; + + if (obj == nil) + { + return NO; + } + /* FIXME */ + return YES; +} + +- (BOOL) copyObject: (id)anObject + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard +{ + return [self copyObjects: [NSArray arrayWithObject: anObject] + type: aType + toPasteboard: aPasteboard]; +} + +- (BOOL) copyObjects: (NSArray*)anArray + type: (NSString*)aType + toPasteboard: (NSPasteboard*)aPasteboard +{ + NSData *obj = [NSArchiver archivedDataWithRootObject: anArray]; + + [aPasteboard declareTypes: [NSArray arrayWithObject: aType] + owner: self]; + return [aPasteboard setData: obj forType: aType]; +} + +- (void) dealloc +{ + [[resourcesManager window] performClose: self]; + RELEASE(resourcesManager); + NSFreeMapTable(objToName); + RELEASE(documentPath); + RELEASE(owner); + [super dealloc]; +} + +- (void) detachObject: (id)anObject +{ + NSString *name = [self nameForObject: anObject]; + unsigned count = [connections count]; + + while (count-- > 0) + { + id con = [connections objectAtIndex: count]; + + if ([con destination] == anObject || [con source] == anObject) + { + [connections removeObjectAtIndex: count]; + } + } + NSMapRemove(objToName, (void*)anObject); + if ([anObject isKindOfClass: [NSWindow class]] == YES) + { + [resourcesManager removeObject: anObject]; + } + else if ([anObject isKindOfClass: [NSMenu class]] == YES) + { + [resourcesManager removeObject: anObject]; + } + [nameTable removeObjectForKey: name]; +} + +- (void) detachObjects: (NSArray*)anArray +{ + NSEnumerator *enumerator = [anArray objectEnumerator]; + NSObject *obj; + + while ((obj = [enumerator nextObject]) != nil) + { + [self detachObject: obj]; + } +} + +- (NSString*) documentPath +{ + return documentPath; +} + +- (BOOL) documentShouldClose +{ + if ([[resourcesManager window] isDocumentEdited] == YES) + { + NSString *msg; + int result; + + if (documentPath == nil || [documentPath isEqualToString: @""]) + { + msg = @"Document 'UNTITLED' has been modified"; + } + else + { + msg = [NSString stringWithFormat: @"Document '%@' has been modified", + [documentPath lastPathComponent]]; + } + result = NSRunAlertPanel(NULL, msg, @"Save", @"Cancel", @"Don't Save"); + if (result == NSAlertAlternateReturn) + { + return NO; + } + else if (result != NSAlertOtherReturn) + { + [self saveDocument: self]; + } + } + return YES; +} + +- (void) documentWillClose +{ + NSEnumerator *enumerator = [nameTable objectEnumerator]; + Class winClass = [NSWindow class]; + id obj; + + /* + * Close all open windows in this document befoew we go away. + */ + while ((obj = [enumerator nextObject]) != nil) + { + if ([obj isKindOfClass: winClass] == YES) + { + [obj setReleasedWhenClosed: YES]; + [obj close]; + } + } + [self setDocumentActive: NO]; +} + +- (void) encodeWithCoder: (NSCoder*)aCoder +{ + NSEnumerator *enumerator; + id con; + + /* + * Map all connector sources and destinations to their name strings. + * The 'owner' dummy object maps to 'NSOwner'. + * The nil object maps to 'NSFirstResponder'. + */ + enumerator = [connections objectEnumerator]; + while ((con = [enumerator nextObject]) != nil) + { + NSString *name; + id obj; + + obj = [con source]; + name = [self nameForObject: obj]; + [con setSource: name]; + obj = [con destination]; + name = [self nameForObject: obj]; + [con setDestination: name]; + } + + [super encodeWithCoder: aCoder]; + + /* + * Map all connector source and destination names to their objects. + * The string 'NSOwner' maps to the 'owner' dummy object. + * The string 'NSFirstResponder' maps to nil. + */ + enumerator = [connections objectEnumerator]; + while ((con = [enumerator nextObject]) != nil) + { + NSString *name; + id obj; + + name = (NSString*)[con source]; + obj = [self objectForName: name]; + [con setSource: obj]; + name = (NSString*)[con destination]; + obj = [self objectForName: name]; + [con setDestination: obj]; + } +} + +- (id) init +{ + self = [super init]; + if (self != nil) + { + objToName = NSCreateMapTableWithZone(NSNonRetainedObjectMapKeyCallBacks, + NSNonRetainedObjectMapValueCallBacks, 128, [self zone]); + owner = [NSObject new]; + resourcesManager = [GormResourcesManager newManagerForDocument: self]; + } + return self; +} + +- (NSString*) nameForObject: (id)anObject +{ + if (anObject == nil) + { + return @"NSFirstResponder"; + } + else if (anObject == owner) + { + return @"NSOwner"; + } + else + { + return (NSString*)NSMapGet(objToName, (void*)anObject); + } +} + +- (id) objectForName: (NSString*)name +{ + id obj = [nameTable objectForKey: name]; + + if (obj == nil) + { + if ([name isEqualToString: @"NSOwner"] == YES) + { + obj = owner; + } + } + return obj; +} + +- (NSArray*) objects +{ + return [nameTable allValues]; +} + +/* + * NB. This assumes we have an empty document to start with - the loaded + * document is merged in to it. + */ +- (id) openDocument: (id)sender +{ + NSArray *fileTypes = [NSArray arrayWithObject: @"nib"]; + NSOpenPanel *oPanel = [NSOpenPanel openPanel]; + int result; + + [oPanel setAllowsMultipleSelection: NO]; + [oPanel setCanChooseFiles: YES]; + [oPanel setCanChooseDirectories: NO]; + result = [oPanel runModalForDirectory: NSHomeDirectory() + file: nil + types: fileTypes]; + if (result == NSOKButton) + { + NSString *aFile = [oPanel filename]; + NSData *data; + NSUnarchiver *u; + GSNibContainer *c; + NSEnumerator *enumerator; + NSDictionary *nt; + id con; + NSString *name; + + data = [NSData dataWithContentsOfFile: aFile]; + if (data == nil) + { + NSRunAlertPanel(NULL, + [NSString stringWithFormat: @"Could not read '%@' data", aFile], + @"OK", NULL, NULL); + return nil; + } + u = AUTORELEASE([[NSUnarchiver alloc] initForReadingWithData: data]); +/* FIXME - need to handle class replacement here */ + c = [u decodeObject]; + if (c == nil || [c isKindOfClass: [GSNibContainer class]] == NO) + { + NSRunAlertPanel(NULL, @"Could not unarchive document data", + @"OK", NULL, NULL); + return nil; + } + + /* + * 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'. + */ + [[c nameTable] setObject: owner forKey: @"NSOwner"]; + nt = [c nameTable]; + enumerator = [[c 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]; + } + [[c nameTable] removeObjectForKey: @"NSOwner"]; + + /* + * Now we merge the objects from the nib container into our own + * data structures. + */ + [connections addObjectsFromArray: [c connections]]; + [nameTable addEntriesFromDictionary: [c nameTable]]; + + /* + * Now we build our reverse mapping information and other initialisation + */ + NSResetMapTable(objToName); + enumerator = [nameTable keyEnumerator]; + while ((name = [enumerator nextObject]) != nil) + { + id obj = [nameTable objectForKey: name]; + + NSMapInsert(objToName, (void*)obj, (void*)name); + + if ([obj isKindOfClass: [NSWindow class]] == YES) + { + [resourcesManager addObject: obj]; + } + else if ([obj isKindOfClass: [NSMenu class]] == YES) + { + [resourcesManager addObject: obj]; + } + } + + /* + * Finally, we set our new file name + */ + ASSIGN(documentPath, aFile); + [[resourcesManager window] setTitleWithRepresentedFilename: documentPath]; + return self; + } + return nil; /* Failed */ +} + +- (id) parentOfObject: (id)anObject +{ + NSArray *old; + id con; + + old = [self connectorsForSource: anObject ofClass: [GormConnector class]]; + con = [old lastObject]; + if (con != nil && [con destination] != owner) + { + return [con destination]; + } + return nil; +} + +- (NSArray*) pasteType: (NSString*)aType + fromPasteboard: (NSPasteboard*)aPasteboard + parent: (id)parent +{ + NSData *data = [aPasteboard dataForType: aType]; + NSArray *objects = [NSUnarchiver unarchiveObjectWithData: data]; + NSEnumerator *enumerator = [objects objectEnumerator]; + NSPoint filePoint; + NSPoint screenPoint; + + filePoint = [[resourcesManager window] mouseLocationOutsideOfEventStream]; + screenPoint = [[resourcesManager window] convertBaseToScreen: filePoint]; + + if ([aType isEqualToString: IBWindowPboardType] == YES) + { + NSWindow *win; + + while ((win = [enumerator nextObject]) != nil) + { + [win setFrameTopLeftPoint: screenPoint]; + [win orderFront: self]; + } + } + else + { + NSLog(@"Pasting %@ not implemented", aType); + objects = nil; +/* FIXME */ + } + + [self attachObjects: objects toParent: parent]; + [self touch]; + return objects; +} + +- (void) removeConnector: (id)aConnector +{ + [connections removeObjectIdenticalTo: aConnector]; +} + +- (GormResourcesManager*) resourcesManager +{ + return resourcesManager; +} + +- (void) setName: (NSString*)aName forObject: (id)object +{ + id oldObject; + NSString *oldName; + + if (object == nil) + { + NSLog(@"Attempt to set name for nil object"); + return; + } + if (aName == nil) + { + /* + * No name given - so we must generate one unless we already have one. + */ + oldName = [self nameForObject: object]; + if (oldName == nil) + { + NSString *base; + unsigned i = 0; + + /* + * Generate a sensible name for the object based on its class. + */ + base = NSStringFromClass([object class]); + if ([base hasPrefix: @"NS"] || [base hasPrefix: @"GS"]) + { + base = [base substringFromIndex: 2]; + } + aName = base; + while ([nameTable objectForKey: aName] != nil) + { + aName = [base stringByAppendingFormat: @"%u", ++i]; + } + } + else + { + return; /* Already named ... nothing to do */ + } + } + else + { + oldObject = [nameTable objectForKey: aName]; + if (oldObject != nil) + { + NSLog(@"Attempt to re-use name '%@'", aName); + return; + } + oldName = [self nameForObject: object]; + if (oldName != nil) + { + if ([oldName isEqual: aName] == YES) + { + return; /* Already have this namre ... nothing to do */ + } + NSMapRemove(objToName, (void*)object); + } + } + if ([aName isEqualToString: @"NSOwner"] + || [aName isEqualToString: @"NSFirstResponder"]) + { + NSLog(@"Attempt to set object name to '%@' ignored", aName); + return; + } + [nameTable setObject: object forKey: aName]; + NSMapInsert(objToName, (void*)object, (void*)aName); + if (oldName != nil) + { + [nameTable removeObjectForKey: oldName]; + } +} + +- (id) saveAsDocument: (id)sender +{ + NSSavePanel *sp; + int result; + + sp = [NSSavePanel savePanel]; + + [sp setRequiredFileType: @"nib"]; + result = [sp runModalForDirectory: NSHomeDirectory() file: @""]; + + if (result == NSOKButton) + { + NSFileManager *mgr = [NSFileManager defaultManager]; + NSString *path = [sp filename]; + NSString *old = documentPath; + id retval; + + if ([path isEqual: documentPath] == NO + && [mgr fileExistsAtPath: path] == YES) + { + if (NSRunAlertPanel(NULL, @"A document with that name exists", + @"Replace", @"Cancel", NULL) != NSAlertDefaultReturn) + { + return nil; + } + else + { + NSString *bPath = [path stringByAppendingString: @"~"]; + + [mgr removeFileAtPath: bPath handler: nil]; + [mgr movePath: path toPath: bPath handler: nil]; + } + } + documentPath = RETAIN(path); + retval = [self saveDocument: sender]; + if (retval == nil) + { + RELEASE(documentPath); + documentPath = old; + } + else + { + RELEASE(old); + /* FIXME - need to update files window title etc */ + return self; + } + } + return nil; +} + +- (id) saveDocument: (id)sender +{ + if (documentPath == nil || [documentPath isEqualToString: @""]) + { + return [self saveAsDocument: sender]; + } + if ([NSArchiver archiveRootObject: self toFile: documentPath] == NO) + { + NSRunAlertPanel(NULL, @"Could not save document", + @"OK", NULL, NULL); + return nil; + } + [[resourcesManager window] setDocumentEdited: NO]; + [[resourcesManager window] setTitleWithRepresentedFilename: documentPath]; + return self; +} + +- (void) setDocumentActive: (BOOL)flag +{ + NSEnumerator *enumerator = [nameTable objectEnumerator]; + Class winClass = [NSWindow class]; + id obj; + + if (flag == YES) + { + while ((obj = [enumerator nextObject]) != nil) + { + if ([obj isKindOfClass: winClass] == YES) + { + [obj orderFront: self]; + } + } + [[resourcesManager window] orderFront: self]; + } + else + { + while ((obj = [enumerator nextObject]) != nil) + { + if ([obj isKindOfClass: winClass] == YES) + { + [obj orderOut: self]; + } + } + [[resourcesManager window] orderOut: self]; + } +} + +- (void) touch +{ + [[resourcesManager window] setDocumentEdited: YES]; +} + +@end + diff --git a/GormEditors.m b/GormEditors.m new file mode 100644 index 00000000..ed6913d4 --- /dev/null +++ b/GormEditors.m @@ -0,0 +1,133 @@ +/* GormEditors.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + + +@implementation NSObject (IBEditorSpecification) +- (NSString*) editorClassName +{ + return @"GormObjectEditor"; +} +@end + + +@interface GormObjectEditor : NSObject +{ + id object; + id document; + NSMutableArray *subeditors; +} +- (BOOL) acceptsTypeFromArray: (NSArray*)types; +- (BOOL) activate; +- (id) initWithObject: (id)anObject inDocument: (id)aDocument; +- (void) close; +- (void) closeSubeditors; +- (void) copySelection; +- (void) deleteSelection; +- (id) document; +- (id) editedObject; +- (void) makeSelectionVisible: (BOOL)flag; +- (id) openSubeditorForObject: (id)anObject; +- (void) orderFront; +- (void) pasteInSelection; +- (void) resetObject: (id)anObject; +- (void) selectObjects: (NSArray*)objects; +- (void) validateEditing; +- (BOOL) wantsSelection; +- (NSWindow*) window; +@end + + +@implementation GormObjectEditor + +- (BOOL) acceptsTypeFromArray: (NSArray*)types +{ + return NO; +} + +- (BOOL) activate +{ + return NO; +} + +- (void) dealloc +{ + RELEASE(subeditors); + RELEASE(object); + RELEASE(document); + [super dealloc]; +} + +- (id) initWithObject: (id)anObject inDocument: (id)aDocument +{ + self = [super init]; + if (self) + { + object = RETAIN(anObject); + document = RETAIN(aDocument); + subeditors = [NSMutableArray new]; + } + return self; +} + +- (void) close +{ + [self closeSubeditors]; +} + +- (void) closeSubeditors +{ + unsigned i = [subeditors count]; + + while (i-- > 0) + { + [[subeditors objectAtIndex: i] close]; + [subeditors removeObjectAtIndex: i]; + } +} + +- (void) copySelection +{ +} + +- (void) deleteSelection +{ +} + +- (id) document +{ + return document; +} + +- (id) editedObject +{ + return object; +} + +- (void) makeSelectionVisible: (BOOL)flag +{ +} + +@end diff --git a/GormInspectorsManager.h b/GormInspectorsManager.h new file mode 100644 index 00000000..59e57219 --- /dev/null +++ b/GormInspectorsManager.h @@ -0,0 +1,19 @@ +#ifndef GORMINSPECTORSMANAGER_H +#define GORMINSPECTORSMANAGER_H + +@interface GormInspectorsManager : NSObject +{ + NSPanel *panel; + NSMatrix *selectionView; + NSView *inspectorView; + NSArray *selection; + NSButton *emptyView; + NSButton *multipleView; + IBInspector *inspector; + int current; +} +- (NSPanel*) panel; +- (void) setCurrentInspector: (id)anObject; +@end + +#endif diff --git a/GormInspectorsManager.m b/GormInspectorsManager.m new file mode 100644 index 00000000..e5fae38f --- /dev/null +++ b/GormInspectorsManager.m @@ -0,0 +1,225 @@ +/* GormInspectorsManager.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + +@implementation NSObject (IBInspectorClassNames) +- (NSString*) inspectorClassName +{ + return @"GormObjectAttributesInspector"; +} + +- (NSString*) connectInspectorClassName +{ + return @"GormObjectConnectionsInspector"; +} + +- (NSString*) sizeInspectorClassName +{ + return @"GormObjectSizeInspector"; +} + +- (NSString*) helpInspectorClassName +{ + return @"GormObjectHelpInspector"; +} + +- (NSString*) classInspectorClassName +{ + return @"GormObjectClassInspector"; +} + +@end + +@implementation GormInspectorsManager + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + RELEASE(selectionView); + RELEASE(inspectorView); + RELEASE(emptyView); + RELEASE(multipleView); + RELEASE(panel); + [super dealloc]; +} + +- (id) init +{ + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + NSBox *box; + NSCell *cell; + NSRect contentRect = {{0, 0}, {272, 420}}; + NSRect selectionRect = {{0, 378}, {272, 52}}; + NSRect boxRect = {{0, 361}, {272, 2}}; + NSRect inspectorRect = {{0, 0}, {272, 360}}; + unsigned int style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask; + + panel = [[NSPanel alloc] initWithContentRect: contentRect + styleMask: style + backing: NSBackingStoreRetained + defer: NO]; + box = [[NSBox alloc] initWithFrame: boxRect]; + [box setBorderType: NSLineBorder]; + [box setTitlePosition: NSNoTitle]; + [box setAutoresizingMask: NSViewWidthSizable|NSViewMinYMargin]; + [[panel contentView] addSubview: box]; + RELEASE(box); + + [panel setTitle: @"Inspector"]; + [panel setMinSize: [panel frame].size]; + + selectionView = [[NSMatrix alloc] initWithFrame: selectionRect + mode: NSRadioModeMatrix + cellClass: [NSCell class] + numberOfRows: 1 + numberOfColumns: 4]; + [selectionView setTarget: self]; + [selectionView setAction: @selector(setCurrentInspector:)]; + [selectionView setCellSize: NSMakeSize(52,52)]; + [selectionView setIntercellSpacing: NSMakeSize(0,0)]; + [selectionView setAutoresizingMask: NSViewWidthSizable|NSViewMinYMargin]; + cell = [selectionView cellAtRow: 0 column: 0]; + [cell setStringValue: @"Attr"]; + cell = [selectionView cellAtRow: 0 column: 1]; + [cell setStringValue: @"Size"]; + cell = [selectionView cellAtRow: 0 column: 2]; + [cell setStringValue: @"Conn"]; + cell = [selectionView cellAtRow: 0 column: 3]; + [cell setStringValue: @"Help"]; + [[panel contentView] addSubview: selectionView]; + RELEASE(selectionView); + + inspectorView = [[NSView alloc] initWithFrame: inspectorRect]; + [inspectorView setAutoresizingMask: + NSViewHeightSizable | NSViewWidthSizable]; + [[panel contentView] addSubview: inspectorView]; + RELEASE(inspectorView); + + [panel setFrameUsingName: @"Inspector"]; + [panel setFrameAutosaveName: @"Inspector"]; + + current = -1; + + emptyView = [[NSButton alloc] initWithFrame: inspectorRect]; + [emptyView setAutoresizingMask: + NSViewHeightSizable | NSViewWidthSizable]; + [emptyView setStringValue: @"Empty Selection"]; + [emptyView setBordered: NO]; + + multipleView = [[NSButton alloc] initWithFrame: inspectorRect]; + [multipleView setAutoresizingMask: + NSViewHeightSizable | NSViewWidthSizable]; + [multipleView setStringValue: @"Multiple Selection"]; + [multipleView setBordered: NO]; + + [nc addObserver: self + selector: @selector(selectionChanged:) + name: IBSelectionChangedNotification + object: nil]; + [self setCurrentInspector: 0]; + return self; +} + +- (NSPanel*) panel +{ + return panel; +} + +- (void) selectionChanged: (NSNotification*)notification +{ + [self setCurrentInspector: self]; +} + +- (void) setCurrentInspector: (id)anObj +{ + id owner = [(id)NSApp selectionOwner]; + unsigned count = [owner selectionCount]; + NSArray *sub = [inspectorView subviews]; + IBInspector *newInspector = nil; + NSView *newView = nil; + + if (anObj != self) + { + current = [anObj selectedColumn]; + } + + if (count == 0) + { + newView = emptyView; + } + else if (count > 1) + { + newView = multipleView; + } + else + { + id obj = [[owner selection] lastObject]; + NSString *name; + Class c; + + switch (current) + { + case 0: name = [obj inspectorClassName]; break; + case 1: name = [obj connectInspectorClassName]; break; + case 2: name = [obj sizeInspectorClassName]; break; + case 3: name = [obj helpInspectorClassName]; break; + default: name = [obj classInspectorClassName]; break; + } + c = NSClassFromString(name); + if (inspector == nil || [inspector class] != c) + { + newInspector = [c new]; + newView = [[newInspector window] contentView]; + } + else + { + newInspector = inspector; + } + } + + if (newInspector != inspector) + { + if (inspector != nil) + { + [[inspector window] setContentView: [sub lastObject]]; + RELEASE((id)inspector); + sub = [inspectorView subviews]; + } + inspector = newInspector; + } + if (newView != nil) + { + if ([sub count] > 0) + { + [inspectorView replaceSubview: [sub lastObject] with: newView]; + } + else + { + [inspectorView addSubview: newView]; + } + } +} + +@end diff --git a/GormPalettesManager.h b/GormPalettesManager.h new file mode 100644 index 00000000..488e7e36 --- /dev/null +++ b/GormPalettesManager.h @@ -0,0 +1,20 @@ +#ifndef GORMPALETTESMANAGER_H +#define GORMPALETTESMANAGER_H + +@interface GormPalettesManager : NSObject +{ + NSPanel *panel; + NSMatrix *selectionView; + NSView *dragView; + NSMutableArray *bundles; + NSMutableArray *palettes; + int current; +} + +- (void) loadPalette: (NSString*)path; +- (id) openPalette: (id) sender; +- (NSPanel*) panel; +- (void) setCurrentPalette: (id)anObject; +@end + +#endif diff --git a/GormPalettesManager.m b/GormPalettesManager.m new file mode 100644 index 00000000..c0760079 --- /dev/null +++ b/GormPalettesManager.m @@ -0,0 +1,434 @@ +/* GormPalettesPanager.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + +@interface GormPaletteView : NSView +{ + NSPoint mouseDownPoint; + BOOL shouldBeginDrag; + NSPasteboard *dragPb; +} +- (void) draggedImage: (NSImage*)i endedAt: (NSPoint)p deposited: (BOOL)f; +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)flag; +@end + +@implementation GormPaletteView + +static NSImage *dragImage = nil; ++ (void) initialize +{ + if (self == [GormPaletteView class]) + { + NSBundle *bundle = [NSBundle mainBundle]; + NSString *path = [bundle pathForImageResource: @"GormLinkImage"]; + + dragImage = [[NSImage alloc] initWithContentsOfFile: path]; + } +} + +/* + * Initialisation - register to receive DnD with our own types. + */ +- (id) initWithFrame: (NSRect)aFrame +{ + self = [super initWithFrame: aFrame]; + if (self != nil) + { + [self registerForDraggedTypes: [NSArray arrayWithObjects: + IBCellPboardType, IBMenuPboardType, IBMenuCellPboardType, + IBObjectPboardType, IBViewPboardType, IBWindowPboardType, nil]]; + } + return self; +} + +/* + * Dragging source protocol implementation + */ +- (void) draggedImage: (NSImage*)i endedAt: (NSPoint)p deposited: (BOOL)f +{ + NSString *type = [[dragPb types] lastObject]; + + /* + * Windows are an exception to the normal DnD mechanism - we create them + * if they are dropped anywhere except back in the pallettes view - + * ie. if they are dragged, but the drop fails. + */ + if (f == NO && [type isEqual: IBWindowPboardType] == YES) + { + id active = [(id)NSApp activeDocument]; + + if (active != nil) + { + [active pasteType: type fromPasteboard: dragPb parent: nil]; + } + } +} + +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)flag +{ + return NSDragOperationCopy; +} + +/* + * Dragging destination protocol implementation + * + * We actually don't handle anything being dropped on the palette, + * but we pretend to accept drops from ourself, so that the drag + * session quietly terminates - and it looks like the drop has + * been successful - this stops windows being created when they are + * dropped back on the palette (a window is normally created if the + * dnd drop is refused). + */ +- (unsigned) draggingEntered: (id)sender +{ + return NSDragOperationCopy;; +} +- (BOOL) performDragOperation: (id)sender +{ + return YES; +} +- (BOOL) prepareForDragOperation: (id)sender +{ + return YES; +} + + +/* + * Intercepting events in the view and handling them + */ +- (NSView*) hitTest: (NSPoint)loc +{ + /* + * Stop the subviews receiving events - we grab them all. + */ + if ([super hitTest: loc] != nil) + return self; + return nil; +} + +- (void) mouseDown: (NSEvent*)theEvent +{ + NSView *view; + + mouseDownPoint = [theEvent locationInWindow]; + view = [super hitTest: mouseDownPoint]; + if (view == self) + { + shouldBeginDrag = NO; + } + else + { + shouldBeginDrag = YES; + } +} + +- (void) mouseDragged: (NSEvent*)theEvent +{ + if (shouldBeginDrag == YES) + { + NSPoint dragPoint = [theEvent locationInWindow]; + NSView *view = [super hitTest: mouseDownPoint]; + GormDocument *active = [(id)NSApp activeDocument]; + NSRect rect = [view frame]; + NSString *type; + id obj; + NSPasteboard *pb; + NSImageRep *rep; + NSSize offset; + + offset.width = mouseDownPoint.x - dragPoint.x; + offset.height = mouseDownPoint.y - dragPoint.y; + + RELEASE(dragImage); + dragImage = [NSImage new]; + rep = [[NSCachedImageRep alloc] initWithWindow: [self window] + rect: rect]; + [dragImage setSize: rect.size]; + [dragImage addRepresentation: rep]; + + type = [IBPalette typeForView: view]; + obj = [IBPalette objectForView: view]; + pb = [NSPasteboard pasteboardWithName: NSDragPboard]; + ASSIGN(dragPb, pb); + [active copyObject: obj type: type toPasteboard: pb]; + + [self dragImage: dragImage + at: rect.origin + offset: offset + event: theEvent + pasteboard: pb + source: self + slideBack: [type isEqual: IBWindowPboardType] ? NO : YES]; + } +} +@end + + +@implementation GormPalettesManager + +- (void) dealloc +{ + RELEASE(panel); + RELEASE(bundles); + RELEASE(palettes); + [super dealloc]; +} + +- (id) init +{ + NSScrollView *scrollView; + NSArray *array; + NSRect contentRect = {{0, 0}, {272, 266}}; + NSRect selectionRect = {{0, 0}, {52, 52}}; + NSRect scrollRect = {{0, 192}, {272, 74}}; + NSRect dragRect = {{0, 0}, {272, 192}}; + unsigned int style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask; + + panel = [[NSPanel alloc] initWithContentRect: contentRect + styleMask: style + backing: NSBackingStoreRetained + defer: NO]; + [panel setTitle: @"Palettes"]; + [panel setMinSize: [panel frame].size]; + + bundles = [NSMutableArray new]; + palettes = [NSMutableArray new]; + + scrollView = [[NSScrollView alloc] initWithFrame: scrollRect]; + [scrollView setHasHorizontalScroller: YES]; + [scrollView setHasVerticalScroller: NO]; + [scrollView setAutoresizingMask: NSViewMinYMargin | NSViewWidthSizable]; + selectionView = [[NSMatrix alloc] initWithFrame: selectionRect + mode: NSRadioModeMatrix + cellClass: [NSImageCell class] + numberOfRows: 1 + numberOfColumns: 0]; + [selectionView setTarget: self]; + [selectionView setAction: @selector(setCurrentPalette:)]; + [selectionView setCellSize: NSMakeSize(52,52)]; + [selectionView setIntercellSpacing: NSMakeSize(0,0)]; + [scrollView setDocumentView: selectionView]; + RELEASE(selectionView); + [[panel contentView] addSubview: scrollView]; + RELEASE(scrollView); + + dragView = [[GormPaletteView alloc] initWithFrame: dragRect]; + [dragView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; + [[panel contentView] addSubview: dragView]; + RELEASE(dragView); + + [panel setFrameUsingName: @"Palettes"]; + [panel setFrameAutosaveName: @"Palettes"]; + current = -1; + + array = [[NSBundle mainBundle] pathsForResourcesOfType: @"palette" + inDirectory: nil]; + if ([array count] > 0) + { + unsigned index; + + for (index = 0; index < [array count]; index++) + { + [self loadPalette: [array objectAtIndex: index]]; + } + } + + return self; +} + +- (void) loadPalette: (NSString*)path +{ + NSBundle *bundle; + NSWindow *window; + Class paletteClass; + NSDictionary *paletteInfo; + NSString *className; + IBPalette *palette; + NSImageCell *cell; + int col; + + for (col = 0; col < [bundles count]; col++) + { + bundle = [bundles objectAtIndex: col]; + if ([path isEqualToString: [bundle bundlePath]] == YES) + { + NSRunAlertPanel (NULL, @"Palette has already been loaded", + @"OK", NULL, NULL); + return; + } + } + bundle = [NSBundle bundleWithPath: path]; + if (bundle == nil) + { + NSRunAlertPanel(NULL, @"Could not load Palette", + @"OK", NULL, NULL); + return; + } + [bundles addObject: bundle]; + + path = [bundle pathForResource: @"palette" ofType: @"table"]; + if (path == nil) + { + NSRunAlertPanel(NULL, @"File 'palette.table' missing", + @"OK", NULL, NULL); + return; + } + + paletteInfo = [[NSString stringWithContentsOfFile: path] + propertyListFromStringsFileFormat]; + if (paletteInfo == nil) + { + NSRunAlertPanel(NULL, @"Failed to load 'palette.table'", + @"OK", NULL, NULL); + return; + } + + className = [paletteInfo objectForKey: @"Class"]; + if (className == nil) + { + NSRunAlertPanel(NULL, @"No palette class in 'palette.table'", + @"OK", NULL, NULL); + return; + } + + paletteClass = [bundle classNamed: className]; + if (paletteClass == 0) + { + NSRunAlertPanel (NULL, @"Could not load palette class", + @"OK", NULL, NULL); + return; + } + + palette = [paletteClass new]; + if ([palette isKindOfClass: [IBPalette class]] == NO) + { + NSRunAlertPanel (NULL, @"Palette contains wrong type of class", + @"OK", NULL, NULL); + RELEASE(palette); + return; + } + + [palette finishInstantiate]; + window = [palette originalWindow]; + [window setExcludedFromWindowsMenu: YES]; + + [palettes addObject: palette]; + [selectionView addColumn]; + [[palette paletteIcon] setBackgroundColor: [selectionView backgroundColor]]; + col = [selectionView numberOfColumns] - 1; + cell = [selectionView cellAtRow: 0 column: col]; + [cell setImageFrameStyle: NSImageFrameButton]; + [cell setImage: [palette paletteIcon]]; + [selectionView sizeToCells]; + [selectionView selectCellAtRow: 0 column: col]; + [selectionView setNeedsDisplay: YES]; + RELEASE(palette); +} + +- (id) openPalette: (id) sender +{ + NSArray *fileTypes = [NSArray arrayWithObject: @"palette"]; + NSOpenPanel *oPanel = [NSOpenPanel openPanel]; + int result; + + [oPanel setAllowsMultipleSelection: YES]; + [oPanel setCanChooseFiles: YES]; + [oPanel setCanChooseDirectories: NO]; + result = [oPanel runModalForDirectory: NSHomeDirectory() + file: nil + types: fileTypes]; + + if (result == NSOKButton) + { + NSArray *filesToOpen = [oPanel filenames]; + unsigned count = [filesToOpen count]; + unsigned i; + + for (i = 0; i < count; i++) + { + NSString *aFile = [filesToOpen objectAtIndex: i]; + + [self loadPalette: aFile]; + } + return self; + } + return nil; +} + +- (NSPanel*) panel +{ + return panel; +} + +- (void) setCurrentPalette: (id)anObj +{ + NSView *wv; + NSView *sv; + NSEnumerator *enumerator; + + if (current >= 0) + { + /* + * Move the views in the drag view back to the content view of the + * window they originally came from. + */ + wv = [[[palettes objectAtIndex: current] originalWindow] contentView]; + enumerator = [[dragView subviews] objectEnumerator]; + while ((sv = [enumerator nextObject]) != nil) + { + RETAIN(sv); + [sv removeFromSuperview]; + [wv addSubview: sv]; + RELEASE(sv); + } + } + + current = [anObj selectedColumn]; + if (current >= 0 && current < [palettes count]) + { + /* + * Move the views from their original window into our drag view. + * Resize our drag view to the right size fitrst. + */ + wv = [[[palettes objectAtIndex: current] originalWindow] contentView]; + [dragView setFrameSize: [wv frame].size]; + enumerator = [[wv subviews] objectEnumerator]; + while ((sv = [enumerator nextObject]) != nil) + { + RETAIN(sv); + [sv removeFromSuperview]; + [dragView addSubview: sv]; + RELEASE(sv); + } + } + else + { + NSLog(@"Bad palette selection - %d", [anObj selectedColumn]); + current = -1; + } + [dragView setNeedsDisplay: YES]; +} + +@end diff --git a/GormPrivate.h b/GormPrivate.h new file mode 100644 index 00000000..f14362f1 --- /dev/null +++ b/GormPrivate.h @@ -0,0 +1,34 @@ +#ifndef GORMPRIVATE_H +#define GORMPRIVATE_H + +@class GormDocument; +@class GormInspectorsManager; +@class GormPalettesManager; +@class GormResourcesManager; + +#include "Gorm.h" + +#include "GormDocument.h" +#include "GormInspectorsManager.h" +#include "GormPalettesManager.h" +#include "GormResourcesManager.h" + +@interface Gorm : NSApplication +{ + id infoPanel; + GormInspectorsManager *inspectorsManager; + GormPalettesManager *palettesManager; + id selectionOwner; + NSMutableArray *documents; +} +- (id) activeDocument; +- (GormInspectorsManager*) inspectorsManager; +- (id) makeNewDocument: (id) sender; +- (id) openPalette: (id) sender; +- (GormPalettesManager*) palettesManager; +- (id) runInfoPanel: (id) sender; +- (id) runGormInspectors: (id) sender; +- (id) runGormPalettes: (id) sender; +@end + +#endif diff --git a/GormResourcesManager.h b/GormResourcesManager.h new file mode 100644 index 00000000..7dd68273 --- /dev/null +++ b/GormResourcesManager.h @@ -0,0 +1,22 @@ +#ifndef GORMRESOURCESMANAGER_H +#define GORMRESOURCESMANAGER_H + +@interface GormResourcesManager : NSObject +{ + NSWindow *window; + NSMatrix *selectionView; + NSScrollView *scrollView; + id objectsView; + id document; +} ++ (GormResourcesManager*) newManagerForDocument: (id)doc; +- (void) addObject: (id)anObject; +- (void) changeView: (id)sender; +- (id) document; +- (void) removeObject: (id)anObject; +- (NSWindow*) window; +- (BOOL) windowShouldClose: (NSWindow*)aWindow; +- (void) windowWillClose: (NSNotification*)aNotification; +@end + +#endif diff --git a/GormResourcesManager.m b/GormResourcesManager.m new file mode 100644 index 00000000..ab502d74 --- /dev/null +++ b/GormResourcesManager.m @@ -0,0 +1,535 @@ +/* GormResourcesManager.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "GormPrivate.h" + + +@interface GormObjectsView : NSMatrix +{ + NSMutableArray *objects; + NSPoint mouseDownPoint; + BOOL shouldBeginDrag; + NSPasteboard *dragPb; +} +- (void) addObject: (id)anObject; +- (void) draggedImage: (NSImage*)i endedAt: (NSPoint)p deposited: (BOOL)f; +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)flag; +- (void) refreshCells; +- (void) removeObject: (id)anObject; +@end + +@implementation GormObjectsView + +static NSImage *objectImage = nil; +static NSImage *windowImage = nil; +static NSImage *menuImage = nil; +static NSImage *firstImage = nil; +static NSImage *ownerImage = nil; +static NSImage *fontImage = nil; +static NSImage *dragImage = nil; + ++ (void) initialize +{ + if (self == [GormObjectsView class]) + { + NSBundle *bundle; + NSString *path; + + bundle = [NSBundle mainBundle]; + path = [bundle pathForImageResource: @"GormLinkImage"]; + if (path != nil) + { + dragImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormObject"]; + if (path != nil) + { + objectImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormFilesOwner"]; + if (path != nil) + { + ownerImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormFirstResponder"]; + if (path != nil) + { + firstImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormFontManager"]; + if (path != nil) + { + fontImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormMenu"]; + if (path != nil) + { + menuImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + path = [bundle pathForImageResource: @"GormWindow"]; + if (path != nil) + { + windowImage = [[NSImage alloc] initWithContentsOfFile: path]; + } + } +} + +- (void) addObject: (id)anObject +{ + if ([objects indexOfObjectIdenticalTo: anObject] == NSNotFound) + { + [objects addObject: anObject]; + [self refreshCells]; + } +} + +- (void) dealloc +{ + RELEASE(objects); + [super dealloc]; +} + +/* + * Initialisation - register to receive DnD with our own types. + */ +- (id) initWithFrame: (NSRect)aFrame +{ + self = [super initWithFrame: aFrame]; + if (self != nil) + { + NSButtonCell *proto; + + [self registerForDraggedTypes: [NSArray arrayWithObjects: + IBCellPboardType, IBMenuPboardType, IBMenuCellPboardType, + IBObjectPboardType, IBViewPboardType, IBWindowPboardType, nil]]; + + [self setAutosizesCells: NO]; + [self setCellSize: NSMakeSize(72,72)]; + [self setIntercellSpacing: NSMakeSize(8,8)]; + [self setAutoresizingMask: NSViewMinYMargin|NSViewWidthSizable]; + + objects = [NSMutableArray new]; + [objects addObject: ownerImage]; + [objects addObject: firstImage]; + proto = [NSButtonCell new]; + [proto setBordered: NO]; + [proto setAlignment: NSCenterTextAlignment]; + [proto setImagePosition: NSImageAbove]; + [self setPrototype: proto]; + RELEASE(proto); + [self renewRows: 2 columns: 3]; + [self refreshCells]; + } + return self; +} + +/* + * Dragging source protocol implementation + */ +- (void) draggedImage: (NSImage*)i endedAt: (NSPoint)p deposited: (BOOL)f +{ + NSString *type = [[dragPb types] lastObject]; + + /* + * Windows are an exception to the normal DnD mechanism - we create them + * if they are dropped anywhere except back in the pallettes view - + * ie. if they are dragged, but the drop fails. + */ + if (f == NO && [type isEqual: IBWindowPboardType] == YES) + { + id active = [(id)NSApp activeDocument]; + + if (active != nil) + { + [active pasteType: type fromPasteboard: dragPb parent: nil]; + } + } +} + +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)flag +{ + return NSDragOperationCopy; +} + +/* + * Dragging destination protocol implementation + * + * We actually don't handle anything being dropped on the palette, + * but we pretend to accept drops from ourself, so that the drag + * session quietly terminates - and it looks like the drop has + * been successful - this stops windows being created when they are + * dropped back on the palette (a window is normally created if the + * dnd drop is refused). + */ +- (unsigned) draggingEntered: (id)sender +{ + return NSDragOperationCopy;; +} +- (BOOL) performDragOperation: (id)sender +{ + return YES; +} +- (BOOL) prepareForDragOperation: (id)sender +{ + return YES; +} + + +/* + * Intercepting events in the view and handling them + */ +- (NSView*) hitTest: (NSPoint)loc +{ + /* + * Stop the subviews receiving events - we grab them all. + */ + if ([super hitTest: loc] != nil) + return self; + return nil; +} + +- (void) mouseDown: (NSEvent*)theEvent +{ + NSView *view; + + mouseDownPoint = [theEvent locationInWindow]; + view = [super hitTest: mouseDownPoint]; + if (view == self) + { + shouldBeginDrag = NO; + } + else + { + shouldBeginDrag = YES; + } +} + +- (void) mouseDragged: (NSEvent*)theEvent +{ + if (shouldBeginDrag == YES) + { + NSPoint dragPoint = [theEvent locationInWindow]; + NSView *view = [super hitTest: mouseDownPoint]; + GormDocument *active = [(id)NSApp activeDocument]; + NSRect rect = [view frame]; + NSString *type; + id obj; + NSPasteboard *pb; + NSImageRep *rep; + NSSize offset; + + offset.width = mouseDownPoint.x - dragPoint.x; + offset.height = mouseDownPoint.y - dragPoint.y; + + RELEASE(dragImage); + dragImage = [NSImage new]; + rep = [[NSCachedImageRep alloc] initWithWindow: [self window] + rect: rect]; + [dragImage setSize: rect.size]; + [dragImage addRepresentation: rep]; + + type = [IBPalette typeForView: view]; + obj = [IBPalette objectForView: view]; + pb = [NSPasteboard pasteboardWithName: NSDragPboard]; + ASSIGN(dragPb, pb); + [active copyObject: obj type: type toPasteboard: pb]; + + [self dragImage: dragImage + at: rect.origin + offset: offset + event: theEvent + pasteboard: pb + source: self + slideBack: [type isEqual: IBWindowPboardType] ? NO : YES]; + } +} + +- (void) refreshCells +{ + unsigned count = [objects count]; + unsigned index; + int cols = 0; + int rows; + int width; + id document; + + document = [(id)NSApp activeDocument]; + + width = [[self superview] bounds].size.width; + while (width >= 72) + { + width -= (72 + 8); + cols++; + } + if (cols == 0) + { + cols = 1; + } + rows = count / cols; + if (rows == 0 || rows * cols != count) + { + rows++; + } + [self renewRows: rows columns: cols]; + + for (index = 0; index < count; index++) + { + id obj = [objects objectAtIndex: index]; + NSButtonCell *but = [self cellAtRow: index/cols column: index%cols]; + + if (obj == ownerImage) + { + [but setImage: obj]; + [but setTitle: @"File's Owner"]; + } + else if (obj == firstImage) + { + [but setImage: obj]; + [but setTitle: @"1st Responder"]; + } + else if (obj == fontImage) + { + [but setImage: obj]; + [but setTitle: @"Font Manager"]; + } + else if ([obj isKindOfClass: [NSWindow class]]) + { + [but setImage: windowImage]; + [but setTitle: [document nameForObject: obj]]; + } + else if ([obj isKindOfClass: [NSMenu class]]) + { + [but setImage: menuImage]; + [but setTitle: [document nameForObject: obj]]; + } + else + { + [but setImage: objectImage]; + [but setTitle: [document nameForObject: obj]]; + } + } + while (index < rows * cols) + { + NSButtonCell *but = [self cellAtRow: index/cols column: index%cols]; + + [but setImage: nil]; + [but setTitle: nil]; + index++; + } + [self setIntercellSpacing: NSMakeSize(8,8)]; + [self sizeToCells]; + [self setNeedsDisplay: YES]; +} + +- (void) removeObject: (id)anObject +{ + unsigned pos; + + pos = [objects indexOfObjectIdenticalTo: anObject]; + if (pos == NSNotFound) + { + return; + } + if (anObject == ownerImage || anObject == firstImage) + { + return; + } + [objects removeObjectAtIndex: pos]; + [self refreshCells]; +} + +- (void) resizeWithOldSuperviewSize: (NSSize)oldSize +{ + [self refreshCells]; +} + +@end + + + + +@implementation GormResourcesManager + ++ (GormResourcesManager*) newManagerForDocument: (id)doc +{ + GormResourcesManager *mgr; + + mgr = [[self alloc] init]; + mgr->document = doc; + return mgr; +} + +- (void) addObject: (id)anObject +{ + [objectsView addObject: anObject]; +} + +- (void) dealloc +{ + [window performClose: self]; + RELEASE(window); + RELEASE(objectsView); + [super dealloc]; +} + +- (id) document +{ + return document; +} + +- (id) init +{ + self = [super init]; + if (self != nil) + { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + NSRect winrect = NSMakeRect(100,100,340,252); + NSRect selectionRect = {{0, 188}, {240, 64}}; + NSRect scrollRect = {{0, 0}, {340, 188}}; + NSRect mainRect = {{20, 0}, {320, 188}}; + NSBundle *bundle; + NSString *path; + NSImage *image; + NSButtonCell *cell; + unsigned style = NSTitledWindowMask | NSClosableWindowMask + | NSResizableWindowMask | NSMiniaturizableWindowMask; + + window = [[NSWindow alloc] initWithContentRect: winrect + styleMask: style + backing: NSBackingStoreRetained + defer: NO]; + [window setDelegate: self]; + [window setMinSize: [window frame].size]; + [window setTitle: @"UNTITLED"]; + [nc addObserver: self + selector: @selector(windowWillClose:) + name: NSWindowWillCloseNotification + object: window]; + + selectionView = [[NSMatrix alloc] initWithFrame: selectionRect + mode: NSRadioModeMatrix + cellClass: [NSButtonCell class] + numberOfRows: 1 + numberOfColumns: 4]; + [selectionView setTarget: self]; + [selectionView setAction: @selector(changeView:)]; + [selectionView setAutosizesCells: NO]; + [selectionView setCellSize: NSMakeSize(64,64)]; + [selectionView setIntercellSpacing: NSMakeSize(28,0)]; + [selectionView setAutoresizingMask: NSViewMinYMargin|NSViewWidthSizable]; + + bundle = [NSBundle mainBundle]; + + path = [bundle pathForImageResource: @"GormObject"]; + if (path != nil) + { + image = [[NSImage alloc] initWithContentsOfFile: path]; + cell = [selectionView cellAtRow: 0 column: 0]; + [cell setImage: image]; + RELEASE(image); + [cell setTitle: @"Objects"]; + [cell setBordered: NO]; + [cell setAlignment: NSCenterTextAlignment]; + [cell setImagePosition: NSImageAbove]; + } + + path = [bundle pathForImageResource: @"GormImage"]; + if (path != nil) + { + image = [[NSImage alloc] initWithContentsOfFile: path]; + cell = [selectionView cellAtRow: 0 column: 1]; + [cell setImage: image]; + RELEASE(image); + [cell setTitle: @"Images"]; + [cell setBordered: NO]; + [cell setAlignment: NSCenterTextAlignment]; + [cell setImagePosition: NSImageAbove]; + } + + path = [bundle pathForImageResource: @"GormSound"]; + if (path != nil) + { + image = [[NSImage alloc] initWithContentsOfFile: path]; + cell = [selectionView cellAtRow: 0 column: 2]; + [cell setImage: image]; + RELEASE(image); + [cell setTitle: @"Sounds"]; + [cell setBordered: NO]; + [cell setAlignment: NSCenterTextAlignment]; + [cell setImagePosition: NSImageAbove]; + } + + path = [bundle pathForImageResource: @"GormClass"]; + if (path != nil) + { + image = [[NSImage alloc] initWithContentsOfFile: path]; + cell = [selectionView cellAtRow: 0 column: 3]; + [cell setImage: image]; + RELEASE(image); + [cell setTitle: @"Classes"]; + [cell setBordered: NO]; + [cell setAlignment: NSCenterTextAlignment]; + [cell setImagePosition: NSImageAbove]; + } + + [[window contentView] addSubview: selectionView]; + RELEASE(selectionView); + + scrollView = [[NSScrollView alloc] initWithFrame: scrollRect]; + [scrollView setHasVerticalScroller: YES]; + [scrollView setHasHorizontalScroller: NO]; + [scrollView setAutoresizingMask: NSViewHeightSizable|NSViewWidthSizable]; + [[window contentView] addSubview: scrollView]; + RELEASE(scrollView); + + mainRect.origin = NSMakePoint(0,0); + mainRect.size = [scrollView contentSize]; + objectsView = [[GormObjectsView alloc] initWithFrame: mainRect]; + [objectsView setAutoresizingMask: NSViewHeightSizable|NSViewWidthSizable]; + [scrollView setDocumentView: objectsView]; + } + return self; +} + +- (void) removeObject: (id)anObject +{ + [objectsView removeObject: anObject]; +} + +- (NSWindow*) window +{ + return window; +} + +- (BOOL) windowShouldClose: (NSWindow*)aWindow +{ + return [document documentShouldClose]; +} + +- (void) windowWillClose: (NSNotification*)aNotification +{ + [document documentWillClose]; +} +@end + diff --git a/IBInspector.m b/IBInspector.m new file mode 100644 index 00000000..f2934696 --- /dev/null +++ b/IBInspector.m @@ -0,0 +1,83 @@ +/* IBInspector.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Gorm.h" + + +NSString *IBInspectorDidModifyObjectNotification + = @"IBInspectorDidModifyObjectNotification"; +NSString *IBSelectionChangedNotification + = @"IBSelectionChangedNotification"; + +@implementation IBInspector + +- (void) dealloc +{ + [super dealloc]; +} + +- (id) init +{ + return self; +} + +- (id) object +{ + return object; +} + +- (void) ok: sender +{ +} + +- (NSButton*) okButton +{ + return okButton; +} + +- (void) revert: (id)sender +{ +} + +- (NSButton*) revertButton +{ + return revertButton; +} + +- (void) touch: (id)sender +{ + [window setDocumentEdited]; +} + +- (BOOL) wantsButtons +{ + return NO; +} + +- (NSWindow*) window +{ + return window; +} +@end + diff --git a/IBPalette.m b/IBPalette.m new file mode 100644 index 00000000..1be7a401 --- /dev/null +++ b/IBPalette.m @@ -0,0 +1,139 @@ +/* IBPalette.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Gorm.h" + +NSString *IBCellPboardType = @"IBCellPboardType"; +NSString *IBMenuPboardType = @"IBMenuPboardType"; +NSString *IBMenuCellPboardType = @"IBMenuCellPboardType"; +NSString *IBObjectPboardType = @"IBObjectPboardType"; +NSString *IBViewPboardType = @"IBViewPboardType"; +NSString *IBWindowPboardType = @"IBWindowPboardType"; + +@implementation IBPalette + +static NSMapTable *viewToObject = 0; +static NSMapTable *viewToType = 0; + ++ (void) initialize +{ + if (self == [IBPalette class]) + { + viewToObject = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 20); + viewToType = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 20); + } +} + ++ (id) objectForView: (NSView*)aView +{ + id obj = (id)NSMapGet(viewToObject, (void*)aView); + + if (obj == nil) + { + obj = aView; + } + return obj; +} + ++ (NSString*) typeForView: (NSView*)aView +{ + NSString *type = (NSString*)NSMapGet(viewToType, (void*)aView); + + if (type == nil) + { + type = IBViewPboardType; + } + return type; +} + +- (void) associateObject: (id)anObject + type: (NSString*)aType + with: (NSView*)aView +{ + NSMapInsert(viewToType, (void*)aView, (id)aType); + NSMapInsert(viewToObject, (void*)aView, (id)anObject); +} + +- (void) dealloc +{ + RELEASE(icon); + RELEASE(window); + [super dealloc]; +} + +- (void) finishInstantiate +{ +} + +- (id) init +{ + NSBundle *bundle; + NSDictionary *paletteInfo; + NSString *fileName; + + bundle = [NSBundle bundleForClass: [self class]]; + + fileName = [bundle pathForResource: @"palette" ofType: @"table"]; + paletteInfo = [[NSString stringWithContentsOfFile: fileName] + propertyListFromStringsFileFormat]; + + fileName = [paletteInfo objectForKey: @"Icon"]; + fileName = [bundle pathForImageResource: fileName]; + if (fileName == nil) + { + NSRunAlertPanel(NULL, @"Icon for palette is missing", + @"OK", NULL, NULL); + AUTORELEASE(self); + return nil; + } + icon = [[NSImage alloc] initWithContentsOfFile: fileName]; + + fileName = [paletteInfo objectForKey: @"NibFile"]; + if (fileName != nil && [fileName isEqual: @""] == NO) + { + if ([NSBundle loadNibNamed: fileName owner: self] == NO) + { + NSRunAlertPanel(NULL, @"Nib for palette would not load", + @"OK", NULL, NULL); + AUTORELEASE(self); + return nil; + } + } + + return self; +} + +- (NSImage*) paletteIcon +{ + return icon; +} + +- (NSWindow*) originalWindow +{ + return window; +} +@end + diff --git a/Implementation b/Implementation new file mode 100644 index 00000000..97431d0d --- /dev/null +++ b/Implementation @@ -0,0 +1,23 @@ + +Notes on implementation +======================= + + +The IB documentation on how object selection is managed and how editors and +inspectors are used is unclear ... so I've gone my own way. + +1. When a document is loaded, the document object creates an editor attached +to each top-level object in the user interface (NSMenu and NSWindow objects). + +These editors must be aware of their edited objects being clicked upon, and +clicking on one of these should cause the corresponding editor to become the +active editor. + +The active editor is responsible for handling selection of the edited object +(and any objects below it in the object hierarchy). Upon change of selection, +the editor is responsible for sending an IBSelectionChangedNotification with +the selection owner (normally the editor itsself) as the notification owner. + +The main application watches for these notifications in order to keep track +of who has the selection. + diff --git a/InfoPanel.m b/InfoPanel.m new file mode 100644 index 00000000..2ac6d1d5 --- /dev/null +++ b/InfoPanel.m @@ -0,0 +1,104 @@ +/* InfoPanel.m + * + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * Author: Richard Frith-Macdonald + * Date: 1999 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +@interface InfoPanel : NSPanel +{ + NSTextField *versionfield; + NSTextField *authorfield; + NSTextField *addressfield; +} +@end + +@implementation InfoPanel + +- (id) init +{ + NSRect contentRect = {{0, 0}, {380, 120}}; + NSRect versionRect = {{30, 75}, {320, 20}}; + NSRect authorRect = {{30, 50}, {320, 20}}; + NSRect addressRect = {{30, 25}, {320, 20}}; + NSFont *font; + unsigned int style = NSTitledWindowMask | NSClosableWindowMask; + + self = [super initWithContentRect: contentRect + styleMask: style + backing: NSBackingStoreRetained + defer: NO]; + if (self != nil) + { + [self setTitle: @"Info"]; + font = [NSFont systemFontOfSize: 10]; + + versionfield = [[NSTextField alloc] init]; + [versionfield setFrame: versionRect]; + [versionfield setFont: font]; + [versionfield setBezeled: NO]; + [versionfield setEditable: NO]; + [versionfield setSelectable: NO]; + [versionfield setAlignment: NSCenterTextAlignment]; + [versionfield setBackgroundColor: [NSColor lightGrayColor]]; + [versionfield setStringValue: + @"GNUstep Graphicsl Object Relationship Modeller v0.0 1999"]; + [[self contentView] addSubview: versionfield]; + + authorfield = [[NSTextField alloc] init]; + [authorfield setFrame: authorRect]; + [authorfield setFont: font]; + [authorfield setBezeled: NO]; + [authorfield setEditable: NO]; + [authorfield setSelectable: NO]; + [authorfield setAlignment: NSCenterTextAlignment]; + [authorfield setBackgroundColor: [NSColor lightGrayColor]]; + [authorfield setStringValue: @"by Richard Frith-Macdonald"]; + [[self contentView] addSubview: authorfield]; + + addressfield = [[NSTextField alloc] init]; + [addressfield setFrame: addressRect]; + [addressfield setFont: font]; + [addressfield setBezeled: NO]; + [addressfield setEditable: NO]; + [addressfield setSelectable: NO]; + [addressfield setAlignment: NSCenterTextAlignment]; + [addressfield setBackgroundColor: [NSColor lightGrayColor]]; + [addressfield setStringValue: @"http://www.gnustep.org"]; + [[self contentView] addSubview: addressfield]; + [self center]; + [self setFrameUsingName: @"Info"]; + [self setFrameAutosaveName: @"Info"]; + } + return self; +} + +- (void) dealloc +{ + [versionfield release]; + [authorfield release]; + [addressfield release]; + [super dealloc]; +} + +@end