1/* GormMatrixEditor.m - Editor for matrices.
2 *
3 * Copyright (C) 2001 Free Software Foundation, Inc.
4 *
5 * Authors:	Adam Fedor <fedor@gnu.org>
6 *              Pierre-Yves Rivaille <pyrivail@ens-lyon.fr>
7 * Date:	Sep 2001
8 *              Aug 2002
9 *
10 * This file is part of GNUstep.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
25 */
26
27#include <InterfaceBuilder/IBObjectAdditions.h>
28#include <AppKit/AppKit.h>
29
30#include "GormPrivate.h"
31#include "GormImage.h"
32#include "GormViewEditor.h"
33#include "GormMatrixEditor.h"
34#include "GormViewWithSubviewsEditor.h"
35#include "GormPlacementInfo.h"
36#include "GormFontViewController.h"
37#include "GormViewKnobs.h"
38
39#define _EO ((NSMatrix*)_editedObject)
40
41@interface GormViewEditor (Private)
42- (void) _displayFrame: (NSRect) frame
43     withPlacementInfo: (GormPlacementInfo*)gpi;
44@end
45
46@implementation NSMatrix (IBObjectAdditions)
47- (NSString*) editorClassName
48{
49  return @"GormMatrixEditor";
50}
51@end
52
53@interface NSForm (GormAdditions)
54- (CGFloat) titleWidth;
55@end
56
57@implementation NSForm (GormAdditions)
58
59- (CGFloat)titleWidth
60{
61  NSInteger i, count = [self numberOfRows];
62  float new_title_width = 0;
63  float candidate_title_width = 0;
64
65  // Compute max of title width in the cells
66  for (i = 0; i < count; i++)
67    {
68      candidate_title_width = [_cells[i][0] titleWidth];
69      if (candidate_title_width > new_title_width)
70	new_title_width = candidate_title_width;
71    }
72  return new_title_width;
73}
74
75@end
76
77@implementation	GormMatrixEditor
78
79- (void) copySelection
80{
81  if (selected != nil)
82    {
83      [document copyObjects: [self selection]
84		       type: IBViewPboardType
85	       toPasteboard: [NSPasteboard generalPasteboard]];
86    }
87}
88
89- (void) deleteSelection
90{
91  NSDebugLog(@"Cannot delete Matrix cell\n");
92}
93
94static BOOL done_editing;
95
96- (void) handleNotification: (NSNotification*)aNotification
97{
98  NSString	*name = [aNotification name];
99  if ([name isEqual: NSControlTextDidEndEditingNotification] == YES)
100    {
101      done_editing = YES;
102    }
103  else
104    NSLog(@"GormMatrixEditor got unhandled notification %@", name);
105}
106
107
108/*
109 *	Initialisation
110 */
111- (id) initWithObject: (id)anObject inDocument: (id<IBDocuments>)aDocument
112{
113  NSMutableArray *draggedTypes = [NSMutableArray array];
114
115  opened = NO;
116  selected = nil;
117  selectedCol = -1;
118  selectedRow = -1;
119  _displaySelection = YES;
120  self = [super initWithObject: anObject
121		inDocument: aDocument];
122
123  // dragged types...
124  [draggedTypes addObject: GormImagePboardType];
125  [draggedTypes addObject: GormLinkPboardType];
126  [draggedTypes addObject: GormSoundPboardType];
127
128  // register...
129  [self registerForDraggedTypes: draggedTypes];
130
131  return self;
132}
133
134/* Called when we double-click on a text/editable cell or form. Overlay
135   a text field so the user can edit the title. */
136- (void) editTitleWithEvent: (NSEvent *)theEvent
137{
138  NSInteger row, col;
139  unsigned eventMask;
140  id edit_view;
141  BOOL isForm;
142  NSRect                 frame;
143  NSTextField           *editField;
144  NSDate		*future = [NSDate distantFuture];
145  NSNotificationCenter  *nc = [NSNotificationCenter defaultCenter];
146
147  isForm = [_EO isKindOfClass: [NSForm class]];
148  if (isForm == NO && [selected type] != NSTextCellType)
149    return;
150
151  // get the superview we are to edit from.
152  edit_view = [_EO superview];
153
154  [_EO getRow: &row column: &col ofCell: selected];
155  frame = [_EO cellFrameAtRow: row column: col];
156  frame.origin.x += NSMinX([_EO frame]);
157  if (isForm)
158    frame.size.width = [(NSForm *)_EO titleWidth];
159  else
160    frame = [selected titleRectForBounds: frame];
161  if ([_EO isFlipped])
162    {
163      frame.origin.y = NSMaxY([_EO frame]) - NSMaxY(frame);
164    }
165  else
166    {
167      frame.origin.y = NSMinY([_EO frame]) + NSMinY(frame);
168    }
169
170  /* Now create an edit field and allow the user to edit the text */
171  editField = [[NSTextField alloc] initWithFrame: frame];
172  [editField setEditable: YES];
173  [editField setSelectable: YES];
174  [editField setBezeled: NO];
175  [editField setEnabled: YES];
176  if (isForm)
177    [editField setStringValue: [(NSFormCell *)selected title]];
178  else
179    [editField setStringValue: [selected stringValue]];
180  [edit_view addSubview: editField];
181  // [edit_view displayRect: frame];
182  [edit_view display];
183  [[edit_view window] flushWindow];
184  [nc addObserver: self
185         selector: @selector(handleNotification:)
186             name: NSControlTextDidEndEditingNotification
187           object: nil];
188
189  /* Do some modal editing */
190  [editField selectText: self];
191  eventMask = NSLeftMouseDownMask |  NSLeftMouseUpMask  |
192  NSKeyDownMask  |  NSKeyUpMask  | NSFlagsChangedMask;
193
194  done_editing = NO;
195  while (!done_editing)
196    {
197      NSEvent *e;
198      NSEventType eType;
199      e = [NSApp nextEventMatchingMask: eventMask
200		 untilDate: future
201		 inMode: NSEventTrackingRunLoopMode
202		 dequeue: YES];
203      eType = [e type];
204      switch (eType)
205	{
206	case NSLeftMouseDown:
207	  {
208	    NSPoint dp =  [edit_view convertPoint: [e locationInWindow]
209				fromView: nil];
210	    if (NSMouseInRect(dp, frame, NO) == NO)
211	      {
212		done_editing = YES;
213		break;
214	      }
215	  }
216	  [[editField currentEditor] mouseDown: e];
217	  break;
218	case NSLeftMouseUp:
219	  [[editField currentEditor] mouseUp: e];
220	  break;
221	case NSLeftMouseDragged:
222	  [[editField currentEditor] mouseDragged: e];
223	  break;
224	case NSKeyDown:
225	  [[editField currentEditor] keyDown: e];
226	  break;
227	case NSKeyUp:
228	  [[editField currentEditor] keyUp: e];
229	  break;
230	case NSFlagsChanged:
231	  [[editField currentEditor] flagsChanged: e];
232	  break;
233	default:
234	  NSLog(@"Internal Error: Unhandled event during editing: %@", e);
235	  break;
236	}
237    }
238
239  [nc removeObserver: self
240                name: NSControlTextDidEndEditingNotification
241              object: nil];
242
243  [self makeSelectionVisible: NO];
244  if (isForm)
245    {
246      /* Set the new title and resize the form to match the titles */
247      CGFloat oldTitleWidth, titleWidth;
248      NSRect oldFrame;
249      oldTitleWidth = [(NSForm *)_EO titleWidth];
250      [(NSFormCell *)selected setTitle: [editField stringValue]];
251      [(NSForm *)_EO calcSize];
252      titleWidth = [(NSForm *)_EO titleWidth];
253      oldFrame = frame = [_EO frame];
254      frame.origin.x -= (titleWidth - oldTitleWidth);
255      frame.size.width += (titleWidth - oldTitleWidth);
256      [(NSForm *)_EO setEntryWidth: NSWidth(frame)];
257      [(NSForm *)_EO setFrame: frame];
258      frame = NSUnionRect(frame, oldFrame);
259    }
260  else
261    [selected setStringValue: [editField stringValue]];
262
263  [edit_view removeSubview: editField];
264  [edit_view displayRect: frame];
265  [self makeSelectionVisible: YES];
266
267  RELEASE(editField);
268}
269
270- (BOOL) canBeOpened
271{
272  return YES;
273}
274
275- (void) setOpened: (BOOL) value
276{
277  if (value)
278    {
279      opened = YES;
280    }
281  else
282    {
283      opened = NO;
284      selected = nil;
285      selectedCol = -1;
286      selectedRow = -1;
287    }
288}
289
290- (void) mouseDown: (NSEvent *)theEvent
291{
292  BOOL onKnob = NO;
293
294  {
295    if ([[parent selection] containsObject: _EO])
296      {
297	IBKnobPosition	knob = IBNoneKnobPosition;
298	NSPoint mouseDownPoint =
299	  [self convertPoint: [theEvent locationInWindow]
300		fromView: nil];
301	knob = GormKnobHitInRect([self bounds],
302				 mouseDownPoint);
303	if (knob != IBNoneKnobPosition)
304	  onKnob = YES;
305      }
306    if (onKnob == YES)
307      {
308	if (_next_responder)
309	  return [_next_responder mouseDown: theEvent];
310	else
311	  return [self noResponderFor: @selector(mouseDown:)];
312      }
313  }
314
315  if (opened == NO)
316    {
317      [super mouseDown: theEvent];
318      return;
319    }
320
321
322  {
323    NSInteger row, col;
324    NSPoint mouseDownPoint =
325      [_EO
326	convertPoint: [theEvent locationInWindow]
327	fromView: nil];
328
329    if ([_EO
330	  getRow: &row
331	  column: &col
332	  forPoint: mouseDownPoint] == YES)
333      {
334	selectedRow = row;
335	selectedCol = col;
336	selected = [_EO cellAtRow: row
337				  column: col];
338
339	[document setSelectionFromEditor: self];
340	if (selected != nil && ([theEvent clickCount] == 2) )
341	  {
342	    [self editTitleWithEvent: theEvent];
343	    return;
344	  }
345
346	[self setNeedsDisplay: YES];
347      }
348    else
349      {
350	selected = nil;
351	selectedRow = -1;
352	selectedCol = -1;
353	[document setSelectionFromEditor: self];
354      }
355  }
356}
357
358- (void) makeSelectionVisible: (BOOL)flag
359{
360  if (selected != nil)
361    {
362      NSInteger row, col;
363      if ([_EO getRow: &row column: &col ofCell: selected])
364	{
365	  NSRect frame = [_EO cellFrameAtRow: row column: col];
366	  if (flag == YES)
367	    [_EO selectCellAtRow: row column: col];
368	  [_EO lockFocus];
369	  [[NSColor controlShadowColor] set];
370	  NSHighlightRect(frame);
371	  [_EO unlockFocus];
372	}
373    }
374  else
375    {
376      [_EO deselectAllCells];
377    }
378  [_EO display];
379  [[_EO window] flushWindow];
380}
381
382
383- (void) selectObjects: (NSArray*)anArray
384{
385  id	obj = [anArray lastObject];
386  [self makeSelectionVisible: NO];
387  selected = obj;
388  [document setSelectionFromEditor: self];
389  [self makeSelectionVisible: YES];
390}
391
392- (NSArray*) selection
393{
394  if (selected == nil)
395    return [NSArray arrayWithObject: _EO];
396  else
397    return [NSArray arrayWithObject: selected];
398}
399
400- (BOOL) acceptsTypeFromArray: (NSArray*)types
401{
402  return ([types containsObject: IBObjectPboardType] || [types containsObject: GormImagePboardType]);
403}
404
405- (void) postDraw: (NSRect) rect
406{
407  if (_displaySelection)
408    {
409      if ((selectedRow != -1) && (selectedCol != -1))
410	{
411	  NSDebugLog(@"highlighting %@",
412		NSStringFromRect([_EO
413				       cellFrameAtRow: selectedRow
414				       column: selectedCol]));
415	  [[NSColor blackColor] set];
416	  NSHighlightRect([_EO
417			    convertRect:
418			      [_EO
419					   cellFrameAtRow: selectedRow
420					   column: selectedCol]
421			    toView: self]);
422
423	}
424    }
425}
426
427- (NSRect) _constrainedFrame: (NSRect) frame
428		   withEvent: (NSEvent *)theEvent
429		     andKnob: (IBKnobPosition) knob
430{
431  NSInteger width;
432  NSInteger height;
433
434  if ([theEvent modifierFlags] & NSAlternateKeyMask)
435    {
436      NSInteger rows = [_EO numberOfRows];
437      NSInteger cols = [_EO numberOfColumns];
438      NSSize interSize = [_EO intercellSpacing];
439
440      NSInteger colWidth = ([_EO frame].size.width -
441		      (cols - 1) * interSize.width) / cols;
442      NSInteger rowHeight = ([_EO frame].size.height -
443		       (rows - 1) * interSize.height) / rows;
444
445      NSInteger widthIncrement = colWidth + interSize.width;
446      NSInteger heightIncrement = rowHeight + interSize.height;
447
448      if (frame.size.width < colWidth)
449	{
450	  width = colWidth;
451	  rows = 1;
452	}
453      else
454	{
455	  width = frame.size.width - [_EO frame].size.width;
456	  rows = width / widthIncrement;
457	  width = rows * widthIncrement + [_EO frame].size.width;
458	}
459
460      if (frame.size.height < rowHeight)
461	{
462	  height = rowHeight;
463	  cols = 1;
464	}
465      else
466	{
467	  height = frame.size.height - [_EO frame].size.height;
468	  cols = height / heightIncrement;
469	  height = cols * heightIncrement + [_EO frame].size.height;
470	}
471    }
472  else if ([theEvent modifierFlags] & NSControlKeyMask)
473    {
474      NSInteger rows = [_EO numberOfRows];
475      NSInteger cols = [_EO numberOfColumns];
476      NSSize cellSize = [_EO cellSize];
477
478      height = width = 0;
479      if (cols > 1)
480	width = ( frame.size.width - cellSize.width * cols) / (cols - 1);
481      if (rows > 1)
482	height = ( frame.size.height - cellSize.height * rows ) / (rows - 1);
483
484      width *= (cols - 1);
485      width += cellSize.width * cols;
486      height *= (rows - 1);
487      height += cellSize.height * rows;
488    }
489  else
490    {
491      NSInteger rows = [_EO numberOfRows];
492      NSInteger cols = [_EO numberOfColumns];
493      NSSize interSize = [_EO intercellSpacing];
494
495      width = ( frame.size.width - interSize.width * (cols - 1) ) /  cols;
496      width *= cols;
497      width += (interSize.width * (cols - 1));
498
499      height = ( frame.size.height - interSize.height * (rows - 1) ) /  rows;
500      height *= rows;
501      height += (interSize.height * (rows - 1));
502    }
503
504  switch (knob)
505    {
506    case IBBottomLeftKnobPosition:
507    case IBMiddleLeftKnobPosition:
508    case IBTopLeftKnobPosition:
509      frame.origin.x = NSMaxX(frame) - width;
510      frame.size.width = width;
511      break;
512    case IBTopRightKnobPosition:
513    case IBMiddleRightKnobPosition:
514    case IBBottomRightKnobPosition:
515      frame.size.width = width;
516      break;
517    case IBTopMiddleKnobPosition:
518    case IBBottomMiddleKnobPosition:
519    case IBNoneKnobPosition:
520      break;
521    }
522
523
524  switch (knob)
525    {
526    case IBBottomLeftKnobPosition:
527    case IBBottomRightKnobPosition:
528    case IBBottomMiddleKnobPosition:
529      frame.origin.y = NSMaxY(frame) - height;
530      frame.size.height = height;
531      break;
532    case IBTopMiddleKnobPosition:
533    case IBTopRightKnobPosition:
534    case IBTopLeftKnobPosition:
535      frame.size.height = height;
536      break;
537    case IBMiddleLeftKnobPosition:
538    case IBMiddleRightKnobPosition:
539    case IBNoneKnobPosition:
540      break;
541    }
542
543  return frame;
544}
545
546
547- (void) updateResizingWithFrame: (NSRect) frame
548			andEvent: (NSEvent *)theEvent
549		andPlacementInfo: (GormPlacementInfo*) gpi
550{
551  gpi->lastFrame = [self _constrainedFrame: frame
552		    withEvent: theEvent
553		    andKnob: gpi->knob];
554
555  [self _displayFrame: gpi->lastFrame
556	withPlacementInfo: gpi];
557}
558
559
560
561- (void) validateFrame: (NSRect) frame
562	     withEvent: (NSEvent *) theEvent
563      andPlacementInfo: (GormPlacementInfo*)gpi
564{
565  frame = gpi->lastFrame;
566
567  if ([theEvent modifierFlags] & (NSControlKeyMask | NSShiftKeyMask))
568    {
569      NSInteger rows = [_EO numberOfRows];
570      NSInteger cols = [_EO numberOfColumns];
571      NSSize interSize = [_EO intercellSpacing];
572
573      NSInteger colWidth = ([_EO frame].size.width -
574		      (cols - 1) * interSize.width) / cols;
575      NSInteger rowHeight = ([_EO frame].size.height -
576		       (rows - 1) * interSize.height) / rows;
577
578      NSInteger widthIncrement = colWidth + interSize.width;
579      NSInteger heightIncrement = rowHeight + interSize.height;
580
581      NSInteger newCols = (frame.size.width - [_EO frame].size.width) /
582	widthIncrement;
583      NSInteger newRows = (frame.size.height - [_EO frame].size.height) /
584	heightIncrement;
585
586      NSInteger i, j;
587
588      if (newCols > 0)
589	{
590	  for (j = cols; j < cols + newCols; j++)
591	    {
592	      [_EO addColumn];
593	      for (i = 0; i < rows; i++)
594		{
595		  [document attachObject: [_EO cellAtRow: i column: j]
596				toParent: _EO];
597		}
598	    }
599	}
600      else if (newCols < 0)
601	{
602	  for (j = cols - 1; j >= cols - newCols; j--)
603	    {
604	      for (i = 0; i < rows; i++)
605		{
606		  [document detachObject: [_EO cellAtRow: i column: j]];
607		}
608	      [_EO removeColumn: j];
609	    }
610	}
611
612      if (newRows > 0)
613	{
614	  for (i = rows; i < rows + newRows; i++)
615	    {
616	      [_EO addRow];
617	      for (j = 0; j < cols + newCols; j++)
618		{
619		  [document attachObject: [_EO cellAtRow: i column: j]
620				toParent: _EO];
621		}
622	    }
623	}
624      else if (newRows < 0)
625	{
626	  for (i = rows - 1; i >= rows + newRows; i--)
627	    {
628	      for (j = 0; j < cols + newCols; j++)
629		{
630		  [document detachObject: [_EO cellAtRow: i column: j]];
631		}
632	      [_EO removeRow: i];
633	    }
634	}
635      [_EO setFrame: frame];
636    }
637  else if ([theEvent modifierFlags] & NSControlKeyMask)
638    {
639      NSInteger width;
640      NSInteger height;
641      NSInteger rows = [_EO numberOfRows];
642      NSInteger cols = [_EO numberOfColumns];
643      NSSize cellSize = [_EO cellSize];
644
645
646      [self setFrame: frame];
647
648
649      height = width = 0;
650      if (cols > 1)
651	width = ( frame.size.width - cellSize.width * cols) / (cols - 1);
652      if (rows > 1)
653	height = ( frame.size.height - cellSize.height * rows ) / (rows - 1);
654
655      [_EO setIntercellSpacing: NSMakeSize(width, height)];
656    }
657  else
658    {
659      NSInteger width;
660      NSInteger height;
661      NSInteger rows = [_EO numberOfRows];
662      NSInteger cols = [_EO numberOfColumns];
663      NSSize interSize = [_EO intercellSpacing];
664
665
666      [self setFrame: frame];
667
668
669      width = ( frame.size.width - interSize.width * (cols - 1) ) /  cols;
670      height = ( frame.size.height - interSize.height * (rows - 1) ) /  rows;
671
672      [_EO setCellSize: NSMakeSize(width, height)];
673    }
674}
675
676- (void) changeFont: (id)sender
677{
678  NSEnumerator *enumerator = [[self selection] objectEnumerator];
679  id anObject;
680  NSFont *newFont;
681
682  NSDebugLog(@"In %@ changing font for %@",[self className],[self selection]);
683  while ((anObject = [enumerator nextObject]))
684    {
685      if([anObject respondsToSelector: @selector(setTitleFont:)] &&
686	 [anObject respondsToSelector: @selector(setTextFont:)])
687	{
688	  newFont = [sender convertFont: [anObject font]];
689	  newFont = [[GormFontViewController sharedGormFontViewController]
690		      convertFont: newFont];
691	  [anObject setTitleFont: newFont];
692	  [anObject setTextFont: newFont];
693	}
694      else if ([anObject respondsToSelector: @selector(font)] &&
695	       [anObject respondsToSelector: @selector(setFont:)])
696	{
697	  newFont = [sender convertFont: [anObject font]];
698	  newFont = [[GormFontViewController sharedGormFontViewController]
699		      convertFont: newFont];
700	  [anObject setFont: newFont];
701	}
702    }
703
704  return;
705}
706
707- (id) connectTargetAtPoint: (NSPoint)mouseLoc
708{
709  NSInteger row, col;
710
711  if ([_EO getRow: &row column: &col forPoint: mouseLoc] == YES)
712    {
713      /* If a matrix has small intercell spacing (less than 1 pixel), it
714	 becomes impossible to make connections to the whole matrix, since
715	 -getRow:column:forPoint: returns YES for every location within the
716	 matrix's bounds. Therefore, we accept connection to matrix cells
717	 only if the mouse is strictly inside the cell. */
718      NSRect cellFrame = [_EO cellFrameAtRow: row column: col];
719
720      if (mouseLoc.x != NSMinX(cellFrame) &&
721	  mouseLoc.x != NSMaxX(cellFrame) &&
722	  mouseLoc.y != NSMinY(cellFrame) &&
723	  mouseLoc.y != NSMaxY(cellFrame))
724	{
725	  return [_EO cellAtRow: row column: col];
726	}
727    }
728
729  return _EO;
730}
731
732- (NSDragOperation) draggingEntered: (id<NSDraggingInfo>)sender
733{
734  NSPasteboard *dragPb;
735  NSArray      *types;
736
737  dragPb = [sender draggingPasteboard];
738  types = [dragPb types];
739  if ([types containsObject: GormLinkPboardType] == YES)
740    {
741      NSPoint loc = [sender draggingLocation];
742      NSPoint mouseDownPoint = [_EO convertPoint: loc fromView: nil];
743
744      [NSApp displayConnectionBetween: [NSApp connectSource]
745	     and: [self connectTargetAtPoint: mouseDownPoint]];
746      return NSDragOperationLink;
747    }
748  return [super draggingEntered: sender];
749}
750
751- (BOOL) performDragOperation: (id<NSDraggingInfo>)sender
752{
753  NSPasteboard	*dragPb;
754  NSArray	*types;
755  NSPoint       dropPoint = [sender draggedImageLocation];
756  NSPoint       mouseDownPoint = [_EO convertPoint: dropPoint fromView: nil];
757
758  dragPb = [sender draggingPasteboard];
759  types = [dragPb types];
760
761  if ([types containsObject: GormLinkPboardType])
762    {
763      [NSApp displayConnectionBetween: [NSApp connectSource]
764             and: [self connectTargetAtPoint: mouseDownPoint]];
765      [NSApp startConnecting];
766    }
767  else if ([types containsObject: GormImagePboardType] == YES ||
768	   [types containsObject: GormSoundPboardType] == YES)
769    {
770      NSInteger row, col;
771      if ([_EO getRow: &row column: &col forPoint: mouseDownPoint] == YES)
772	{
773	  id object = [_EO cellAtRow: row column: col];
774	  if ([types containsObject: GormImagePboardType] == YES)
775	    {
776	      NSString *name = [dragPb stringForType: GormImagePboardType];
777	      NSImage *image = [NSImage imageNamed: name];
778	      [image setArchiveByName: NO];
779	      if ([object respondsToSelector: @selector(setSound:)])
780		{
781		  [object setImage: image];
782		}
783	      else
784		{
785		  return NO;
786		}
787
788	      return YES;
789	    }
790	  else if ([types containsObject: GormSoundPboardType] == YES)
791	    {
792	      NSString *name;
793	      name = [dragPb stringForType: GormSoundPboardType];
794	      if ([object respondsToSelector: @selector(setSound:)])
795		{
796		  [object setSound: [NSSound soundNamed: name]];
797		}
798	      else
799		{
800		  return NO;
801		}
802
803	      return YES;
804	    }
805	}
806    }
807
808  return NO;
809}
810
811@end
812
813
814
815