apps-gorm/GormCore/GormObjectEditor.m
Gregory John Casamento 564893d37a Fix to prevent a problem in unarchiving from crashing the app.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@21134 72102866-910b-0410-8b05-ffd578937521
2005-04-21 03:04:08 +00:00

565 lines
13 KiB
Objective-C

/* GormObjectEditor.m
*
* Copyright (C) 1999,2002,2003,2004,2005 Free Software Foundation, Inc.
*
* Author: Gregory John Casamento <greg_casamento@yahoo.com>
* Date: 2002,2003,2004,2005
* Author: Richard Frith-Macdonald <richard@brainstrom.co.uk>
* 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"
#include "GormFunctions.h"
#include <InterfaceBuilder/IBObjectAdditions.h>
/*
* Method to return the image that should be used to display objects within
* the matrix containing the objects in a document.
*/
@interface NSObject (GormObjectAdditions)
@end
@implementation NSObject (GormObjectAdditions)
- (NSImage*) imageForViewer
{
static NSImage *image = nil;
if (image == nil)
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForImageResource: @"GormUnknown"];
image = [[NSImage alloc] initWithContentsOfFile: path];
}
return image;
}
- (NSString*) inspectorClassName
{
return @"GormObjectInspector";
}
- (NSString*) connectInspectorClassName
{
return @"GormConnectionInspector";
}
- (NSString*) sizeInspectorClassName
{
return @"GormNotApplicableInspector";
}
- (NSString*) helpInspectorClassName
{
return @"GormNotApplicableInspector";
}
- (NSString*) classInspectorClassName
{
return @"GormCustomClassInspector";
}
- (NSString*) editorClassName
{
return @"GormObjectEditor";
}
@end
@implementation GormObjectEditor
static NSMapTable *docMap = 0;
+ (void) initialize
{
if (self == [GormObjectEditor class])
{
docMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
2);
}
}
+ (id) editorForDocument: (id<IBDocuments>)aDocument
{
id editor = NSMapGet(docMap, (void*)aDocument);
if (editor == nil)
{
editor = [[self alloc] initWithObject: nil inDocument: aDocument];
AUTORELEASE(editor);
}
return editor;
}
+ (void) setEditor: (id)editor
forDocument: (id<IBDocuments>)aDocument
{
NSMapInsert(docMap, (void*)aDocument, (void*)editor);
}
- (BOOL) acceptsTypeFromArray: (NSArray*)types
{
NSArray *resourceTypes = [resourceManager resourcePasteboardTypes];
return ([resourceTypes firstObjectCommonWithArray: types] != nil);
}
- (void) pasteInSelection
{
// not implemented
}
- (void) copySelection
{
// not implemented
}
- (void) deleteSelection
{
if (selected != nil
&& [[document nameForObject: selected] isEqualToString: @"NSOwner"] == NO
&& [[document nameForObject: selected] isEqualToString: @"NSFirst"] == NO)
{
NSNotificationCenter *nc;
nc = [NSNotificationCenter defaultCenter];
if ([selected isKindOfClass: [NSMenu class]] &&
[[document nameForObject: selected] isEqual: @"NSMenu"] == YES)
{
NSString *title = _(@"Removing Main Menu");
NSString *msg = _(@"Are you sure you want to do this?");
int retval = NSRunAlertPanel(title, msg,_(@"OK"),_(@"Cancel"), nil, nil);
// if the user *really* wants to delete the menu, do it.
if(retval != NSAlertDefaultReturn)
return;
}
[document detachObject: selected];
if ([selected isKindOfClass: [NSWindow class]] == YES)
{
NSArray *subviews = allSubviews([(NSWindow *)selected contentView]);
[document detachObjects: subviews];
[selected close];
}
if ([selected isKindOfClass: [NSMenu class]] == YES)
{
NSArray *items = findAll( selected );
NSEnumerator *en = [items objectEnumerator];
id obj = nil;
while((obj = [en nextObject]) != nil)
{
[document detachObject: obj];
}
}
[objects removeObjectIdenticalTo: selected];
[self selectObjects: [NSArray array]];
[self refreshCells];
}
}
- (void) removeAllInstancesOfClass: (NSString *)className
{
GormClassManager *classManager = [(GormDocument *)document classManager];
NSMutableArray *removedObjects = [NSMutableArray array];
NSEnumerator *en = [objects objectEnumerator];
id object = nil;
// locate objects for removal
while((object = [en nextObject]) != nil)
{
NSString *clsForObj = [classManager classNameForObject: object];
if([className isEqual: clsForObj])
{
[removedObjects addObject: object];
}
}
// remove the objects
[document detachObjects: removedObjects];
}
/*
* Dragging source protocol implementation
*/
- (void) draggedImage: (NSImage*)i endedAt: (NSPoint)p deposited: (BOOL)f
{
}
- (unsigned) draggingEntered: (id<NSDraggingInfo>)sender
{
NSArray *pbTypes = nil;
NSString *type = nil;
NSArray *mgrTypes = nil;
// Get the resource manager first, if nil don't bother calling the rest...
dragPb = [sender draggingPasteboard];
pbTypes = [dragPb types];
resourceManager = [(GormDocument *)document resourceManagerForPasteboard: dragPb];
if(resourceManager != nil)
{
mgrTypes = [resourceManager resourcePasteboardTypes];
type = [mgrTypes firstObjectCommonWithArray: pbTypes];
}
if (type != nil)
{
dragType = type;
}
else if ([pbTypes containsObject: GormLinkPboardType] == YES)
{
dragType = GormLinkPboardType;
}
else
{
dragType = nil;
}
return [self draggingUpdated: sender];
}
- (unsigned) draggingUpdated: (id<NSDraggingInfo>)sender
{
if ([[resourceManager resourcePasteboardTypes] containsObject: dragType])
{
return NSDragOperationCopy;
}
else if (dragType == GormLinkPboardType)
{
NSPoint loc = [sender draggingLocation];
int r, c;
int pos;
id obj = nil;
loc = [self convertPoint: loc fromView: nil];
[self getRow: &r column: &c forPoint: loc];
pos = r * [self numberOfColumns] + c;
if (pos >= 0 && pos < [objects count])
{
obj = [objects objectAtIndex: pos];
}
if (obj == [NSApp connectSource])
{
return NSDragOperationNone; /* Can't drag an object onto itsself */
}
[NSApp displayConnectionBetween: [NSApp connectSource] and: obj];
if (obj != nil)
{
return NSDragOperationLink;
}
return NSDragOperationNone;
}
return NSDragOperationNone;
}
- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)flag
{
return NSDragOperationLink;
}
- (void) drawSelection
{
}
- (void) _registerForAllResourceManagers
{
NSMutableArray *allTypes = [[NSMutableArray alloc] initWithObjects: GormLinkPboardType, nil];
NSArray *mgrs = [(GormDocument *)document resourceManagers];
NSEnumerator *en = [mgrs objectEnumerator];
IBResourceManager *mgr = nil;
AUTORELEASE(allTypes);
while((mgr = [en nextObject]) != nil)
{
NSArray *pbTypes = [mgr resourcePasteboardTypes];
[allTypes addObjectsFromArray: pbTypes];
}
[self registerForDraggedTypes: allTypes];
}
- (void) handleNotification: (NSNotification*)aNotification
{
NSString *name = [aNotification name];
if([name isEqual: GormResizeCellNotification])
{
NSDebugLog(@"Recieved notification");
[self setCellSize: defaultCellSize()];
}
else if([name isEqual: IBResourceManagerRegistryDidChangeNotification])
{
[self _registerForAllResourceManagers];
}
}
/*
* Initialisation - register to receive DnD with our own types.
*/
- (id) initWithObject: (id)anObject inDocument: (id<IBDocuments>)aDocument
{
id old = NSMapGet(docMap, (void*)aDocument);
if (old != nil)
{
RELEASE(self);
self = RETAIN(old);
[self addObject: anObject];
return self;
}
self = [super initWithObject: anObject inDocument: aDocument];
if (self != nil)
{
NSButtonCell *proto;
document = aDocument;
[self _registerForAllResourceManagers];
// [self registerForDraggedTypes: [NSArray arrayWithObjects:
// IBObjectPboardType, GormLinkPboardType, nil]];
[self setAutosizesCells: NO];
[self setCellSize: defaultCellSize()];
[self setIntercellSpacing: NSMakeSize(8,8)];
[self setAutoresizingMask: NSViewMinYMargin|NSViewWidthSizable];
[self setMode: NSRadioModeMatrix];
/*
* Send mouse click actions to self, so we can handle selection.
*/
[self setAction: @selector(changeSelection:)];
[self setDoubleAction: @selector(raiseSelection:)];
[self setTarget: self];
objects = [NSMutableArray new];
proto = [NSButtonCell new];
[proto setBordered: NO];
[proto setAlignment: NSCenterTextAlignment];
[proto setImagePosition: NSImageAbove];
[proto setSelectable: NO];
[proto setEditable: NO];
[self setPrototype: proto];
RELEASE(proto);
[self setEditor: self
forDocument: aDocument];
[self addObject: anObject];
// set up the notification...
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(handleNotification:)
name: GormResizeCellNotification
object: nil];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(handleNotification:)
name: IBResourceManagerRegistryDidChangeNotification
object: nil];
}
return self;
}
- (void) close
{
[super close];
[[NSNotificationCenter defaultCenter] removeObserver: self];
NSMapRemove(docMap,document);
}
- (void) makeSelectionVisible: (BOOL)flag
{
if (flag == YES && selected != nil)
{
unsigned pos = [objects indexOfObjectIdenticalTo: selected];
int r = pos / [self numberOfColumns];
int c = pos % [self numberOfColumns];
[self selectCellAtRow: r column: c];
}
else
{
[self deselectAllCells];
}
[self displayIfNeeded];
[[self window] flushWindow];
}
- (void) mouseDown: (NSEvent*)theEvent
{
if ([theEvent modifierFlags] & NSControlKeyMask)
{
NSPoint loc = [theEvent locationInWindow];
NSString *name;
int r = 0, c = 0;
int pos = 0;
id obj = nil;
loc = [self convertPoint: loc fromView: nil];
[self getRow: &r column: &c forPoint: loc];
pos = r * [self numberOfColumns] + c;
if (pos >= 0 && pos < [objects count])
{
obj = [objects objectAtIndex: pos];
}
if (obj != nil && obj != selected)
{
[self selectObjects: [NSArray arrayWithObject: obj]];
[self makeSelectionVisible: YES];
}
name = [document nameForObject: obj];
if ([name isEqualToString: @"NSFirst"] == NO && name != nil)
{
NSPasteboard *pb;
pb = [NSPasteboard pasteboardWithName: NSDragPboard];
[pb declareTypes: [NSArray arrayWithObject: GormLinkPboardType]
owner: self];
[pb setString: name forType: GormLinkPboardType];
[NSApp displayConnectionBetween: obj and: nil];
[self dragImage: [NSApp linkImage]
at: loc
offset: NSZeroSize
event: theEvent
pasteboard: pb
source: self
slideBack: YES];
[self makeSelectionVisible: YES];
return;
}
}
[super mouseDown: theEvent];
}
- (BOOL) performDragOperation: (id<NSDraggingInfo>)sender
{
if ([[resourceManager resourcePasteboardTypes] containsObject: dragType])
{
[resourceManager addResourcesFromPasteboard: dragPb];
return YES;
}
else if (dragType == GormLinkPboardType)
{
NSPoint loc = [sender draggingLocation];
int r, c;
int pos;
id obj = nil;
loc = [self convertPoint: loc fromView: nil];
[self getRow: &r column: &c forPoint: loc];
pos = r * [self numberOfColumns] + c;
if (pos >= 0 && pos < [objects count])
{
obj = [objects objectAtIndex: pos];
}
if (obj == nil)
{
return NO;
}
else
{
[NSApp displayConnectionBetween: [NSApp connectSource] and: obj];
[NSApp startConnecting];
return YES;
}
}
else
{
NSLog(@"Drop with unrecognized type!");
return NO;
}
}
- (BOOL) prepareForDragOperation: (id<NSDraggingInfo>)sender
{
/*
* Tell the source that we will accept the drop if we can.
*/
if ([[resourceManager resourcePasteboardTypes] containsObject: dragType])
{
/*
* We can accept objects dropped anywhere.
*/
return YES;
}
else if (dragType == GormLinkPboardType)
{
NSPoint loc = [sender draggingLocation];
int r, c;
int pos;
id obj = nil;
loc = [self convertPoint: loc fromView: nil];
[self getRow: &r column: &c forPoint: loc];
pos = r * [self numberOfColumns] + c;
if (pos >= 0 && pos < [objects count])
{
obj = [objects objectAtIndex: pos];
}
if (obj != nil)
{
return YES;
}
}
return NO;
}
- (id) raiseSelection: (id)sender
{
id obj = [self changeSelection: sender];
id e;
if(obj != nil)
{
e = [document editorForObject: obj create: YES];
[e orderFront];
[e resetObject: obj];
}
return self;
}
- (void) resetObject: (id)anObject
{
NSString *name = [document nameForObject: anObject];
GormInspectorsManager *mgr = [(id<Gorm>)NSApp inspectorsManager];
if ([name isEqual: @"NSOwner"] == YES)
{
[mgr setClassInspector];
}
if ([name isEqual: @"NSFirst"] == YES)
{
[mgr setClassInspector];
}
}
@end