Logo Search packages:      
Sourcecode: abiword version File versions

xap_CocoaToolPalette.mm

/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */

/* AbiSource Application Framework
 * Copyright (C) 2004 AbiSource, Inc.
 * Copyright (C) 2004 Francis James Franklin <fjf@alinameridon.com>
 * 
 * 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., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */


#include "ut_assert.h"
#include "ut_debugmsg.h"
#include "ut_exception.h"
#include "ut_string_class.h"

#import "xap_CocoaApp.h"
#import "xap_CocoaAppController.h"
#import "xap_CocoaFont.h"
#import "xap_CocoaToolPalette.h"
#import "xap_CocoaToolbar_Icons.h"

#include "xap_Frame.h"
#include "xap_Toolbar_LabelSet.h"
#include "xav_View.h"

#include "ev_EditEventMapper.h"
#include "ev_Menu_Actions.h"
#include "ev_Toolbar_Actions.h"
#include "ev_Toolbar_Layouts.h"
#include "ev_Toolbar_Labels.h"
#include "ev_Toolbar_Control.h"

#include "pd_Document.h"
#include "pd_Style.h"

#include "pp_AttrProp.h"

#include "fv_View.h"

#include "ap_Menu_Id.h"

enum _XAP_CocoaTool_Id
{
#define defn(T,X,Y)                 ToolID_##T,
#include "xap_CocoaTools.h"
#undef defn
      XAP_COCOA_TOOL_ID__COUNT_
};

@interface XAP_CocoaPalette : NSObject
{
      NSString *        m_Name;
      NSButton *        m_Title;
      NSBox *                 m_Box;

      UT_uint32         m_heightTitle;
      UT_uint32         m_heightBox;
}
- (id)initWithPalette:(const struct XAP_CocoaPaletteRef *)palette;
- (void)dealloc;

- (NSString *)Name;
- (NSButton *)Title;
- (NSBox *)Box;

- (BOOL)isExpanded;

- (UT_uint32)heightTitle;
- (UT_uint32)heightBox;
- (UT_uint32)heightConditional;
@end

@implementation XAP_CocoaPalette

- (id)initWithPalette:(const struct XAP_CocoaPaletteRef *)palette
{
      if (self = [super init])
            {
                  UT_ASSERT(palette);
                  UT_ASSERT(palette->Name);

                  m_Name = [[NSString alloc] initWithString:(palette->Name)];
                  if (!m_Name)
                        {
                              [super dealloc];
                              self = 0;
                        }
            }
      if (self)
            {
                  UT_ASSERT(palette->Title && palette->Box);

                  m_Title = palette->Title;
                  m_Box   = palette->Box;

                  [m_Title retain];
                  [m_Box   retain];

                  NSRect frame;

                  frame = [m_Title frame];
                  m_heightTitle = static_cast<UT_uint32>(frame.size.height);

                  frame = [m_Box frame];
                  m_heightBox = static_cast<UT_uint32>(frame.size.height);
            }
      return self;
}

- (void)dealloc
{
      if (m_Name)
            {
                  [m_Name release];
                  m_Name = 0;
            }
      if (m_Title)
            {
                  [m_Title release];
                  m_Title = 0;
            }
      if (m_Box)
            {
                  [m_Box release];
                  m_Box = 0;
            }
      [super dealloc];
}

- (NSString *)Name
{
      return m_Name;
}

- (NSButton *)Title
{
      return m_Title;
}

- (NSBox *)Box
{
      return m_Box;
}

- (BOOL)isExpanded
{
      return ([m_Title tag] == 1) ? YES : NO;
}

- (UT_uint32)heightTitle
{
      return m_heightTitle;
}

- (UT_uint32)heightBox
{
      return m_heightBox;
}

- (UT_uint32)heightConditional
{
      UT_uint32 height = m_heightTitle;

      if ([m_Title tag] == 1)
            {
                  height += m_heightBox;
            }
      return height;
}

@end

@implementation XAP_CocoaPaletteView

- (id)init
{
      NSRect frame;
      frame.origin.x    =   0;
      frame.origin.y    =   0;
      frame.size.width  = 300;
      frame.size.height = 100;

      if (self = [super initWithFrame:frame]) // ignore frame here
            {
                  m_Palette = [[NSMutableArray alloc] initWithCapacity:4];
                  if (!m_Palette)
                        {
                              [super dealloc];
                              self = nil;
                        }
            }
      return self;
}

- (void)dealloc
{
      if (m_Palette)
            {
                  [m_Palette release];
                  m_Palette = 0;
            }
      [super dealloc];
}

- (void)addPalette:(const struct XAP_CocoaPaletteRef *)paletteRef
{
      XAP_CocoaPalette * palette = [[XAP_CocoaPalette alloc] initWithPalette:paletteRef];
      if (palette)
            {
                  [m_Palette addObject:palette];
                  [palette release];

                  [paletteRef->Title removeFromSuperviewWithoutNeedingDisplay];
                  [paletteRef->Box   removeFromSuperviewWithoutNeedingDisplay];

                  [self sync]; // update frames

                  [self addSubview:(paletteRef->Title)];
                  [self addSubview:(paletteRef->Box  )];

                  [self setNeedsDisplay:YES];
            }
}

#define PALETTE_ELEMENT_ORIGIN_X  -3
#define PALETTE_ELEMENT_WIDTH    219
#define PALETTE_PANEL_WIDTH      213

- (void)sync
{
      unsigned count = [m_Palette count];
      unsigned i;

      if (!count) return; // huh. no palettes

      /* First, calculate total height
       */
      UT_uint32 view_height = 0;

      for (i = 0; i < count; i++)
            {
                  XAP_CocoaPalette * palette = (XAP_CocoaPalette *) [m_Palette objectAtIndex:i];

                  view_height += [palette heightConditional];
            }

      NSSize size;
      size.width  = PALETTE_PANEL_WIDTH;
      size.height = static_cast<float>(view_height);

      NSRect frame;

      UT_uint32 vh_remember = view_height;

      /* Adjust frames of individual palettes
       */
      for (i = 0; i < count; i++)
            {
                  XAP_CocoaPalette * palette = (XAP_CocoaPalette *) [m_Palette objectAtIndex:i];

                  UT_uint32 height = [palette heightTitle];

                  view_height -= height;

                  /* Title
                   */

                  /* Box
                   */
                  height = [palette heightBox];

                  if ([palette isExpanded])
                        {
                              view_height -= height;
                        }
                  else // move it out of sight
                        {
                              [self setNeedsDisplayInRect:[[palette Box] frame]];

                              frame.origin.x    = PALETTE_ELEMENT_WIDTH;
                              frame.origin.y    = static_cast<float>(view_height);
                              frame.size.width  = PALETTE_ELEMENT_WIDTH;
                              frame.size.height = static_cast<float>(height);
                              [[palette Box] setFrame:frame];
                        }
            }
      [self displayIfNeeded];

      view_height = vh_remember;

      /* Update panel size, if in a panel, else set the frame size
       */
      NSWindow * window = [self window];
      if (window)
            {
                  // [self setNeedsDisplay:NO];

                  NSRect current = [window frame];

                  int y = static_cast<int>(current.origin.y) + static_cast<int>(current.size.height);

                  NSRect content;
                  content.origin.x    = 0;
                  content.origin.y    = 0;
                  content.size.width  = size.width;
                  content.size.height = size.height;

                  frame = [NSWindow frameRectForContentRect:content styleMask:(NSTitledWindowMask|NSClosableWindowMask|NSUtilityWindowMask)];
                  frame.origin.x = current.origin.x;
                  frame.origin.y = static_cast<float>(y - static_cast<int>(frame.size.height));
                  [window setFrame:frame display:YES animate:YES];
            }
      else
            {
                  frame.origin.x    = 0;
                  frame.origin.y    = 0;
                  frame.size.width  = size.width;
                  frame.size.height = size.height;
                  [self setFrame:frame];
            }

      /* Adjust frames of individual palettes
       */
      for (i = 0; i < count; i++)
            {
                  XAP_CocoaPalette * palette = (XAP_CocoaPalette *) [m_Palette objectAtIndex:i];

                  UT_uint32 height = [palette heightTitle];

                  view_height -= height;

                  /* Title
                   */
                  frame.origin.x    = PALETTE_ELEMENT_ORIGIN_X;
                  frame.origin.y    = static_cast<float>(view_height);
                  frame.size.width  = PALETTE_ELEMENT_WIDTH;
                  frame.size.height = static_cast<float>(height);
                  [[palette Title] setFrame:frame];
                  [[palette Title] setNeedsDisplay:YES];
                  [[palette Title] displayIfNeeded];

                  /* Box
                   */
                  height = [palette heightBox];

                  if ([palette isExpanded])
                        {
                              view_height -= height;

                              frame.origin.x    = PALETTE_ELEMENT_ORIGIN_X;
                              frame.origin.y    = static_cast<float>(view_height);
                              frame.size.width  = PALETTE_ELEMENT_WIDTH;
                              frame.size.height = static_cast<float>(height);
                              [[palette Box] setFrame:frame];
                              [[palette Box] setNeedsDisplay:YES];
                              [[palette Box] displayIfNeeded];
                        }
                  else // move it out of sight
                        {
                              frame.origin.x    = PALETTE_ELEMENT_WIDTH;
                              frame.origin.y    = static_cast<float>(view_height);
                              frame.size.width  = PALETTE_ELEMENT_WIDTH;
                              frame.size.height = static_cast<float>(height);
                              [[palette Box] setFrame:frame];
                        }
            }
}

