1/*
2   NSToolbarItem.m
3
4   The Toolbar item class.
5
6   Copyright (C) 2002 Free Software Foundation, Inc.
7
8   Author:  Gregory John Casamento <greg_casamento@yahoo.com>,
9            Fabien Vallon <fabien.vallon@fr.alcove.com>,
10            Quentin Mathe <qmathe@club-internet.fr>
11   Date: May 2002
12
13   This file is part of the GNUstep GUI Library.
14
15   This library is free software; you can redistribute it and/or
16   modify it under the terms of the GNU Lesser General Public
17   License as published by the Free Software Foundation; either
18   version 2 of the License, or (at your option) any later version.
19
20   This library is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
23   Lesser General Public License for more details.
24
25   You should have received a copy of the GNU Lesser General Public
26   License along with this library; see the file COPYING.LIB.
27   If not, see <http://www.gnu.org/licenses/> or write to the
28   Free Software Foundation, 51 Franklin Street, Fifth Floor,
29   Boston, MA 02110-1301, USA.
30*/
31
32#import <Foundation/NSObject.h>
33#import <Foundation/NSArray.h>
34#import <Foundation/NSArchiver.h>
35#import <Foundation/NSDictionary.h>
36#import <Foundation/NSString.h>
37#import "AppKit/NSApplication.h"
38#import "AppKit/NSAttributedString.h"
39#import "AppKit/NSButton.h"
40#import "AppKit/NSButtonCell.h"
41#import "AppKit/NSDragging.h"
42#import "AppKit/NSEvent.h"
43#import "AppKit/NSFont.h"
44#import "AppKit/NSImage.h"
45#import "AppKit/NSMenu.h"
46#import "AppKit/NSMenuItem.h"
47#import "AppKit/NSParagraphStyle.h"
48#import "AppKit/NSPasteboard.h"
49#import "AppKit/NSStringDrawing.h"
50#import "AppKit/NSToolbar.h"
51#import "AppKit/NSView.h"
52#import "GNUstepGUI/GSToolbarView.h"
53#import "AppKit/NSToolbarItem.h"
54
55#import "NSToolbarFrameworkPrivate.h"
56#import "GSGuiPrivate.h"
57
58/*
59 * Each NSToolbarItem object are coupled with a backView which is their
60 * representation on the screen.
61 * backView for the standard toolbar item (without custom view) are NSButton
62 * subclass called GSToolbarButton.
63 * backView for the toolbar item with a custom view are NSView subclass called
64 * GSToolbarBackView.
65 * GSToolbarButton and GSToolbarBackView are adjusted according to their content
66 * and their title when the method layout is called.
67 * The predefined GNUstep toolbar items are implemented with a class cluster
68 * pattern: initWithToolbarItemIdentifier: returns differents concrete subclass
69 * in accordance with the item identifier.
70 */
71
72typedef enum {
73  ItemBackViewDefaultHeight = 60,
74  ItemBackViewRegularHeight = 60,
75  ItemBackViewSmallHeight = 50
76} ItemBackViewHeight;
77
78typedef enum {
79  ItemBackViewDefaultWidth = 60,
80  ItemBackViewRegularWidth = 60,
81  ItemBackViewSmallWidth = 50
82} ItemBackViewWidth;
83
84static const int ItemBackViewX = 0;
85static const int ItemBackViewY = 0;
86static const int InsetItemViewX = 10;
87static const int InsetItemViewY = 26;
88static const int InsetItemTextX = 3;
89static const int InsetItemTextY = 4;
90
91// See NSToolbarItem -initialize method
92static NSFont *NormalFont = nil;
93static NSFont *SmallFont = nil;
94
95NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
96
97/*
98 * NSButton subclass is the toolbar buttons _backView
99 */
100@interface GSToolbarButton : NSButton
101{
102  NSToolbarItem *_toolbarItem;
103}
104
105- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem;
106- (void) layout;
107
108// Accessors
109- (NSToolbarItem *) toolbarItem;
110@end
111
112@interface GSToolbarButtonCell : NSButtonCell
113{
114  NSRect titleRect;
115  NSRect imageRect;
116}
117
118@end
119
120// ---
121
122@implementation GSToolbarButton
123
124+ (Class) cellClass
125{
126  return [GSToolbarButtonCell class];
127}
128
129- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem
130{
131  // Frame will be reset by the layout method
132  self = [super initWithFrame: NSMakeRect(ItemBackViewX, ItemBackViewY,
133    ItemBackViewDefaultWidth, ItemBackViewDefaultHeight)];
134
135  if (self != nil)
136    {
137      // Don't do an ASSIGN here, the toolbar item itself retains us.
138      _toolbarItem = toolbarItem;
139
140      [self setTitle: @""];
141      [self setEnabled: NO];
142      [_cell setBezeled: YES];
143      [self setImagePosition: NSImageAbove];
144      [self setHighlightsBy:
145                NSChangeGrayCellMask | NSChangeBackgroundCellMask];
146      [self setFont: NormalFont];
147    }
148
149  return self;
150}
151
152/*
153 * The code below should be kept in sync with GSToolbarBackView methods which
154 * have identical names.
155 */
156
157- (void) layout
158{
159  float textWidth, layoutedWidth = -1, layoutedHeight = -1;
160  NSFont *font;
161  unsigned int borderMask = [[[_toolbarItem toolbar] _toolbarView] borderMask];
162  NSSize labelSize = NSZeroSize;
163
164  font = NormalFont;
165
166  // Adjust the layout in accordance with NSToolbarSizeMode
167  switch ([[_toolbarItem toolbar] sizeMode])
168    {
169      case NSToolbarSizeModeDefault:
170        layoutedWidth = ItemBackViewDefaultWidth;
171        layoutedHeight = ItemBackViewDefaultHeight;
172        [[_toolbarItem image] setSize: NSMakeSize(32, 32)];
173        break;
174      case NSToolbarSizeModeRegular:
175        layoutedWidth = ItemBackViewRegularWidth;
176        layoutedHeight = ItemBackViewRegularHeight;
177        [[_toolbarItem image] setSize: NSMakeSize(32, 32)];
178        break;
179      case NSToolbarSizeModeSmall:
180        layoutedWidth = ItemBackViewSmallWidth;
181        layoutedHeight = ItemBackViewSmallHeight;
182        /* Not use [self image] here because it can return nil, when image
183           position is set to NSNoImage. Even if NSToolbarDisplayModeTextOnly
184           is not true anymore -setImagePosition: is only called below, then
185           [self image] can still returns nil. */
186        [[_toolbarItem image] setSize: NSMakeSize(24, 24)];
187        font = SmallFont;
188        break;
189      default:
190        NSLog(@"Invalid NSToolbarSizeMode"); // Invalid
191    }
192
193  [self setFont: font];
194
195  // Adjust the layout in accordance with the border
196  if (!(borderMask & GSToolbarViewBottomBorder))
197    {
198      layoutedHeight++;
199      layoutedWidth++;
200    }
201
202  if (!(borderMask & GSToolbarViewTopBorder))
203    {
204      layoutedHeight++;
205      layoutedWidth++;
206    }
207
208  // Adjust the layout in accordance with the label
209  {
210    NSAttributedString *attrStr;
211    NSDictionary *attr;
212    NSString *label = [_toolbarItem label];
213
214    attr = [NSDictionary dictionaryWithObject: font forKey: NSFontAttributeName];
215    if (label == nil || [label isEqualToString: @""])
216      label = @"Dummy";
217    attrStr = [[NSAttributedString alloc] initWithString: label attributes: attr];
218    labelSize = [attrStr size];
219    DESTROY(attrStr);
220  }
221
222  textWidth = labelSize.width + 2 * InsetItemTextX;
223  if ([[_toolbarItem toolbar] displayMode] != NSToolbarDisplayModeIconOnly
224    && layoutedWidth != -1 && textWidth > layoutedWidth)
225     layoutedWidth = textWidth;
226
227  // Adjust the layout in accordance with NSToolbarDisplayMode
228  switch ([[_toolbarItem toolbar] displayMode])
229    {
230      case NSToolbarDisplayModeDefault:
231        [self setImagePosition: NSImageAbove];
232        break;
233      case NSToolbarDisplayModeIconAndLabel:
234        [self setImagePosition: NSImageAbove];
235        break;
236      case NSToolbarDisplayModeIconOnly:
237        [self setImagePosition: NSImageOnly];
238        layoutedHeight -= labelSize.height + InsetItemTextY;
239        break;
240      case NSToolbarDisplayModeLabelOnly:
241        [self setImagePosition: NSNoImage];
242        layoutedHeight = labelSize.height + InsetItemTextY * 2;
243        break;
244      default:
245        ; // Invalid
246    }
247
248  // Set the frame size to use the new layout
249  [self setFrameSize: NSMakeSize(layoutedWidth, layoutedHeight)];
250}
251
252- (void) mouseDown: (NSEvent *)event
253{
254  NSToolbar *toolbar = [_toolbarItem toolbar];
255
256  if (([event modifierFlags] == NSCommandKeyMask
257       && [toolbar allowsUserCustomization])
258      || [toolbar customizationPaletteIsRunning] || toolbar == nil)
259    {
260      NSSize viewSize = [self frame].size;
261      NSImage *image = [[NSImage alloc] initWithSize: viewSize];
262      NSCell *cell = [self cell];
263      NSPasteboard *pboard;
264      NSInteger index = NSNotFound;
265
266      // Prepare the drag
267
268      /* We need to keep this view (aka self) to be able to draw the drag
269         image. */
270      RETAIN(self);
271
272      // Draw the drag content in an image
273      /* The code below is only partially supported by GNUstep, then NSImage
274         needs to be improved. */
275      [image lockFocus];
276      [cell setShowsFirstResponder: NO]; // To remove the dotted rect
277      [cell drawWithFrame:
278                NSMakeRect(0, 0, viewSize.width, viewSize.height) inView: nil];
279      [cell setShowsFirstResponder: YES];
280      [image unlockFocus];
281
282      pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
283      [pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType]
284              owner: nil];
285      if (toolbar != nil)
286	{
287          index = [toolbar _indexOfItem: _toolbarItem];
288        }
289	  [GSToolbarView setDraggedItemIndex:index];
290      [pboard setString: [NSString stringWithFormat:@"%ld", (long) index]
291              forType: GSMovableToolbarItemPboardType];
292
293      [self dragImage: image
294            at: NSMakePoint(0.0, viewSize.height)
295            offset: NSMakeSize(0.0, 0.0)
296            event: event
297            pasteboard: pboard
298            source: self
299            slideBack: NO];
300      RELEASE(image);
301    }
302  else if ([event modifierFlags] != NSCommandKeyMask)
303    {
304      [super mouseDown: event];
305    }
306}
307
308- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
309{
310  //nothing to do
311}
312
313- (void) draggedImage: (NSImage *)dragImage
314              endedAt: (NSPoint)location
315            operation: (NSDragOperation)operation
316{
317  //nothing to do
318}
319
320- (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL)isLocal
321{
322  return isLocal ? NSDragOperationGeneric : NSDragOperationNone;
323}
324
325- (NSToolbarItem *) toolbarItem
326{
327  return _toolbarItem;
328}
329
330/*
331 * End of the code to keep in sync
332 */
333
334- (BOOL) sendAction: (SEL)action to: (id)target
335{
336  if ([_toolbarItem _selectable])
337    {
338      [[_toolbarItem toolbar]
339        setSelectedItemIdentifier: [_toolbarItem itemIdentifier]];
340    }
341
342  if (action)
343    {
344      // Send from toolbar item not self
345      return [NSApp sendAction: action
346                            to: target
347                          from: _toolbarItem];
348    }
349  else
350    {
351      return NO;
352    }
353}
354
355@end
356
357@implementation GSToolbarButtonCell
358
359/* Overriden NSButtonCell method to handle cell type in a basic way which avoids
360   to lose image or empty title on new image position (when this involves a cell
361   type switch) and the need to reset it. That would happen in GSToolbarButton
362   -layout method (on toolbar display mode switch).
363   Note that empty title are used with space or separator toolbar items. */
364- (void) setImagePosition: (NSCellImagePosition)aPosition
365{
366  _cell.image_position = aPosition;
367
368  if (_cell.image_position == NSNoImage)
369    {
370      _cell.type = NSTextCellType;
371    }
372  else
373    {
374      _cell.type = NSImageCellType;
375    }
376}
377
378/* Allways return the image, even when no image gets displayed. */
379- (NSImage*) image
380{
381  return _cell_image;
382}
383
384// Overriden NSButtonCell method to make sure all text is at the same height.
385- (void) drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView*)controlView
386{
387  BOOL flippedView = [controlView isFlipped];
388  NSCellImagePosition ipos = _cell.image_position;
389  // We ignore alternateAttributedTitle, it is not needed
390  NSSize titleSize = [[self attributedTitle] size];
391
392  if (flippedView == YES)
393    {
394      if (ipos == NSImageAbove)
395        {
396          ipos = NSImageBelow;
397        }
398      else if (ipos == NSImageBelow)
399        {
400          ipos = NSImageAbove;
401        }
402    }
403
404  /* We store the values we need to customize the drawing into titleRect and
405     imageRect. */
406  switch (ipos)
407    {
408      case NSNoImage:
409        titleRect = cellFrame;
410        break;
411
412      case NSImageOnly:
413        imageRect = cellFrame;
414        break;
415
416      default:
417      case NSImageBelow:
418        titleRect.origin.x = cellFrame.origin.x;
419        titleRect.origin.y = NSMaxY(cellFrame) - titleSize.height - InsetItemTextY;
420        titleRect.size.width = cellFrame.size.width;
421        titleRect.size.height = titleSize.height;
422
423        imageRect.origin.x = cellFrame.origin.x;
424        imageRect.origin.y = cellFrame.origin.y;
425        imageRect.size.width = cellFrame.size.width;
426        imageRect.size.height = cellFrame.size.height - titleRect.size.height;
427        break;
428
429      case NSImageAbove:
430        titleRect.origin.x = cellFrame.origin.x;
431        titleRect.origin.y = cellFrame.origin.y + InsetItemTextY;
432        titleRect.size.width = cellFrame.size.width;
433        titleRect.size.height = titleSize.height;
434
435        imageRect.origin.x = cellFrame.origin.x;
436        imageRect.origin.y = cellFrame.origin.y + titleRect.size.height;
437        imageRect.size.width = cellFrame.size.width;
438        imageRect.size.height = cellFrame.size.height - titleRect.size.height;
439        break;
440    }
441
442  [super drawInteriorWithFrame: cellFrame inView: controlView];
443}
444
445// Overriden NSCell method
446- (void) _drawAttributedText: (NSAttributedString*)aString
447                     inFrame: (NSRect)aRect
448{
449  if (aString == nil)
450    return;
451
452  /* Important: text should always be vertically centered without considering
453     descender (as if descender did not exist). This is particularly important
454     for single line texts.Please make sure the output remains always
455     correct. */
456
457  [aString drawInRect: titleRect]; // We ignore aRect value
458}
459
460// Overriden NSButtonCell method
461- (void) drawImage: (NSImage *)anImage withFrame: (NSRect)aRect inView: (NSView*)controlView
462{
463  // We ignore aRect value
464  [super drawImage: anImage withFrame: imageRect inView: controlView];
465}
466
467@end
468
469/*
470 * Back view used to enclose toolbar item's custom view
471 */
472@interface GSToolbarBackView : NSView
473{
474  NSToolbarItem *_toolbarItem;
475  NSFont *_font;
476  BOOL _enabled;
477  BOOL _showLabel;
478  // record the fact that the view responds to these
479  // to save time.
480  struct __flags
481  {
482    // gets
483    unsigned int _isEnabled:1;
484    unsigned int _action:1;
485    unsigned int _target:1;
486    unsigned int _image:1;
487    // sets
488    unsigned int _setEnabled:1;
489    unsigned int _setAction:1;
490    unsigned int _setTarget:1;
491    unsigned int _setImage:1;
492
493    // to even out the int.
494    unsigned int RESERVED:24;
495  } _flags;
496}
497
498- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem;
499- (void) layout;
500
501- (NSToolbarItem *) toolbarItem;
502- (BOOL) isEnabled;
503- (void) setEnabled: (BOOL)enabled;
504@end
505
506@implementation GSToolbarBackView
507
508- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem
509{
510  self = [super initWithFrame: NSMakeRect(ItemBackViewX, ItemBackViewY,
511    ItemBackViewDefaultWidth, ItemBackViewDefaultHeight)];
512  // Frame will be reset by the layout method
513
514  if (self != nil)
515    {
516      NSView *view;
517
518      // Don't do an ASSIGN here, the toolbar item itself retains us.
519      _toolbarItem = toolbarItem;
520      view = [toolbarItem view];
521
522      // gets
523      _flags._isEnabled  = [view respondsToSelector: @selector(isEnabled)];
524      _flags._action     = [view respondsToSelector: @selector(action)];
525      _flags._target     = [view respondsToSelector: @selector(target)];
526      _flags._image      = [view respondsToSelector: @selector(image)];
527      // sets
528      _flags._setEnabled = [view respondsToSelector: @selector(setEnabled:)];
529      _flags._setAction  = [view respondsToSelector: @selector(setAction:)];
530      _flags._setTarget  = [view respondsToSelector: @selector(setTarget:)];
531      _flags._setImage   = [view respondsToSelector: @selector(setImage:)];
532    }
533
534  return self;
535}
536
537- (void) drawRect: (NSRect)rect
538{
539  if (_showLabel && NSIntersectsRect(rect, [self bounds]))
540    {
541      NSAttributedString *attrString;
542      NSDictionary *attr;
543      NSColor *color;
544      NSMutableParagraphStyle *pStyle;
545      NSRect titleRect;
546      NSRect viewBounds = [self bounds];
547
548      if (_enabled)
549        {
550          color = [NSColor blackColor];
551        }
552      else
553        {
554          color = [NSColor disabledControlTextColor];
555        }
556
557      pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
558      [pStyle setAlignment: NSCenterTextAlignment];
559
560      // We draw the label
561      attr = [NSDictionary dictionaryWithObjectsAndKeys: _font,
562        NSFontAttributeName, color, NSForegroundColorAttributeName, pStyle,
563        NSParagraphStyleAttributeName, nil];
564      RELEASE(pStyle);
565
566      attrString = [[NSAttributedString alloc]
567        initWithString: [_toolbarItem label] attributes: attr];
568
569      titleRect.origin.x = viewBounds.origin.x;
570      titleRect.origin.y = viewBounds.origin.y + InsetItemTextY;
571      titleRect.size.width = viewBounds.size.width;
572      titleRect.size.height = [attrString size].height;
573      [attrString drawInRect: titleRect];
574
575      DESTROY(attrString);
576   }
577}
578
579- (NSView *) hitTest: (NSPoint)point
580{
581  if (_super_view && [_super_view mouse: point inRect: _frame])
582    {
583      NSEvent *event = [NSApp currentEvent];
584      NSToolbar *toolbar = [_toolbarItem toolbar];
585
586      if (([event type] == NSLeftMouseDown)
587	  && (([event modifierFlags] == NSCommandKeyMask
588	      && [toolbar allowsUserCustomization])
589	      || [toolbar customizationPaletteIsRunning] || toolbar == nil))
590	{
591	  return self;
592	}
593    }
594
595  return [super hitTest: point];
596}
597
598/*
599 * The code below should be kept in sync with GSToolbarButton methods which
600 * have identical names.
601 */
602
603- (void) layout
604{
605  NSView *view = [_toolbarItem view];
606  float textWidth, layoutedWidth = -1, layoutedHeight = -1;
607  NSFont *font;
608  unsigned int borderMask = [[[_toolbarItem toolbar] _toolbarView] borderMask];
609  NSSize labelSize = NSZeroSize;
610
611  font = NormalFont;
612
613  if ([view superview] == nil) // Show the view to eventually hide it later
614    [self addSubview: view];
615
616  if ([view respondsToSelector: @selector(sizeToFit)])
617    {
618      NSSize newSize, minSize = [_toolbarItem minSize];
619
620      [(id)view sizeToFit];
621      newSize = [view frame].size;
622      if (minSize.width > 0 || newSize.height < minSize.height)
623        {
624          if (minSize.width > 0)
625			newSize.width = minSize.width;
626          newSize.height = MAX(newSize.height, minSize.height);
627          [view setFrameSize: newSize];
628        }
629    }
630
631  // Adjust the layout in accordance with NSToolbarSizeMode
632  switch ([[_toolbarItem toolbar] sizeMode])
633    {
634      case NSToolbarSizeModeDefault:
635        layoutedWidth = ItemBackViewDefaultWidth;
636        layoutedHeight = ItemBackViewDefaultHeight;
637        if ([view frame].size.height > 32)
638          [view removeFromSuperview];
639        break;
640      case NSToolbarSizeModeRegular:
641        layoutedWidth = ItemBackViewRegularWidth;
642        layoutedHeight = ItemBackViewRegularHeight;
643        if ([view frame].size.height > 32)
644          [view removeFromSuperview];
645        break;
646      case NSToolbarSizeModeSmall:
647        layoutedWidth = ItemBackViewSmallWidth;
648        layoutedHeight = ItemBackViewSmallHeight;
649        font = SmallFont;
650        if ([view frame].size.height > 24)
651          [view removeFromSuperview];
652        break;
653      default:
654        NSLog(@"Invalid NSToolbarSizeMode"); // Invalid
655    }
656
657  _font = font;
658
659  // Adjust the layout in accordance with the border
660  if (!(borderMask & GSToolbarViewBottomBorder))
661    {
662      layoutedHeight++;
663      layoutedWidth++;
664    }
665
666  if (!(borderMask & GSToolbarViewTopBorder))
667    {
668      layoutedHeight++;
669      layoutedWidth++;
670    }
671
672  // Adjust the layout in accordance with the label
673  {
674    NSAttributedString *attrStr;
675    NSDictionary *attr;
676    NSString *label = [_toolbarItem label];
677
678    attr = [NSDictionary dictionaryWithObject: font forKey: NSFontAttributeName];
679    if (label == nil || [label isEqualToString: @""])
680      label = @"Dummy";
681    attrStr = [[NSAttributedString alloc] initWithString: label attributes: attr];
682    labelSize = [attrStr size];
683    DESTROY(attrStr);
684  }
685
686  textWidth = labelSize.width + 2 * InsetItemTextX;
687  if (textWidth > layoutedWidth)
688    layoutedWidth = textWidth;
689
690  _enabled = YES;
691  /* This boolean variable is used to known when it's needed to draw the label
692     in the -drawRect: method. */
693  _showLabel = YES;
694
695  // Adjust the layout in accordance with NSToolbarDisplayMode
696  switch ([[_toolbarItem toolbar] displayMode])
697    {
698      case NSToolbarDisplayModeDefault:
699        break; // Nothing to do
700      case NSToolbarDisplayModeIconAndLabel:
701        break; // Nothing to do
702      case NSToolbarDisplayModeIconOnly:
703        _showLabel = NO;
704        layoutedHeight -= labelSize.height + InsetItemTextY;
705        break;
706      case NSToolbarDisplayModeLabelOnly:
707        _enabled = NO;
708        layoutedHeight = labelSize.height + InsetItemTextY * 2;
709        if ([view superview] != nil)
710          [view removeFromSuperview];
711        break;
712      default:
713        ; // Invalid
714    }
715
716  /* If the view is visible...
717     Adjust the layout in accordance with the view width in the case it is
718     needed. */
719  if ([view superview] != nil)
720    {
721      if (layoutedWidth < [view frame].size.width + 2 * InsetItemViewX)
722        layoutedWidth = [view frame].size.width + 2 * InsetItemViewX;
723    }
724
725  // Set the frame size to use the new layout
726  [self setFrameSize: NSMakeSize(layoutedWidth, layoutedHeight)];
727
728  /* If the view is visible...
729     Adjust the view position in accordance with the new layout. */
730  if ([view superview] != nil)
731    {
732      float insetItemViewY = ([self frame].size.height
733			      - [view frame].size.height) / 2;
734
735      if (_showLabel)
736        {
737          insetItemViewY += (labelSize.height + InsetItemTextY) / 2;
738        }
739
740      [view setFrameOrigin: NSMakePoint((layoutedWidth
741        - [view frame].size.width) / 2, insetItemViewY)];
742    }
743}
744
745- (void) mouseDown: (NSEvent *)event
746{
747  NSToolbar *toolbar = [_toolbarItem toolbar];
748
749  if (([event modifierFlags] == NSCommandKeyMask
750       && [toolbar allowsUserCustomization])
751      || [toolbar customizationPaletteIsRunning] || toolbar == nil)
752    {
753      NSSize viewSize = [self frame].size;
754      NSImage *image = [[NSImage alloc] initWithSize: viewSize];
755      NSPasteboard *pboard;
756      NSInteger index = NSNotFound;
757
758      // Prepare the drag
759
760      /* We need to keep this view (aka self) to be able to draw the drag
761         image. */
762      RETAIN(self);
763
764      // Draw the drag content in an image
765      /* The code below is only partially supported by GNUstep, then NSImage
766         needs to be improved. */
767      [image lockFocus];
768      [self drawRect:
769                NSMakeRect(0, 0, viewSize.width, viewSize.height)];
770      [image unlockFocus];
771
772      pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
773      [pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType]
774              owner: nil];
775      if (toolbar != nil)
776	{
777          index = [toolbar _indexOfItem: _toolbarItem];
778        }
779	  [GSToolbarView setDraggedItemIndex:index];
780      [pboard setString: [NSString stringWithFormat:@"%ld", (long) index]
781              forType: GSMovableToolbarItemPboardType];
782
783      [self dragImage: image
784            //at: NSMakePoint(0.0, viewSize.height)
785            at: NSMakePoint(0.0, 0.0)
786            offset: NSMakeSize(0.0, 0.0)
787            event: event
788            pasteboard: pboard
789            source: self
790            slideBack: NO];
791      RELEASE(image);
792    }
793  else if ([event modifierFlags] != NSCommandKeyMask)
794    {
795      [super mouseDown: event];
796    }
797}
798
799- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
800{
801  //nothing to do
802}
803
804- (void) draggedImage: (NSImage *)dragImage
805              endedAt: (NSPoint)location
806            operation: (NSDragOperation)operation
807{
808  //nothing to do
809}
810
811- (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL)isLocal
812{
813  return isLocal ? NSDragOperationGeneric : NSDragOperationNone;
814}
815
816- (NSToolbarItem *) toolbarItem
817{
818  return _toolbarItem;
819}
820
821/*
822 * End of the code to keep in sync
823 */
824
825- (BOOL) isEnabled
826{
827  if (_flags._isEnabled)
828    {
829      id view = [_toolbarItem view];
830
831      return [view isEnabled];
832    }
833  else
834    {
835      return _enabled;
836    }
837}
838
839- (void) setEnabled: (BOOL)enabled
840{
841  if (_flags._setEnabled)
842    {
843      id view = [_toolbarItem view];
844
845      [view setEnabled: enabled];
846    }
847  else
848    {
849      _enabled = enabled;
850    }
851}
852
853- (NSImage *) image
854{
855  if (_flags._image)
856    {
857      id view = [_toolbarItem view];
858
859      return [view image];
860    }
861  else
862    {
863      return nil;
864    }
865}
866
867- (void) setImage: (NSImage *)image
868{
869  if (_flags._setImage)
870    {
871      id view = [_toolbarItem view];
872
873      [view setImage: image];
874    }
875}
876
877- (void) setAction: (SEL)action
878{
879  if (_flags._setAction)
880    {
881      id view = [_toolbarItem view];
882
883      [view setAction: action];
884    }
885}
886
887- (SEL) action
888{
889  if (_flags._action)
890    {
891      id view = [_toolbarItem view];
892
893      return [view action];
894    }
895  else
896    {
897      return 0;
898    }
899}
900
901- (void) setTarget: (id)target
902{
903  if (_flags._setTarget)
904    {
905      id view = [_toolbarItem view];
906
907      [view setTarget: target];
908    }
909}
910
911- (id) target
912{
913  if (_flags._target)
914    {
915      id view = [_toolbarItem view];
916
917      return [view target];
918    }
919  else
920    {
921      return nil;
922    }
923}
924
925@end
926
927/*
928 * Standard toolbar items.
929 */
930
931// ---- NSToolbarSeparatorItemIdentifier
932@interface NSToolbarSeparatorItem : NSToolbarItem
933{
934}
935@end
936
937@implementation NSToolbarSeparatorItem
938- (id) initWithItemIdentifier: (NSString *)itemIdentifier
939{
940  self = [super initWithItemIdentifier: itemIdentifier];
941  if (!self)
942    return nil;
943
944  [(NSButton *)[self _backView] setImagePosition: NSImageOnly];
945  [(NSButton *)[self _backView] setImage:
946                   [NSImage imageNamed: @"common_ToolbarSeparatorItem"]];
947  /* We bypass the toolbar item accessor to set the image in order to have it
948     (48 * 48) not resized. */
949   [self setPaletteLabel: _(@"Separator")];
950
951  [[self _backView] setFrameSize: NSMakeSize(30, ItemBackViewDefaultHeight)];
952
953  return self;
954}
955
956- (NSMenuItem *) _defaultMenuFormRepresentation
957{
958  return nil; // Override the default implementation in order to do nothing
959}
960
961- (void) _layout
962{
963  NSView *backView = [self _backView];
964
965  // Override the default implementation
966
967  [(id)backView layout];
968  if ([self toolbar] != nil)
969    [backView setFrameSize: NSMakeSize(30, [backView frame].size.height)];
970}
971
972- (BOOL) allowsDuplicatesInToolbar
973{
974  return YES;
975}
976
977@end
978
979// ---- NSToolbarSpaceItemIdentifier
980@interface NSToolbarSpaceItem : NSToolbarItem
981{
982}
983@end
984
985@implementation NSToolbarSpaceItem
986- (id) initWithItemIdentifier: (NSString *)itemIdentifier
987{
988  self = [super initWithItemIdentifier: itemIdentifier];
989  if (!self)
990    return nil;
991  [self setPaletteLabel: _(@"Space")];
992
993  return self;
994}
995
996// Override the default implementation in order to do nothing
997- (NSMenuItem *) _defaultMenuFormRepresentation
998{
999  return nil;
1000}
1001
1002- (BOOL) allowsDuplicatesInToolbar
1003{
1004  return YES;
1005}
1006
1007@end
1008
1009// ---- NSToolbarFlexibleSpaceItemIdentifier
1010@interface NSToolbarFlexibleSpaceItem : NSToolbarItem
1011{
1012}
1013@end
1014
1015@implementation NSToolbarFlexibleSpaceItem
1016- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1017{
1018  self = [super initWithItemIdentifier: itemIdentifier];
1019  if (!self)
1020    return nil;
1021  [self setPaletteLabel: _(@"Flexible Space")];
1022  [self _layout];
1023
1024  return self;
1025}
1026
1027// Override the default implementation in order to do nothing
1028- (NSMenuItem *) _defaultMenuFormRepresentation
1029{
1030  return nil;
1031}
1032
1033// Override the default implementation in order to reset the _backView to a zero width
1034- (void) _layout
1035{
1036  NSView *backView = [self _backView];
1037  NSSize size;
1038
1039  [(id)backView layout];
1040  size = [backView frame].size;
1041
1042  /* If the item is not part of a toolbar, this usually means it is used by
1043     customization palette, we shouldn't resize it in this case. */
1044  if ([self toolbar] != nil)
1045    [backView setFrameSize: NSMakeSize(0, size.height)];
1046
1047  [self setMinSize: NSMakeSize(0, size.height)];
1048  [self setMaxSize: NSMakeSize(10000, size.height)];
1049}
1050
1051- (BOOL) _isFlexibleSpace
1052{
1053  return YES;
1054}
1055
1056- (BOOL) allowsDuplicatesInToolbar
1057{
1058  return YES;
1059}
1060
1061@end
1062
1063// ---- NSToolbarShowColorsItemIdentifier
1064@interface GSToolbarShowColorsItem : NSToolbarItem
1065{
1066}
1067@end
1068
1069@implementation GSToolbarShowColorsItem
1070- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1071{
1072  self = [super initWithItemIdentifier: itemIdentifier];
1073  if (!self)
1074    return nil;
1075  [self setImage: [NSImage imageNamed: @"common_ToolbarShowColorsItem"]];
1076  [self setLabel: _(@"Colors")];
1077
1078  // Set action...
1079  [self setTarget: nil]; // Goes to first responder..
1080  [self setAction: @selector(orderFrontColorPanel:)];
1081
1082  return self;
1083}
1084@end
1085
1086// ---- NSToolbarShowFontsItemIdentifier
1087@interface GSToolbarShowFontsItem : NSToolbarItem
1088{
1089}
1090@end
1091
1092@implementation GSToolbarShowFontsItem
1093- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1094{
1095  self = [super initWithItemIdentifier: itemIdentifier];
1096  if (!self)
1097    return nil;
1098  [self setImage: [NSImage imageNamed: @"common_ToolbarShowFontsItem"]];
1099  [self setLabel: _(@"Fonts")];
1100
1101  // Set action...
1102  [self setTarget: nil]; // Goes to first responder..
1103  [self setAction: @selector(orderFrontFontPanel:)];
1104
1105  return self;
1106}
1107@end
1108
1109// ---- NSToolbarCustomizeToolbarItemIdentifier
1110@interface GSToolbarCustomizeToolbarItem : NSToolbarItem
1111{
1112}
1113@end
1114
1115@implementation GSToolbarCustomizeToolbarItem
1116- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1117{
1118  self = [super initWithItemIdentifier: itemIdentifier];
1119  if (!self)
1120    return nil;
1121  [self setImage: [NSImage imageNamed: @"common_ToolbarCustomizeToolbarItem"]];
1122  [self setLabel: _(@"Customize")];
1123
1124  // Set action...
1125  [self setTarget: nil]; // Goes to first responder..
1126  [self setAction: @selector(runToolbarCustomizationPalette:)];
1127
1128  return self;
1129}
1130@end
1131
1132// ---- NSToolbarPrintItemIdentifier
1133@interface GSToolbarPrintItem : NSToolbarItem
1134{
1135}
1136@end
1137
1138@implementation GSToolbarPrintItem
1139- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1140{
1141  self = [super initWithItemIdentifier: itemIdentifier];
1142  if (!self)
1143    return nil;
1144  [self setImage: [NSImage imageNamed: @"common_Printer"]];
1145  [self setLabel: _(@"Print...")];
1146
1147  // Set action...
1148  [self setTarget: nil]; // goes to first responder..
1149  [self setAction: @selector(printDocument:)];
1150
1151  return self;
1152}
1153@end
1154
1155
1156@implementation NSToolbarItem
1157
1158+ (void) initialize
1159{
1160  // This used to be size 11.
1161  NormalFont = RETAIN([NSFont systemFontOfSize: [NSFont systemFontSize]]);
1162  // [NSFont smallSystemFontSize] or better should be NSControlContentFontSize
1163  SmallFont = RETAIN([NSFont systemFontOfSize: [NSFont smallSystemFontSize]]);
1164}
1165
1166- (id) initWithItemIdentifier: (NSString *)itemIdentifier
1167{
1168  // GNUstep predefined toolbar items
1169  if ([itemIdentifier isEqualToString: NSToolbarSeparatorItemIdentifier]
1170      && [self isKindOfClass: [NSToolbarSeparatorItem class]] == NO)
1171    {
1172      RELEASE(self);
1173      return [[NSToolbarSeparatorItem alloc]
1174                 initWithItemIdentifier: itemIdentifier];
1175    }
1176  else if ([itemIdentifier isEqualToString: NSToolbarSpaceItemIdentifier]
1177           && [self isKindOfClass: [NSToolbarSpaceItem class]] == NO)
1178    {
1179      RELEASE(self);
1180      return [[NSToolbarSpaceItem alloc]
1181                 initWithItemIdentifier: itemIdentifier];
1182    }
1183  else if ([itemIdentifier
1184               isEqualToString: NSToolbarFlexibleSpaceItemIdentifier]
1185           && [self isKindOfClass: [NSToolbarFlexibleSpaceItem class]] == NO)
1186    {
1187      RELEASE(self);
1188      return [[NSToolbarFlexibleSpaceItem alloc]
1189                 initWithItemIdentifier: itemIdentifier];
1190    }
1191  else if ([itemIdentifier
1192               isEqualToString: NSToolbarShowColorsItemIdentifier]
1193           && [self isKindOfClass: [GSToolbarShowColorsItem class]] == NO)
1194    {
1195      RELEASE(self);
1196      return [[GSToolbarShowColorsItem alloc]
1197                 initWithItemIdentifier: itemIdentifier];
1198    }
1199  else if ([itemIdentifier
1200               isEqualToString: NSToolbarShowFontsItemIdentifier]
1201           && [self isKindOfClass: [GSToolbarShowFontsItem class]] == NO)
1202    {
1203      RELEASE(self);
1204      return [[GSToolbarShowFontsItem alloc]
1205                 initWithItemIdentifier: itemIdentifier];
1206    }
1207  else if ([itemIdentifier
1208               isEqualToString: NSToolbarCustomizeToolbarItemIdentifier]
1209           && [self isKindOfClass: [GSToolbarCustomizeToolbarItem class]] == NO)
1210    {
1211      RELEASE(self);
1212      return [[GSToolbarCustomizeToolbarItem alloc]
1213                 initWithItemIdentifier: itemIdentifier];
1214    }
1215  else if ([itemIdentifier isEqualToString: NSToolbarPrintItemIdentifier]
1216           && [self isKindOfClass: [GSToolbarPrintItem class]] == NO)
1217    {
1218      RELEASE(self);
1219      return [[GSToolbarPrintItem alloc]
1220                 initWithItemIdentifier: itemIdentifier];
1221    }
1222  else
1223    {
1224      if ((self = [super init]) != nil)
1225        {
1226          // Normal toolbar items
1227          ASSIGN(_itemIdentifier, itemIdentifier);
1228          [self setAutovalidates: YES];
1229
1230          // Set the backview to an GSToolbarButton, will get reset to a
1231          // GSToolbarBackView when setView: gets called.
1232	  [self setView: nil];
1233        }
1234    }
1235
1236  return self;
1237}
1238
1239- (void) dealloc
1240{
1241  RELEASE(_itemIdentifier);
1242  RELEASE(_label);
1243  RELEASE(_image);
1244  RELEASE(_menuFormRepresentation);
1245  RELEASE(_paletteLabel);
1246  RELEASE(_toolTip);
1247  TEST_RELEASE(_view);
1248  RELEASE(_backView);
1249
1250  [super dealloc];
1251}
1252
1253- (BOOL) allowsDuplicatesInToolbar
1254{
1255  return NO;
1256}
1257
1258- (BOOL) isEnabled
1259{
1260  return [(GSToolbarButton*)_backView isEnabled];
1261}
1262
1263- (NSImage *) image
1264{
1265  // return [(GSToolbarButton*)_backView image];
1266  return _image;
1267}
1268
1269- (NSString *) itemIdentifier
1270{
1271  return _itemIdentifier;
1272}
1273
1274- (NSString *) label
1275{
1276  // FIXME: I think this is not needed
1277  if ([[self toolbar] displayMode] == NSToolbarDisplayModeLabelOnly)
1278    {
1279      NSMenuItem *menuItem = [self menuFormRepresentation];
1280
1281      if (menuItem != nil)
1282        return [menuItem title];
1283    }
1284
1285  if (nil != _label)
1286    {
1287      return _label;
1288    }
1289  else
1290    {
1291      return @"";
1292    }
1293}
1294
1295- (NSSize) maxSize
1296{
1297  return _maxSize;
1298}
1299
1300- (NSMenuItem *) menuFormRepresentation
1301{
1302  return _menuFormRepresentation;
1303}
1304
1305- (NSSize) minSize
1306{
1307  return _minSize;
1308}
1309
1310- (NSString *) paletteLabel
1311{
1312  return _paletteLabel;
1313}
1314
1315- (void) setAction: (SEL)action
1316{
1317  [(GSToolbarButton *)_backView setAction: action];
1318
1319  [self setEnabled: (action != NULL)];
1320}
1321
1322- (void) setEnabled: (BOOL)enabled
1323{
1324  [(GSToolbarButton*)_backView setEnabled: enabled];
1325}
1326
1327- (void) setImage: (NSImage *)image
1328{
1329  ASSIGN(_image, image);
1330
1331  [_image setScalesWhenResized: YES];
1332  //[_image setSize: NSMakeSize(32, 32)];
1333
1334  // Do not set the image on the button if we are in "LabelOnly"
1335  // mode. If the toolbar's displayMode changes later, we'll
1336  // put the image on the button in the layout method.
1337  if ([[self toolbar] displayMode] != NSToolbarDisplayModeLabelOnly)
1338    {
1339      [(GSToolbarButton*)_backView setImage: image];
1340    }
1341}
1342
1343- (void) setLabel: (NSString *)label
1344{
1345  ASSIGN(_label, label);
1346
1347  if (!_view)
1348    [(GSToolbarButton *)_backView setTitle: _label];
1349
1350  _modified = YES;
1351  if (_toolbar != nil)
1352    [[_toolbar _toolbarView] _reload];
1353}
1354
1355- (void) setMaxSize: (NSSize)maxSize
1356{
1357  _maxSize = maxSize;
1358}
1359
1360- (void) setMenuFormRepresentation: (NSMenuItem *)menuItem
1361{
1362  ASSIGN(_menuFormRepresentation, menuItem);
1363}
1364
1365- (void) setMinSize: (NSSize)minSize
1366{
1367  _minSize = minSize;
1368}
1369
1370- (void) setPaletteLabel: (NSString *)paletteLabel
1371{
1372  ASSIGN(_paletteLabel, paletteLabel);
1373}
1374
1375- (void) setTag: (NSInteger)tag
1376{
1377  _tag = tag;
1378}
1379
1380- (void) setTarget: (id)target
1381{
1382  [(NSButton *)_backView setTarget: target];
1383}
1384
1385- (void) setToolTip: (NSString *)toolTip
1386{
1387  ASSIGN(_toolTip, toolTip);
1388  if (_view)
1389    {
1390      [_view setToolTip: _toolTip];
1391    }
1392  else
1393    {
1394      [_backView setToolTip: _toolTip];
1395    }
1396}
1397
1398- (void) setView: (NSView *)view
1399{
1400  if ((_view == view) && (_backView != nil))
1401    return;
1402
1403  ASSIGN(_view, view);
1404
1405  if (view)
1406    {
1407      NSSize size;
1408
1409      size = [view frame].size;
1410      if (NSEqualSizes(NSZeroSize, _minSize))
1411          [self setMinSize: size];
1412      if (NSEqualSizes(NSZeroSize, _maxSize))
1413          [self setMaxSize: size];
1414
1415      [_view setToolTip: _toolTip];
1416
1417      RELEASE(_backView);
1418      _backView = [[GSToolbarBackView alloc] initWithToolbarItem: self];
1419    }
1420  else
1421    {
1422      RELEASE(_backView);
1423      _backView = [[GSToolbarButton alloc] initWithToolbarItem: self];
1424      [_backView setToolTip: _toolTip];
1425    }
1426}
1427
1428- (NSInteger) tag
1429{
1430  return _tag;
1431}
1432
1433- (NSString *) toolTip
1434{
1435  return _toolTip;
1436}
1437
1438- (NSToolbar *) toolbar
1439{
1440  return _toolbar;
1441}
1442
1443- (void) validate
1444{
1445  BOOL enabled = YES;
1446  id target;
1447
1448  /* No validation for custom views */
1449  if (_view)
1450    return;
1451
1452  target = [NSApp targetForAction: [self action] to: [self target] from: self];
1453  if (target == nil || ![target respondsToSelector: [self action]])
1454    {
1455      enabled = NO;
1456    }
1457  else if ([target respondsToSelector: @selector(validateToolbarItem:)])
1458    {
1459      enabled = [target validateToolbarItem: self];
1460    }
1461  else if ([target respondsToSelector: @selector(validateUserInterfaceItem:)])
1462    {
1463      enabled = [target validateUserInterfaceItem: self];
1464    }
1465  [self setEnabled: enabled];
1466}
1467
1468- (NSView *) view
1469{
1470  return _view;
1471}
1472
1473// Private or package like visibility methods
1474
1475- (NSView *) _backView
1476{
1477  return _backView;
1478}
1479
1480//
1481// This method invokes using the toolbar item as the sender.
1482// When invoking from the menu, it shouldn't send the menuitem as the
1483// sender since some applications check this and try to get additional
1484// information about the toolbar item which this is coming from. Since
1485// we implement the menu's action, we must also validate it.
1486//
1487- (void) _sendAction: (id)sender
1488{
1489  [NSApp sendAction: [self action]
1490	 to: [self target]
1491	 from: self];
1492}
1493
1494- (BOOL) validateMenuItem: (NSMenuItem *)menuItem
1495{
1496  return [self isEnabled];
1497}
1498
1499- (NSMenuItem *) _defaultMenuFormRepresentation
1500{
1501  NSMenuItem *menuItem;
1502
1503  menuItem = [[NSMenuItem alloc] initWithTitle: [self label]
1504				 action: @selector(_sendAction:)
1505                                 keyEquivalent: @""];
1506  [menuItem setTarget: self];
1507  AUTORELEASE(menuItem);
1508
1509  return menuItem;
1510}
1511
1512- (void) _layout
1513{
1514  // Reset to image on the backview: We may have toggled
1515  // from one NSToolbarDisplayMode to another, and it is
1516  // possible setImage: would have been called on the
1517  // NSToolbarItem while we were in NSToolbarDisplayModeLabelOnly
1518  if ([[self toolbar] displayMode] != NSToolbarDisplayModeLabelOnly)
1519    {
1520      [(GSToolbarButton*)_backView setImage: _image];
1521    }
1522
1523  [(id)_backView layout];
1524}
1525
1526- (BOOL) _isModified
1527{
1528  return _modified;
1529}
1530
1531- (BOOL) _isFlexibleSpace
1532{
1533  return NO;
1534}
1535
1536- (BOOL) _selectable
1537{
1538  return _selectable;
1539}
1540
1541- (BOOL) _selected
1542{
1543  return [(GSToolbarButton *)_backView state];
1544}
1545
1546- (void) _setSelected: (BOOL)selected
1547{
1548  if (_selectable)
1549    {
1550      if ([self _selected] != selected)
1551        [(GSToolbarButton *)_backView setState: selected];
1552    }
1553  else
1554    {
1555      NSLog(@"The toolbar item %@ is not selectable", self);
1556    }
1557}
1558
1559- (void) _setSelectable: (BOOL)selectable
1560{
1561  if ([_backView isKindOfClass: [GSToolbarButton class]])
1562    {
1563      _selectable = selectable;
1564      [(GSToolbarButton *)_backView setButtonType: NSOnOffButton];
1565    }
1566  else
1567    {
1568      NSLog(@"The toolbar item %@ is not selectable", self);
1569    }
1570}
1571
1572- (void) _setToolbar: (NSToolbar *)toolbar
1573{
1574  // Don't do an ASSIGN here, the toolbar itself retains us.
1575  _toolbar = toolbar;
1576}
1577
1578- (BOOL) autovalidates
1579{
1580  return _autovalidates;
1581}
1582
1583- (void) setAutovalidates: (BOOL)autovalidates
1584{
1585  _autovalidates = autovalidates;
1586}
1587
1588- (NSInteger) visibilityPriority
1589{
1590  return _visibilityPriority;
1591}
1592
1593- (void) setVisibilityPriority: (NSInteger)visibilityPriority
1594{
1595  _visibilityPriority = visibilityPriority;
1596}
1597
1598// NSValidatedUserInterfaceItem protocol
1599- (SEL) action
1600{
1601  return [(GSToolbarButton *)_backView action];
1602}
1603
1604- (id) target
1605{
1606  return [(GSToolbarButton *)_backView target];
1607}
1608
1609// NSCopying protocol
1610- (id) copyWithZone: (NSZone *)zone
1611{
1612  NSToolbarItem *new = [[NSToolbarItem allocWithZone: zone]
1613    initWithItemIdentifier: _itemIdentifier];
1614  NSString *toolTip;
1615  NSImage *image;
1616  NSString *label;
1617  NSMenuItem *item;
1618
1619  // Copy all items individually...
1620  [new setTarget: [self target]];
1621  [new setAction: [self action]];
1622
1623  toolTip = [[self toolTip] copyWithZone: zone];
1624  [new setToolTip: toolTip];
1625  RELEASE(toolTip);
1626  [new setTag: [self tag]];
1627  image = [[self image] copyWithZone: zone];
1628  [new setImage: image];
1629  RELEASE(image);
1630  [new setEnabled: [self isEnabled]];
1631  label = [[self paletteLabel] copyWithZone: zone];
1632  [new setPaletteLabel: label];
1633  RELEASE(label);
1634  label = [[self label] copyWithZone: zone];
1635  [new setLabel: label];
1636  RELEASE(label);
1637  [new setMinSize: [self minSize]];
1638  [new setMaxSize: [self maxSize]];
1639  [new setAutovalidates: [self autovalidates]];
1640  [new setVisibilityPriority: [self visibilityPriority]];
1641  item = [[self menuFormRepresentation] copyWithZone: zone];
1642  [new setMenuFormRepresentation: item];
1643  RELEASE(item);
1644
1645  if ([self view] != nil)
1646    {
1647      NSData *encodedView = nil;
1648      NSView *superview = nil;
1649
1650      /* NSView doesn't implement -copyWithZone:, that's why we encode
1651         then decode the view to create a copy of it. */
1652      superview = [[self view] superview];
1653      /* We must avoid to encode view hierarchy */
1654      [[self view] removeFromSuperviewWithoutNeedingDisplay];
1655      NSLog(@"Encode toolbar item with label %@, view %@ and superview %@",
1656            [self label], [self view], superview);
1657      // NOTE: Keyed archiver would fail on NSSlider here.
1658      encodedView = [NSArchiver archivedDataWithRootObject: [self view]];
1659      [new setView: [NSUnarchiver unarchiveObjectWithData: encodedView]];
1660      // Re-add the view to its hierarchy
1661      [superview addSubview: [self view]];
1662    }
1663
1664  return new;
1665}
1666
1667- (NSString *) description
1668{
1669  return [NSString stringWithFormat: @"<%@ - <%@>>",[super description],[self itemIdentifier]];
1670}
1671
1672- (id) initWithCoder: (NSCoder *)aCoder
1673{
1674  self = [self initWithItemIdentifier: [aCoder decodeObjectForKey:@"NSToolbarItemIdentifier"]];
1675
1676  if ([aCoder containsValueForKey: @"NSToolbarItemTarget"])
1677    [self setTarget: [aCoder decodeObjectForKey:@"NSToolbarItemTarget"]];
1678  if ([aCoder containsValueForKey: @"NSToolbarItemAction"])
1679    [self setAction: NSSelectorFromString([aCoder decodeObjectForKey:@"NSToolbarItemAction"])];
1680  if ([aCoder containsValueForKey: @"NSToolbarItemToolTip"])
1681    [self setToolTip: [aCoder decodeObjectForKey:@"NSToolbarItemToolTip"]];
1682  if ([aCoder containsValueForKey: @"NSToolbarItemTag"])
1683    [self setTag: [aCoder decodeIntForKey:@"NSToolbarItemTag"]];
1684  if ([aCoder containsValueForKey: @"NSToolbarItemImage"])
1685    [self setImage: [aCoder decodeObjectForKey:@"NSToolbarItemImage"]];
1686  if ([aCoder containsValueForKey: @"NSToolbarItemEnabled"])
1687    [self setEnabled: [aCoder decodeBoolForKey:@"NSToolbarItemEnabled"]];
1688  if ([aCoder containsValueForKey: @"NSToolbarItemPaletteLabel"])
1689    [self setPaletteLabel: [aCoder decodeObjectForKey:@"NSToolbarItemPaletteLabel"]];
1690  if ([aCoder containsValueForKey: @"NSToolbarItemLabel"])
1691    [self setLabel: [aCoder decodeObjectForKey:@"NSToolbarItemLabel"]];
1692  if ([aCoder containsValueForKey: @"NSToolbarItemMinSize"])
1693    [self setMinSize: [aCoder decodeSizeForKey:@"NSToolbarItemMinSize"]];
1694  if ([aCoder containsValueForKey: @"NSToolbarItemMaxSize"])
1695    [self setMaxSize: [aCoder decodeSizeForKey:@"NSToolbarItemMaxSize"]];
1696  if ([aCoder containsValueForKey: @"NSToolbarItemAutovalidates"])
1697    [self setAutovalidates: [aCoder decodeBoolForKey:@"NSToolbarItemAutovalidates"]];
1698  if ([aCoder containsValueForKey: @"NSToolbarItemVisibilityPriority"])
1699    [self setVisibilityPriority: [aCoder decodeIntForKey:@"NSToolbarItemVisibilityPriority"]];
1700  if ([aCoder containsValueForKey: @"NSToolbarItemView"])
1701    [self setView: [aCoder decodeObjectForKey: @"NSToolbarItemView"]];
1702
1703  return self;
1704}
1705
1706@end
1707