@end

@interface XAP_PaletteProperties_Level : NSObject
{
      BOOL                    m_IsLevel;

      NSString *              m_Name;
      NSString *              m_Value;

      NSMutableArray *  m_Properties;
}
- (id)initWithAP:(const PP_AttrProp *)pAP levelName:(NSString *)name;
- (id)initWithStyle:(PD_Style *)style levelName:(NSString *)name;
- (id)initWithPropertyName:(NSString *)name propertyValue:(NSString *)value;
- (void)dealloc;

- (int)numberOfChildrenOfItem;
- (BOOL)isItemExpandable;
- (id)child:(int)index;
- (id)objectValueForTableColumn:(NSTableColumn *)tableColumn;
@end

@implementation XAP_PaletteProperties_Level

- (id)initWithAP:(const PP_AttrProp *)pAP levelName:(NSString *)name
{
      if (self = [super init])
            {
                  m_IsLevel = YES;

                  m_Name  = name;
                  m_Value = @"";

                  [m_Name  retain];
                  [m_Value retain];

                  m_Properties = 0;

                  if (int count = static_cast<int>(pAP->getPropertyCount()))
                        if (m_Properties = [[NSMutableArray alloc] initWithCapacity:((unsigned) count)])
                              for (int i = 0; i < count; i++)
                                    {
                                          const XML_Char * szName  = 0;
                                          const XML_Char * szValue = 0;

                                          if (pAP->getNthProperty(i, szName, szValue))
                                                {
                                                      NSString * name  = [NSString stringWithUTF8String:((const char *) szName )];
                                                      NSString * value = [NSString stringWithUTF8String:((const char *) szValue)];

                                                      XAP_PaletteProperties_Level * property = [[XAP_PaletteProperties_Level alloc] initWithPropertyName:name propertyValue:value];
                                                      if (property)
                                                            {
                                                                  [m_Properties addObject:property];
                                                                  [property release];
                                                            }
                                                }
                                    }
            }
      return self;
}

- (id)initWithStyle:(PD_Style *)style levelName:(NSString *)name
{
      if (self = [super init])
            {
                  m_IsLevel = YES;

                  m_Name  = name;
                  m_Value = @"";

                  [m_Name  retain];
                  [m_Value retain];

                  m_Properties = 0;

                  if (int count = static_cast<int>(style->getPropertyCount()))
                        if (m_Properties = [[NSMutableArray alloc] initWithCapacity:((unsigned) count)])
                              for (int i = 0; i < count; i++)
                                    {
                                          const XML_Char * szName  = 0;
                                          const XML_Char * szValue = 0;

                                          if (style->getNthProperty(i, szName, szValue))
                                                {
                                                      NSString * name  = [NSString stringWithUTF8String:((const char *) szName )];
                                                      NSString * value = [NSString stringWithUTF8String:((const char *) szValue)];

                                                      XAP_PaletteProperties_Level * property = [[XAP_PaletteProperties_Level alloc] initWithPropertyName:name propertyValue:value];
                                                      if (property)
                                                            {
                                                                  [m_Properties addObject:property];
                                                                  [property release];
                                                            }
                                                }
                                    }
            }
      return self;
}

- (id)initWithPropertyName:(NSString *)name propertyValue:(NSString *)value
{
      if (self = [super init])
            {
                  m_IsLevel = NO;

                  m_Name  = name;
                  m_Value = value;

                  [m_Name  retain];
                  [m_Value retain];

                  m_Properties = 0;
            }
      return self;
}

- (void)dealloc
{
      if (m_Name)
            {
                  [m_Name  release];
                  m_Name = 0;
            }
      if (m_Value)
            {
                  [m_Value release];
                  m_Value = 0;
            }
      if (m_Properties)
            {
                  [m_Properties release];
                  m_Properties = 0;
            }
      [super dealloc];
}

- (int)numberOfChildrenOfItem
{
      if (m_IsLevel && m_Properties)
            {
                  return [m_Properties count];
            }
      return 0;
}

- (BOOL)isItemExpandable
{
      if (m_IsLevel)
            {
                  return YES;
            }
      return NO;
}

- (id)child:(int)index
{
      if (m_IsLevel /* && m_Properties */)
            {
                  return [m_Properties objectAtIndex:((unsigned) index)];
            }
      return 0; // ??
}

- (id)objectValueForTableColumn:(NSTableColumn *)tableColumn
{
      NSTableHeaderCell * headerCell = [tableColumn headerCell];

      if ([[headerCell stringValue] isEqualToString:@"Value"])
            {
                  return m_Value;
            }
      return m_Name;
}

@end

static PD_Style * _getStyle(const PP_AttrProp * pAttrProp, PD_Document * pDoc)
{
      PD_Style * pStyle = 0;

      const XML_Char * szValue = 0;

// This is where the style/name split gets really hairy. This index AP MIGHT be
// from a style definition in which case the name of the style is PT_NAME_ATTRIBUTE_NAME
// or it might be from the document in which case the attribute is
// PT_STYLE_ATTRIBUTE_NAME. - MES.

      if (pAttrProp->getAttribute(PT_NAME_ATTRIBUTE_NAME, szValue))
            {
                  UT_return_val_if_fail (szValue && szValue[0], 0);
                  if (pDoc)
                        pDoc->getStyle(reinterpret_cast<const char*>(szValue), &pStyle);

                  // NOTE: we silently fail if style is referenced, but not defined
            }
    else if(pAttrProp->getAttribute(PT_STYLE_ATTRIBUTE_NAME, szValue))
            {
                  UT_return_val_if_fail (szValue && szValue[0], 0);
                  if (pDoc)
                        pDoc->getStyle(reinterpret_cast<const char*>(szValue), &pStyle);

                  // NOTE: we silently fail if style is referenced, but not defined
            }
      return pStyle;
}

@implementation XAP_PaletteProperties_DataSource

- (id)initWithOutlineView:(NSOutlineView *)outlineView
{
      if (self = [super init])
            {
                  m_OutlineView = outlineView;

                  m_PropertyLevels = [[NSMutableArray alloc] initWithCapacity:6];
                  if (!m_PropertyLevels)
                        {
                              [super dealloc];
                              self = 0;
                        }
            }
      return self;
}

- (void)dealloc
{
      [m_OutlineView setDelegate:nil];
      [m_OutlineView setDataSource:nil];

      if (m_PropertyLevels)
            {
                  [m_PropertyLevels release];
                  m_PropertyLevels = 0;
            }
      [super dealloc];
}

- (void)syncWithView:(FV_View *)pView
{
      if (m_PropertyLevels)
            {
                  [m_PropertyLevels removeAllObjects];
            }
      if (pView)
            {
                  const PP_AttrProp * pSpanAP    = 0;
                  const PP_AttrProp * pBlockAP   = 0;
                  const PP_AttrProp * pSectionAP = 0;
                  const PP_AttrProp * pDocAP     = 0;

                  if (pView->getAllAttrProp(pSpanAP, pBlockAP, pSectionAP, pDocAP))
                        {
                              if (pSpanAP)
                                    {
                                          if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithAP:pSpanAP levelName:@"Span"])
                                                {
                                                      [m_PropertyLevels addObject:pPPLevel];
                                                      [pPPLevel release];
                                                }
                                          if (PD_Style * style = _getStyle(pSpanAP, pView->getDocument()))
                                                {
                                                      NSString * name = [NSString stringWithUTF8String:(style->getName())];
                                                      if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithStyle:style levelName:name])
                                                            {
                                                                  [m_PropertyLevels addObject:pPPLevel];
                                                                  [pPPLevel release];
                                                            }
                                                }
                                    }

                              if (pBlockAP)
                                    {
                                          if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithAP:pBlockAP levelName:@"Block"])
                                                {
                                                      [m_PropertyLevels addObject:pPPLevel];
                                                      [pPPLevel release];
                                                }
                                          if (PD_Style * style = _getStyle(pBlockAP, pView->getDocument()))
                                                {
                                                      NSString * name = [NSString stringWithUTF8String:(style->getName())];
                                                      if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithStyle:style levelName:name])
                                                            {
                                                                  [m_PropertyLevels addObject:pPPLevel];
                                                                  [pPPLevel release];
                                                            }
                                                }
                                    }

                              if (pSectionAP)
                                    if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithAP:pSectionAP levelName:@"Section"])
                                          {
                                                [m_PropertyLevels addObject:pPPLevel];
                                                [pPPLevel release];
                                          }

                              if (pDocAP)
                                    if (XAP_PaletteProperties_Level * pPPLevel = [[XAP_PaletteProperties_Level alloc] initWithAP:pDocAP levelName:@"Document"])
                                          {
                                                [m_PropertyLevels addObject:pPPLevel];
                                                [pPPLevel release];
                                          }
                        }
            }
      [m_OutlineView reloadData];
}

- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
      if (item)
            {
                  XAP_PaletteProperties_Level * pPPLevel = (XAP_PaletteProperties_Level *) item;
                  return [pPPLevel numberOfChildrenOfItem];
            }
      return (int) [m_PropertyLevels count];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
      if (item)
            {
                  XAP_PaletteProperties_Level * pPPLevel = (XAP_PaletteProperties_Level *) item;
                  return [pPPLevel isItemExpandable];
            }
      return YES; // ??
}

- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
{
      if (item)
            {
                  XAP_PaletteProperties_Level * pPPLevel = (XAP_PaletteProperties_Level *) item;
                  return [pPPLevel child:index];
            }
      return [m_PropertyLevels objectAtIndex:((unsigned) index)];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
      if (item)
            {
                  XAP_PaletteProperties_Level * pPPLevel = (XAP_PaletteProperties_Level *) item;
                  return [pPPLevel objectValueForTableColumn:tableColumn];
            }
      return @"??"; // ??
 }

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
      [cell setFont:[NSFont systemFontOfSize:10.0f]];
}

- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
      [cell setFont:[NSFont systemFontOfSize:10.0f]];
}

@end

@implementation XAP_CocoaPreviewPanel

- (id)init
{
      if (self = [super init])
            {
                  // 
            }
      return self;
}

- (void)dealloc
{
      // 
      [super dealloc];
}

- (void)windowDidLoad
{
      NSPanel * panel = (NSPanel *) [self window];

      [panel setBecomesKeyOnlyIfNeeded:YES];

      [oPreview setStringValue:@"Preview"];

      XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate];

      if (NSMenuItem * item = [[NSMenuItem alloc] initWithTitle:@"Preview Panel" action:@selector(toggleVisibility:) keyEquivalent:@"I"])
            {
                  [item setTarget:self];
                  [pController appendPanelItem:item];
                  [item release];
            }
}

- (void)toggleVisibility:(id)sender
{
      NSPanel * panel = (NSPanel *) [self window];

      if ([panel isVisible])
            [panel orderOut:self];
      else
            [panel orderFront:self];
}

- (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
{
      NSPanel * panel = (NSPanel *) [self window];

      [menuItem setState:([panel isVisible] ? NSOnState : NSOffState)];

      return YES;
}

- (void)setPreviewString:(NSString *)previewString
{
      [oPreview setStringValue:previewString];
}

@end

static XAP_CocoaToolPalette * s_instance = 0;

@implementation XAP_CocoaToolPalette

+ (XAP_CocoaToolPalette *)instance:(id)sender
{
      if (!s_instance)
            if (s_instance = [[XAP_CocoaToolPalette alloc] init])
                  {
                        [s_instance showWindow:sender];
                  }
      return s_instance;
}

+ (BOOL)instantiated
{
      return (s_instance ? YES : NO);
}

- (id)init
{
      if (self = [super initWithWindowNibName:@"xap_CocoaToolPalette"])
            {
                  m_ToolChest = 0;
                  m_PaletteView = 0;
                  m_Properties_DataSource = 0;

                  m_pMenuActionSet = 0;
                  m_pToolbarActionSet = 0;
                  m_pEditMethodContainer = 0;
                  m_pFontFamilies = 0;
                  m_pCurrentFontFamily = 0;
                  m_pCurrentFontFamilyHelper = 0;
                  m_Listener = 0;

                  m_pCocoaApp = static_cast<XAP_CocoaApp *>(XAP_App::getApp());

                  m_pMenuActionSet       = m_pCocoaApp->getMenuActionSet();
                  m_pToolbarActionSet    = m_pCocoaApp->getToolbarActionSet();
                  m_pEditMethodContainer = m_pCocoaApp->getEditMethodContainer();

                  if (!m_pToolbarActionSet || !m_pMenuActionSet || !m_pEditMethodContainer)
                        {
                              UT_ASSERT(m_pToolbarActionSet && m_pMenuActionSet && m_pEditMethodContainer);

                              [self dealloc];
                              self = nil;
                        }
            }
      if (self)
            {
                  NSArray * pAvailableFontFamilies = [[NSFontManager sharedFontManager] availableFontFamilies];

                  unsigned count = [pAvailableFontFamilies count];
                  if (count)
                        {
                              m_pFontFamilies = [[NSMutableArray alloc] initWithCapacity:count];
                              if (m_pFontFamilies)
                                    {
                                          for (unsigned ff = 0; ff < count; ff++)
                                                {
                                                      NSString * pFontFamily = [pAvailableFontFamilies objectAtIndex:ff];

                                                      /* const char * szFF = [pFontFamily UTF8String]; */

                                                      if (true /* (*szFF != '.') && (*szFF != '#') */) // cf. Bug 6638
                                                            {
                                                                  [m_pFontFamilies addObject:pFontFamily];
                                                            }
                                                }
                                          if ([m_pFontFamilies count])
                                                {
                                                      [m_pFontFamilies sortUsingSelector:@selector(compare:)];
                                                }
                                          else
                                                {
                                                      UT_DEBUGMSG(("XAP_CocoaToolPalette -init: no usable font families?\n"));

                                                      [m_pFontFamilies release];
                                                      m_pFontFamilies = 0;
                                                }
                                    }
                        }
                  else
                        {
                              UT_DEBUGMSG(("XAP_CocoaToolPalette -init: no available font families?\n"));
                        }
                  if (!m_pFontFamilies)
                        {
                              [self dealloc];
                              self = nil;
                        }
            }
      if (self)
            {
                  UT_TRY
                        {
                              m_ToolChest = new struct XAP_CocoaToolRef[XAP_COCOA_TOOL_ID__COUNT_];
                        }
                  UT_CATCH(...)
                        {
                              m_ToolChest = 0;
                        }
                  if (!m_ToolChest)
                        {
                              [self dealloc];
                              self = nil;
                        }
            }
      if (self)
            {
                  m_PaletteView = [[XAP_CocoaPaletteView alloc] init];
                  if (!m_PaletteView)
                        {
                              [self dealloc];
                              self = nil;
                        }
            }
      if (self)
            {
                  UT_TRY
                        {
                              m_Listener = new XAP_CocoaToolPaletteListener(self);
                        }
                  UT_CATCH(...)
                        {
                              m_Listener = 0;
                        }
                  if (!m_ToolChest)
                        {
                              [self dealloc];
                              self = nil;
                        }
            }
      return self;
}

- (void)dealloc
{
      if (m_Properties_DataSource)
            {
                  [m_Properties_DataSource release];
                  m_Properties_DataSource = 0;
            }
      if (m_PaletteView)
            if (![m_PaletteView superview])
                  {
                        [m_PaletteView dealloc];
                        m_PaletteView = 0;
                  }
      if (m_pFontFamilies)
            {
                  [m_pFontFamilies release];
                  m_pFontFamilies = 0;
            }
      if (m_pCurrentFontFamily)
            {
                  [m_pCurrentFontFamily release];
                  m_pCurrentFontFamily = 0;
            }
      if (m_pCurrentFontFamilyHelper)
            {
                  [m_pCurrentFontFamilyHelper release];
                  m_pCurrentFontFamilyHelper = 0;
            }
      DELETEP(m_ToolChest);
      DELETEP(m_Listener);

      [super dealloc];
}

- (void)windowDidLoad
{
      UT_DEBUGMSG(("XAP_CocoaToolPalette -windowDidLoad\n"));

      XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate];

      if (m_PaletteView)
            {
                  // TODO: localise palette titles based on toolbar names

                  struct XAP_CocoaPaletteRef palette;

                  [oTitle_Standard setTag:1];
                  palette.Name  = @"Standard";
                  palette.Title = oTitle_Standard;
                  palette.Box   = oBox_Standard;
                  [m_PaletteView addPalette:&palette];

                  [oTitle_Format setTag:1];
                  palette.Name  = @"Format";
                  palette.Title = oTitle_Format;
                  palette.Box   = oBox_Format;
                  [m_PaletteView addPalette:&palette];

                  [oTitle_Table setTag:0];
                  palette.Name  = @"Table";
                  palette.Title = oTitle_Table;
                  palette.Box   = oBox_Table;
                  [m_PaletteView addPalette:&palette];

                  [oTitle_Extra setTag:0];
                  palette.Name  = @"Extra";
                  palette.Title = oTitle_Extra;
                  palette.Box   = oBox_Extra;
                  [m_PaletteView addPalette:&palette];

                  [oTitle_Properties setTag:0];
                  palette.Name  = @"Properties";
                  palette.Title = oTitle_Properties;
                  palette.Box   = oBox_Properties;
                  [m_PaletteView addPalette:&palette];

                  NSRect content = [m_PaletteView frame];
                  NSRect frame = [NSWindow frameRectForContentRect:content styleMask:(NSTitledWindowMask|NSClosableWindowMask|NSUtilityWindowMask)];

                  NSRect visible_frame = [[oPanel screen] visibleFrame];
                  int x = static_cast<int>(visible_frame.size.width ) + static_cast<int>(visible_frame.origin.x);
                  int y = static_cast<int>(visible_frame.size.height) + static_cast<int>(visible_frame.origin.y);

                  frame.origin.x = static_cast<float>(x - static_cast<int>(frame.size.width ));
                  frame.origin.y = static_cast<float>(y - static_cast<int>(frame.size.height));

                  [oPanel setFrame:frame display:NO];
                  [oPanel setContentView:m_PaletteView];

                  [m_PaletteView setNeedsDisplay:YES];

                  [oPanel setFloatingPanel:YES];
                  [oPanel setBecomesKeyOnlyIfNeeded:YES];
                  [oPanel setReleasedWhenClosed:YES];
                  [oPanel setDelegate:self];

                  [self setWindow:oPanel];

                  if (NSMenuItem * item = [[NSMenuItem alloc] initWithTitle:@"Tool Palette" action:@selector(toggleVisibility:) keyEquivalent:@"T"])
                        {
                              [item setTarget:self];
                              [pController appendPanelItem:item];
                              [item release];
                        }
            }

#define defn(T,X,Y)                 m_ToolChest[ToolID_##T].button = T; \
                                          m_ToolChest[ToolID_##T].tlbrid = X; \
                                          m_ToolChest[ToolID_##T].ttipid = Y;
#include "xap_CocoaTools.h"
#undef defn

      const XAP_StringSet * pSS = m_pCocoaApp->getStringSet();

      const char * tooltip = 0;

      for (int i = 0; i < XAP_COCOA_TOOL_ID__COUNT_; i++)
            {
                  [m_ToolChest.button setTag:i];
                  [m_ToolChest.button setEnabled:NO];
                  [m_ToolChest.button setBordered:NO];

                  if (m_ToolChest[i].ttipid != AP_STRING_ID__FIRST__)
                        if (tooltip = pSS->getValue(m_ToolChest[i].ttipid))
                              {
                                    [m_ToolChest.button setToolTip:[NSString stringWithUTF8String:tooltip]];
                              }

                  if ([m_ToolChest[i].button isKindOfClass:[XAP_CocoaToolbarButton class]])
                        {
                              NSButtonCell * cell = (NSButtonCell *) [m_ToolChest[i].button cell];

                              [cell setShowsStateBy:NSNoCellMask];
                              [cell setHighlightsBy:NSNoCellMask];
                        }
            }

      if (tooltip = pSS->getValue(AP_STRING_ID_TOOLBAR_TOOLTIP_FMT_STYLE))
            {
                  [oDocumentStyle setToolTip:[NSString stringWithUTF8String:tooltip]];
            }
      if (tooltip = pSS->getValue(AP_STRING_ID_TOOLBAR_TOOLTIP_FMT_FONT))
            {
                  [oFontName setToolTip:[NSString stringWithUTF8String:tooltip]];
            }
      if (tooltip = pSS->getValue(AP_STRING_ID_TOOLBAR_TOOLTIP_FMT_SIZE))
            {
                  [oFontSize setToolTip:[NSString stringWithUTF8String:tooltip]];
            }
      if (tooltip = pSS->getValue(AP_STRING_ID_TOOLBAR_TOOLTIP_ZOOM))
            {
                  [oZoom setToolTip:[NSString stringWithUTF8String:tooltip]];
            }

      [self rebuildFontFamilyPopUp];

      [[oFontName       menu] setAutoenablesItems:NO];
      [[oFontMemberName menu] setAutoenablesItems:NO];

      [[oDocumentStyle menu] setAutoenablesItems:NO];

      if (m_Properties_DataSource = [[XAP_PaletteProperties_DataSource alloc] initWithOutlineView:oProperties])
            {
                  [oProperties setIndentationPerLevel:10.0f];
                  [oProperties setDataSource:m_Properties_DataSource];
                  [oProperties setDelegate:m_Properties_DataSource];
            }

      [oPreviewPanel windowDidLoad];

      [self setCurrentView:[pController currentView] inFrame:[pController currentFrame]];
      [self sync];
}

- (void)close
{
      UT_DEBUGMSG(("XAP_CocoaToolPalette -close\n"));
      s_instance = 0;
      [super close];
}

- (void)windowWillClose
{
      UT_DEBUGMSG(("XAP_CocoaToolPalette -windowWillClose\n"));
}

- (void)toggleVisibility:(id)sender
{
      if ([oPanel isVisible])
            [oPanel orderOut:self];
      else
            [oPanel orderFront:self];
}

- (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
{
      [menuItem setState:([oPanel isVisible] ? NSOnState : NSOffState)];

      return YES;
}

+ (void)setPreviewText:(id)previewText
{
      if (s_instance) {
            if ([previewText isKindOfClass:[NSString class]]) {
                  NSString * str = (NSString *) previewText;
                  [s_instance setPreviewString:str];
            }
            if ([previewText isKindOfClass:[NSAttributedString class]]) {
                  NSAttributedString * str = (NSAttributedString *) previewText;
                  [s_instance setPreviewString:[str string]];
            }
      }
}

- (void)setPreviewString:(NSString *)previewString
{
      [oPreview setStringValue:previewString];

      [oPreviewPanel setPreviewString:previewString];
}

- (NSWindow *)previewPanel
{
      return [oPreviewPanel window];
}

- (void)setColor:(XAP_Toolbar_Id)tlbrid
{
      if (!m_pViewCurrent)
            return;

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(tlbrid);
      UT_ASSERT(pAction);
      if (!pAction)
            return;

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            return;

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            return;

      UT_DEBUGMSG(("XAP_CocoaToolPalette -setColor: have edit method\n"));

      float red;
      float green;
      float blue;
      float alpha;

      NSColor * color = [[NSColorPanel sharedColorPanel] color];

      [color getRed:&red green:&green blue:&blue alpha:&alpha]; // TODO: is color necessarily RGBA? if not, could be a problem...

      int r = static_cast<int>(lrintf(red   * 255));  r = (r < 0) ? 0 : r;    r = (r > 255) ? 255 : r;
      int g = static_cast<int>(lrintf(green * 255));  g = (g < 0) ? 0 : g;    g = (g > 255) ? 255 : g;
      int b = static_cast<int>(lrintf(blue  * 255));  b = (b < 0) ? 0 : b;    b = (b > 255) ? 255 : b;

      UT_HashColor hash;

      const char * color_string = hash.setColor(static_cast<unsigned char>(r),
                                                                    static_cast<unsigned char>(g),
                                                                    static_cast<unsigned char>(b));
      if (color_string)
            {
                  UT_UCS4String color_data(color_string);

                  const UT_UCS4Char * pData = color_data.ucs4_str();
                  UT_uint32 dataLength = static_cast<UT_uint32>(color_data.length());

                  EV_EditMethodCallData emcd(pData,dataLength);
                  pEM->Fn(m_pViewCurrent, &emcd);
            }
}

- (IBAction)aColor_FG:(id)sender
{
      [self setColor:AP_TOOLBAR_ID_COLOR_FORE];
}

- (IBAction)aColor_BG:(id)sender
{
      [self setColor:AP_TOOLBAR_ID_COLOR_BACK];
}

- (IBAction)aSwitch_FG:(id)sender
{
      // TODO
}

- (IBAction)aSwitch_BG:(id)sender
{
      // TODO
}

- (IBAction)aTitle_click:(id)sender
{
      NSButton * title = (NSButton *) sender;

      if ([title tag] == 0)
            [title setTag:1];
      else
            [title setTag:0];

      [m_PaletteView sync];
      [m_PaletteView setNeedsDisplay:YES];
}

- (IBAction)aDocumentStyle:(id)sender
{
      if (!m_pViewCurrent)
            return;

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_STYLE);
      UT_ASSERT(pAction);
      if (!pAction)
            return;

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            return;

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            return;

      UT_DEBUGMSG(("XAP_CocoaToolPalette -aDocumentStyle: have edit method\n"));

      UT_UCS4String selection([[oDocumentStyle titleOfSelectedItem] UTF8String]);

      const UT_UCS4Char * pData = selection.ucs4_str();
      UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

      EV_EditMethodCallData emcd(pData,dataLength);
      pEM->Fn(m_pViewCurrent, &emcd);
}

- (IBAction)aFontName:(id)sender
{
      if (!m_pViewCurrent)
            return;

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_FONT);
      UT_ASSERT(pAction);
      if (!pAction)
            return;

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            return;

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            return;

      UT_DEBUGMSG(("XAP_CocoaToolPalette -aFontName: have edit method\n"));

      UT_UCS4String selection([[oFontName titleOfSelectedItem] UTF8String]);

      const UT_UCS4Char * pData = selection.ucs4_str();
      UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

      EV_EditMethodCallData emcd(pData,dataLength);
      pEM->Fn(m_pViewCurrent, &emcd);
}

- (IBAction)aFontMemberName:(id)sender
{
      if (!m_pViewCurrent)
            return;

      if (!m_pCurrentFontFamily || !m_pCurrentFontFamilyHelper)
            {
                  return;
            }

      int index = [[oFontMemberName selectedItem] tag];

      NSString * fontFamilyName = m_pCurrentFontFamily;

      BOOL bBold   = ([oTB_text_bold   state] == NSOnState) ? YES : NO; // current state
      BOOL bItalic = ([oTB_text_italic state] == NSOnState) ? YES : NO;

      BOOL bSetBold   = NO;
      BOOL bSetItalic = NO;

      if (index == [m_pCurrentFontFamilyHelper indexBoldItalic])
            {
                  bSetBold   = YES;
                  bSetItalic = YES;
            }
      else if (index == [m_pCurrentFontFamilyHelper indexBold])
            {
                  bSetBold   = YES;
            }
      else if (index == [m_pCurrentFontFamilyHelper indexItalic])
            {
                  bSetItalic = YES;
            }
      else if (index == [m_pCurrentFontFamilyHelper indexRegular])
            {
                  // 
            }
      else // need to set an explicit font name rather than a font family name...
            {
                  NSArray * fontNames = [m_pCurrentFontFamilyHelper fontNames];

                  fontFamilyName = [fontNames objectAtIndex:index];
            }

      /* fontFamilyName gets corrupted for some probably obvious reason, so copy it here and now...
       */
      UT_UCS4String selection([fontFamilyName UTF8String]);

      if (bBold != bSetBold)
            {
                  [oTB_text_bold setState:(bSetBold ? NSOnState : NSOffState)];
                  [self aTB_click:oTB_text_bold];
            }

      if (bItalic != bSetItalic)
            {
                  [oTB_text_italic setState:(bSetItalic ? NSOnState : NSOffState)];
                  [self aTB_click:oTB_text_italic];
            }

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_FONT);
      UT_ASSERT(pAction);
      if (!pAction)
            return;

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            return;

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            return;

      UT_DEBUGMSG(("XAP_CocoaToolPalette -aFontMemberName: have edit method\n"));

      const UT_UCS4Char * pData = selection.ucs4_str();
      UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

      EV_EditMethodCallData emcd(pData,dataLength);
      pEM->Fn(m_pViewCurrent, &emcd);
}

- (IBAction)aFontSize:(id)sender
{
      if (!m_pViewPrevious)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_SIZE);
      UT_ASSERT(pAction);
      if (!pAction)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      UT_DEBUGMSG(("XAP_CocoaToolPalette -aFontSize: have edit method\n"));

      int size = [oFontSize intValue];

      if (size < 1)
            size = 1;   // TODO: ??
      if (size > 100)
            size = 100; // TODO: ??

      char buf;
      sprintf(buf, "%d", size);

      UT_UCS4String selection(buf);

      const UT_UCS4Char * pData = selection.ucs4_str();
      UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

      EV_EditMethodCallData emcd(pData,dataLength);
      pEM->Fn(m_pViewPrevious, &emcd);

      if (m_pFramePrevious)
            m_pFramePrevious->raise();
}

- (IBAction)aTB_click:(id)sender
{
      NSButton * button = (NSButton *) sender;

      int tag = [button tag];

      if ((tag < 0) || (tag >= XAP_COCOA_TOOL_ID__COUNT_))
            {
                  UT_DEBUGMSG(("XAP_CocoaToolPalette -aTB_click: invalid tag\n"));
                  return;
            }
      // button == m_ToolChest[tag].button;

      // TODO: other special buttons

      XAP_Toolbar_Id tlbrid = m_ToolChest.tlbrid;

      if (!m_pViewCurrent)
            {
                  if ((tlbrid == AP_TOOLBAR_ID_FILE_NEW ) ||
                        (tlbrid == AP_TOOLBAR_ID_FILE_OPEN) ||
                        (tlbrid == AP_TOOLBAR_ID_HELP))
                        {
                              // Only these are okay
                        }
                  else
                        {
                              return;
                        }
            }

      /* Toolbar fore- & background color buttons don't actually set the color, they just ensure that the
       * color-chooser is visible & correctly configured:
       */
      if ((tlbrid == AP_TOOLBAR_ID_COLOR_FORE) || (tlbrid == AP_TOOLBAR_ID_COLOR_BACK))
            {
                  NSColorPanel * colorPanel = [NSColorPanel sharedColorPanel];

                  // ?? [NSColorPanel setPickerMask:(NSColorPanelRGBModeMask|NSColorPanelWheelModeMask|NSColorPanelGrayModeMask)];

                  [colorPanel setAction:0];
                  [colorPanel setTarget:0];

                  if (tlbrid == AP_TOOLBAR_ID_COLOR_FORE)
                        {
                              // [colorPanel setTitle:@"Foreground Color"]; // TODO: Localize
                              [colorPanel setColor:[oColor_FG color]];
                              [colorPanel setAction:@selector(aColor_FG:)];
                        }
                  else
                        {
                              // [colorPanel setTitle:@"Background Color"]; // TODO: Localize
                              [colorPanel setColor:[oColor_BG color]];
                              [colorPanel setAction:@selector(aColor_BG:)];
                        }
                  [colorPanel orderFront:self];
                  [colorPanel setTarget:self];

                  return;
            }

      if (tlbrid)
            {
                  const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(tlbrid);
                  UT_ASSERT(pAction);
                  if (!pAction)
                        return;

                  const char * szMethodName = pAction->getMethodName();
                  if (!szMethodName)
                        return;

                  EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
                  if (!pEM)
                        return;

                  UT_DEBUGMSG(("XAP_CocoaToolPalette -aTB_click: have edit method\n"));

                  EV_EditMethodType t = pEM->getType();

                  if (t & EV_EMT_REQUIREDATA) // This method requires character data
                        {
                              UT_DEBUGMSG(("XAP_CocoaToolPalette -aTB_click: method requires data\n"));
                        }
                  else
                        {
                              const UT_UCS4Char * pData = 0;
                              UT_uint32 dataLength = 0;

                              EV_EditMethodCallData emcd(pData,dataLength);
                              pEM->Fn(m_pViewCurrent, &emcd);
                        }
            }
      else
            {
                  switch (tag)
                        {
                        case ToolID_oTB_LineAll:
                        case ToolID_oTB_LineBottom:
                        case ToolID_oTB_LineLeft:
                        case ToolID_oTB_LineNone:
                        case ToolID_oTB_LineRight:
                        case ToolID_oTB_LineTop:
                              // TODO: this is something else. use menu methods, perhaps
                              break;

                        case ToolID_oTB_search:
                              {
                                    bool okay = false;

                                    const EV_Menu_Action * pAction = m_pMenuActionSet->getAction(AP_MENU_ID_EDIT_FIND);
                                    if (m_pViewCurrent && pAction)
                                          if (const char * szMethodName = pAction->getMethodName())
                                          {
                                                EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
                                                if (pEM)
                                                      {
                                                            EV_EditMethodCallData data;
                                                            okay = pEM->Fn(m_pViewCurrent, &data);
                                                      }
                                          }
                                    if (!okay)
                                          {
                                                UT_DEBUGMSG(("XAP_CocoaToolPalette -aTB_click: ToolID_oTB_search: failed!\n"));
                                          }
                              }
                              break;
                        case ToolID_oTB_search_replace:
                              {
                                    bool okay = false;

                                    const EV_Menu_Action * pAction = m_pMenuActionSet->getAction(AP_MENU_ID_EDIT_REPLACE);
                                    if (m_pViewCurrent && pAction)
                                          if (const char * szMethodName = pAction->getMethodName())
                                          {
                                                EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
                                                if (pEM)
                                                      {
                                                            EV_EditMethodCallData data;
                                                            okay = pEM->Fn(m_pViewCurrent, &data);
                                                      }
                                          }
                                    if (!okay)
                                          {
                                                UT_DEBUGMSG(("XAP_CocoaToolPalette -aTB_click: ToolID_oTB_search_replace: failed!\n"));
                                          }
                              }
                              break;

                        case ToolID_oTB_SplitAbove:
                        case ToolID_oTB_SplitBelow:
                        case ToolID_oTB_SplitHoriMid:
                        case ToolID_oTB_SplitLeft:
                        case ToolID_oTB_SplitRight:
                        case ToolID_oTB_SplitVertMid:
                              // TODO: this is something else. use menu methods, perhaps
                              break;

                        default:
                              UT_DEBUGMSG (("XAP_CocoaToolPalette -aTB_click: Unimplemented toolbar button!\n"));
                              break;
                        }
            }
}

- (IBAction)aZoom:(id)sender
{
      if (!m_pViewPrevious)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_ZOOM);
      UT_ASSERT(pAction);
      if (!pAction)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      const char * szMethodName = pAction->getMethodName();
      if (!szMethodName)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      EV_EditMethod * pEM = m_pEditMethodContainer->findEditMethodByName(szMethodName);
      if (!pEM)
            {
                  if (m_pFramePrevious)
                        m_pFramePrevious->raise();
                  return;
            }

      UT_DEBUGMSG(("XAP_CocoaToolPalette -aZoom: have edit method\n"));

      NSString * value = [oZoom stringValue];

      if ([value isEqualToString:@"Whole Page"] || [value isEqualToString:@"Page Width"])
            {
                  UT_UCS4String selection([value UTF8String]);

                  const UT_UCS4Char * pData = selection.ucs4_str();
                  UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

                  EV_EditMethodCallData emcd(pData,dataLength);
                  pEM->Fn(m_pViewPrevious, &emcd);
            }
      else
            {
                  int size = [oZoom intValue];

                  if (size < 1)
                        size = 1;    // TODO: ??
                  if (size > 1000)
                        size = 1000; // TODO: ??

                  char buf;
                  sprintf(buf, "%d", size);

                  UT_UCS4String selection(buf);

                  const UT_UCS4Char * pData = selection.ucs4_str();
                  UT_uint32 dataLength = static_cast<UT_uint32>(selection.length());

                  EV_EditMethodCallData emcd(pData,dataLength);
                  pEM->Fn(m_pViewPrevious, &emcd);
            }
      if (m_pFramePrevious)
            m_pFramePrevious->raise();
}

- (void)sync
{
      /* toolbar buttons
       */
      for (UT_uint32 i = 0; i < XAP_COCOA_TOOL_ID__COUNT_; i++)
            {
                  if (m_ToolChest[i].tlbrid)
                        {
                              if (!m_pViewCurrent)
                                    {
                                          if ((m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_FILE_NEW ) ||
                                                (m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_FILE_OPEN) ||
                                                (m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_HELP))
                                                {
                                                      [m_ToolChest.button setEnabled:YES];
                                                }
                                          else
                                                {
                                                      [m_ToolChest.button setEnabled:NO];
                                                }
                                          continue;
                                    }

                              if ((m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_MERGEABOVE) ||
                                    (m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_MERGEBELOW) ||
                                    (m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_MERGELEFT ) ||
                                    (m_ToolChest[i].tlbrid == AP_TOOLBAR_ID_MERGERIGHT))
                                    {
                                          /* WARNING: MERGELEFT/RIGHT/ABOVE/BELOW need to be implemented properly in toolbar actions!
                                           */
                                          [m_ToolChest.button setEnabled:NO];
                                          continue;
                                    }

                              const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(m_ToolChest[i].tlbrid);
                              UT_ASSERT(pAction);
                              if (!pAction)
                                    continue;

                              const char * szState = 0;
                              EV_Toolbar_ItemState tis = pAction->getToolbarItemState(m_pViewCurrent, &szState);

                              switch (pAction->getItemType())
                                    {
                                    case EV_TBIT_PushButton:
                                    case EV_TBIT_ColorFore:
                                    case EV_TBIT_ColorBack:
                                          {
                                                [m_ToolChest.button setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];
                                          }
                                          break;
                  
                                    case EV_TBIT_ToggleButton:
                                    case EV_TBIT_GroupButton:
                                          {
                                                [m_ToolChest.button setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];
                                                [m_ToolChest.button setState:(EV_TIS_ShouldBeToggled(tis) ? NSOnState : NSOffState)];
                                          }
                                          break;

                                    case EV_TBIT_StaticLabel:
                                    case EV_TBIT_Spacer:
                                    case EV_TBIT_BOGUS:
                                    case EV_TBIT_EditText:
                                    case EV_TBIT_DropDown:
                                    case EV_TBIT_ComboBox: // handled elsewhere
                                          break;

                                    default:
                                          UT_DEBUGMSG (("XAP_CocoaToolPalette -sync: Unexpected toolbar layout flags!\n"));
                                          UT_ASSERT(0);
                                          break;
                                    }
                        }
                  else
                        {
                              switch (i) // well, okay, a little insane to switch this, but...
                                    {
                                    case ToolID_oTB_LineAll:
                                    case ToolID_oTB_LineBottom:
                                    case ToolID_oTB_LineLeft:
                                    case ToolID_oTB_LineNone:
                                    case ToolID_oTB_LineRight:
                                    case ToolID_oTB_LineTop:
                                          // TODO: this is something else. use menu methods, perhaps
                                          [m_ToolChest.button setEnabled:NO];
                                          break;

                                    case ToolID_oTB_search:
                                    case ToolID_oTB_search_replace:
                                                [m_ToolChest.button setEnabled:(m_pViewCurrent ? YES : NO)];
                                          break;

                                    case ToolID_oTB_SplitAbove:
                                    case ToolID_oTB_SplitBelow:
                                    case ToolID_oTB_SplitHoriMid:
                                    case ToolID_oTB_SplitLeft:
                                    case ToolID_oTB_SplitRight:
                                    case ToolID_oTB_SplitVertMid:
                                          // TODO: this is something else. use menu methods, perhaps
                                          [m_ToolChest.button setEnabled:NO];
                                          break;

                                    default:
                                          UT_DEBUGMSG (("XAP_CocoaToolPalette -sync: Unimplemented toolbar button!\n"));
                                          [m_ToolChest.button setEnabled:NO];
                                          break;
                                    }
                        }
            }

      /* Document styles
       */
      [oDocumentStyle removeAllItems];
      [oDocumentStyle setEnabled:NO];

      if (m_pFrameCurrent)
            if (PD_Document * pDoc = static_cast<PD_Document *>(m_pFrameCurrent->getCurrentDoc()))
                  {
                        const char * szName = 0;
                        const PD_Style * pStyle = 0;

                        NSMutableArray * styles = [NSMutableArray arrayWithCapacity:32];

                        for (UT_uint32 k = 0; (pDoc->enumStyles(k, &szName, &pStyle)); k++)
                              if (szName)
                                    {
#if 1
                                          [styles addObject:[NSString stringWithUTF8String:szName]];
#else
                                          // TODO: Make style names reflect properties such as: font, size, alignment ??
                                          NSString * name = [NSString stringWithUTF8String:szName];

                                          NSDictionary * attr = TODO

                                          [oDocumentStyle addItemWithTitle:[NSAttributedString initWithString:name attributes:attr]];
#endif
                                    }
                        [styles sortUsingSelector:@selector(compare:)];

                        [oDocumentStyle addItemsWithTitles:styles];

                        const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_STYLE);
                        UT_ASSERT(pAction);
                        if (pAction)
                              {
                                    const char * szState = 0;
                                    EV_Toolbar_ItemState tis = pAction->getToolbarItemState(m_pViewCurrent, &szState);

                                    [oDocumentStyle setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];

                                    UT_ASSERT(szState);
                                    if (szState)
                                          {
                                                [oDocumentStyle selectItemWithTitle:[NSString stringWithUTF8String:szState]];
                                          }
                              }
                  }

      /* Font name
       */
      [oFontName setEnabled:NO];

      if (m_pViewCurrent)
            {
                  const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_FONT);
                  UT_ASSERT(pAction);
                  if (pAction)
                        {
                              const char * szState = 0;
                              EV_Toolbar_ItemState tis = pAction->getToolbarItemState(m_pViewCurrent, &szState);

                              [oFontName setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];

                              // UT_ASSERT(szState); // This assert is triggered if the selection contains multiple fonts?
                              if (szState)
                                    {
                                          [self syncPopUpsForFont:[NSString stringWithUTF8String:szState]];
                                    }
                        }
            }

      /* Font size
       */
      [oFontSize setEnabled:NO];

      if (m_pViewCurrent)
            {
                  const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_FMT_SIZE);
                  UT_ASSERT(pAction);
                  if (pAction)
                        {
                              const char * szState = 0;
                              EV_Toolbar_ItemState tis = pAction->getToolbarItemState(m_pViewCurrent, &szState);

                              [oFontSize setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];

                              if (szState)
                                    {
                                          NSString * selection = [NSString stringWithUTF8String:szState];

                                          int index = [oFontSize indexOfItemWithObjectValue:selection];

                                          if (index == NSNotFound)
                                                {
                                                      index = [oFontSize indexOfSelectedItem];

                                                      if (index >= 0)
                                                            {
                                                                  [oFontSize deselectItemAtIndex:index];
                                                            }
                                                }
                                          else
                                                {
                                                      [oFontSize selectItemAtIndex:index];
                                                }
                                          [oFontSize setStringValue:selection];
                                    }
                              else // mixed selection
                                    {
                                          [oFontSize setStringValue:@""];
                                    }
                        }
            }

      /* Zoom
       */
      [oZoom setEnabled:NO];

      if (m_pViewCurrent)
            {
                  const EV_Toolbar_Action * pAction = m_pToolbarActionSet->getAction(AP_TOOLBAR_ID_ZOOM);
                  UT_ASSERT(pAction);
                  if (pAction)
                        {
                              const char * szState = 0;
                              EV_Toolbar_ItemState tis = pAction->getToolbarItemState(m_pViewCurrent, &szState);

                              [oZoom setEnabled:(EV_TIS_ShouldBeGray(tis) ? NO : YES)];

                              UT_ASSERT(szState);
                              if (szState)
                                    {
                                          NSString * selection = [NSString stringWithUTF8String:szState];

                                          int index = [oZoom indexOfItemWithObjectValue:selection];

                                          if (index == NSNotFound)
                                                {
                                                      index = [oZoom indexOfSelectedItem];

                                                      if (index >= 0)
                                                            {
                                                                  [oZoom deselectItemAtIndex:index];
                                                            }
                                                }
                                          else
                                                {
                                                      [oZoom selectItemAtIndex:index];
                                                }
                                          [oZoom setStringValue:selection];
                                    }
                        }
            }

      /* Color buttons
       */
      [oSwitch_FG setEnabled:NO]; // TODO
      [oSwitch_BG setEnabled:NO]; // TODO

      if (m_pViewCurrent)
            {
                  FV_View * pFView = static_cast<FV_View *>(m_pViewCurrent);

                  bool bMixedSelection;
                  bool bExplicitlyDefined;

                  UT_UTF8String szColorValue;

                  if (pFView->queryCharFormat("color", szColorValue, bExplicitlyDefined, bMixedSelection))
                        {
                              [oSwitch_FG setState:(bExplicitlyDefined ? NSOnState : NSOffState)];

                              UT_HashColor hash;

                              bool bValid = (hash.setColor(szColorValue.utf8_str()) != 0);
                              if (!bValid)
                                    bValid = (hash.setHashIfValid(szColorValue.utf8_str()) != 0);

                              if (bValid)
                                    {
                                          UT_RGBColor rgb = hash.rgb();

                                          float r = static_cast<float>(rgb.m_red) / 255;
                                          float g = static_cast<float>(rgb.m_grn) / 255;
                                          float b = static_cast<float>(rgb.m_blu) / 255;
                                          float a = 1;

                                          [oColor_FG setColor:[NSColor colorWithDeviceRed:r green:g blue:b alpha:a]];
                                    }
                              else
                                    {
                                          UT_DEBUGMSG(("XAP_CocoaToolPalette -sync: fg=\"%s\"?\n", szColorValue.utf8_str()));
                                    }
                        }
                  if (pFView->queryCharFormat("bgcolor", szColorValue, bExplicitlyDefined, bMixedSelection))
                        {
                              [oSwitch_BG setState:(bExplicitlyDefined ? NSOnState : NSOffState)];

                              if (strcmp (szColorValue.utf8_str(), "transparent") == 0)
                                    {
                                          float r = 1;
                                          float g = 1;
                                          float b = 1;
                                          float a = 0;

                                          [oColor_BG setColor:[NSColor colorWithDeviceRed:r green:g blue:b alpha:a]];
                                    }
                              else
                                    {
                                          UT_HashColor hash;

                                          bool bValid = (hash.setColor(szColorValue.utf8_str()) != 0);
                                          if (!bValid)
                                                bValid = (hash.setHashIfValid(szColorValue.utf8_str()) != 0);

                                          if (bValid)
                                                {
                                                      UT_RGBColor rgb = hash.rgb();

                                                      float r = static_cast<float>(rgb.m_red) / 255;
                                                      float g = static_cast<float>(rgb.m_grn) / 255;
                                                      float b = static_cast<float>(rgb.m_blu) / 255;
                                                      float a = 1;

                                                      [oColor_BG setColor:[NSColor colorWithDeviceRed:r green:g blue:b alpha:a]];
                                                }
                                          else
                                                {
                                                      UT_DEBUGMSG(("XAP_CocoaToolPalette -sync: bg=\"%s\"?\n", szColorValue.utf8_str()));
                                                }
                                    }
                        }
            }

      /* Properties OutlineView
       */
      [m_Properties_DataSource syncWithView:(static_cast<FV_View *>(m_pViewCurrent))];
}

- (void)setCurrentView:(AV_View *)view inFrame:(XAP_Frame *)frame
{
      if (!self) return;

      /* Need to be careful. A frame/view can switch out because keyboard
       * focus has changed (e.g., because a combo-box in the panel has stolen
       * focus) or it may have been killed...
       */
      m_pViewPrevious  = m_pViewCurrent;
      m_pFramePrevious = m_pFrameCurrent;

      bool bSync = false;

      if (frame && view)
            {
                  m_pViewCurrent  = view;
                  m_pFrameCurrent = frame;

                  bSync = true;
            }
      else if (!frame && !view)
            {
                  m_pViewCurrent  = 0;
                  m_pFrameCurrent = 0;

                  // should we sync in this case?
            }
      else
            {
                  UT_ASSERT(view && frame);

                  m_pViewCurrent  = 0;
                  m_pFrameCurrent = 0;

                  bSync = true;
            }

      m_Listener->setCurrentView(m_pViewCurrent);

      if (bSync)
            [self sync];
}

- (void)rebuildFontFamilyPopUp
{
      XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate];

      [oFontName removeAllItems];

      unsigned count = [m_pFontFamilies count];

      BOOL bAttributedTitles = YES;

      for (unsigned i = 0; i < count; i++)
            {
                  NSString * Family = [m_pFontFamilies objectAtIndex:i];

                  [oFontName addItemWithTitle:Family];

                  NSMenuItem * item = [oFontName lastItem];

                  [item setTag:((int) i)];

                  if (i == 0)
                        {
                              bAttributedTitles = [item respondsToSelector:@selector(setAttributedTitle:)];
                        }
                  if (bAttributedTitles)
                        {
                              XAP_CocoaFontFamilyHelper * helper = [pController helperForFontFamily:Family];

                              [item setAttributedTitle:[helper attributedFontFamilyName]];
                        }
            }
}

- (void)syncPopUpsForFont:(NSString *)requestedFontFamilyName
{
      /* requestedFontFamilyName is one of:
       * 
       * (a) a recognized font family name
       * (b) really a font name
       * (c) completely unknown, so we pretend it's a new font family name
       */

      NSString * fontFamilyName = 0;

      XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate];

      XAP_CocoaFontReference * fontRef = 0;

      XAP_CocoaFontFamilyHelper * helper = [pController helperForFontFamily:requestedFontFamilyName];

      if (helper)
            {
                  // (a) a recognized font family name

                  fontFamilyName = requestedFontFamilyName;
            }
      else if (fontRef = [pController helperReferenceForFont:requestedFontFamilyName])
            {
                  // (b) really a font name

                  fontFamilyName = [fontRef fontFamily];

                  helper = [fontRef fontFamilyHelper];
            }
      else
            {
                  // (c) completely unknown, so we pretend it's a new font family name

                  fontFamilyName = requestedFontFamilyName;

                  helper = [pController helperForUnknownFontFamily:requestedFontFamilyName];

                  /* In this case we need to modify the list of font families
                   */

                  [m_pFontFamilies addObject:fontFamilyName];
                  [m_pFontFamilies sortUsingSelector:@selector(compare:)];

                  [self rebuildFontFamilyPopUp];
            }

      BOOL bRebuildMemberPopUp = YES;

      if (m_pCurrentFontFamily)
            {
                  if ([m_pCurrentFontFamily isEqualToString:fontFamilyName])
                        {
                              bRebuildMemberPopUp = NO;
                        }
                  [m_pCurrentFontFamily release];
            }
      m_pCurrentFontFamily = fontFamilyName;
      [m_pCurrentFontFamily retain];

      if (m_pCurrentFontFamilyHelper)
            {
                  [m_pCurrentFontFamilyHelper release];
            }
      m_pCurrentFontFamilyHelper = helper;
      [m_pCurrentFontFamilyHelper retain];

      [oFontName selectItemWithTitle:m_pCurrentFontFamily];

      unsigned count = [helper count];

      NSArray * fontMembers = [helper fontMembers];

      if (bRebuildMemberPopUp)
            {
                  [oFontMemberName removeAllItems];

                  NSArray * attributedFontMembers = [helper attributedFontMembers];

                  BOOL bAttributedTitles = YES;

                  for (unsigned i = 0; i < count; i++)
                        {
                              NSString * fontMember = [fontMembers objectAtIndex:i];

                              [oFontMemberName addItemWithTitle:fontMember];

                              NSMenuItem * item = [oFontMemberName lastItem];

                              [item setTag:((int) i)];

                              if (i == 0)
                                    {
                                          bAttributedTitles = [item respondsToSelector:@selector(setAttributedTitle:)];
                                    }
                              if (bAttributedTitles)
                                    {
                                          NSAttributedString * attr_title = [attributedFontMembers objectAtIndex:i];

                                          [item setAttributedTitle:attr_title];
                                    }
                        }
                  [oFontMemberName setEnabled:((count > 1) ? YES : NO)];
            }
      if (count == 1)
            {
                  return;
            }
      if (fontRef)
            {
                  [oFontMemberName selectItemAtIndex:((int) [fontRef index])];
                  return;
            }

      /* We have a font family name but we need to choose a particular member of the font...
       */
      BOOL bBold   = ([oTB_text_bold   state] == NSOnState) ? YES : NO;
      BOOL bItalic = ([oTB_text_italic state] == NSOnState) ? YES : NO;

      if (bBold && bItalic)
            {
                  int index = [helper indexBoldItalic];
                  if (index >= 0)
                        {
                              [oFontMemberName selectItemAtIndex:index];
                              return;
                        }
            }
      else if (bBold)
            {
                  int index = [helper indexBold];
                  if (index >= 0)
                        {
                              [oFontMemberName selectItemAtIndex:index];
                              return;
                        }
            }
      else if (bItalic)
            {
                  int index = [helper indexItalic];
                  if (index >= 0)
                        {
                              [oFontMemberName selectItemAtIndex:index];
                              return;
                        }
            }
      else
            {
                  int index = [helper indexRegular];

                  [oFontMemberName selectItemAtIndex:((index >= 0) ? index : 0)];
            }
}

@end

XAP_CocoaToolPaletteListener::XAP_CocoaToolPaletteListener(XAP_CocoaToolPalette * pPalette) :
      m_pPalette(pPalette),
      m_pView(0)
{
      // 
}

XAP_CocoaToolPaletteListener::~XAP_CocoaToolPaletteListener()
{
      setCurrentView(0);
}

void XAP_CocoaToolPaletteListener::setCurrentView(AV_View * view)
{
      if (m_pView)
            {
                  if (!m_pView->removeListener(m_lid))
                        {
                              UT_DEBUGMSG(("XAP_CocoaToolPaletteListener::setCurrentView: failed to remove listener!\n"));
                        }
                  m_pView = 0;
            }
      if (view)
            {
                  if (view->addListener(this, &m_lid))
                        {
                              m_pView = view;
                        }
                  else
                        {
                              UT_DEBUGMSG(("XAP_CocoaToolPaletteListener::setCurrentView: failed to add listener!\n"));
                        }
            }
}

bool XAP_CocoaToolPaletteListener::notify(AV_View * pView, const AV_ChangeMask mask)
{
      if (pView == m_pView)
            {
                  [m_pPalette sync];
            }
      return true; // why is this a bool function?
}

AV_ListenerType XAP_CocoaToolPaletteListener::getType()
{
      return AV_LISTENER_TOOLBAR;
}

Generated by  Doxygen 1.6.0   Back to index