/*
**  Toolbox.m
**
**  Copyright (c) 2003
**
**  Author: Yen-Ju  <yjchenx@hotmail.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 "Toolbox.h"
#include "ExtendedBrowser.h"
#include "ExtendedMatrix.h"
#include "ItemPanel.h"
#include "ItemImportPanel.h"
#include "ItemInfoPanel.h"
#include "ItemHelpPanel.h"
#include "ToolboxWindow.h"
#include <Toolbox/BundleLoader.h>
#include <Toolbox/ToolboxBundleProtocol.h>
#include <AppKit/AppKit.h>

@implementation Toolbox

- (void) orderFrontItemInfoPanel: (id) sender
{
  int selectedItem, selectedCategory = [browserView selectedRowInColumn: 0];
  id object;

  if ([browserView selectedColumn] == 0) /* No item selected */
    return;

  selectedItem = [browserView selectedRowInColumn: 1];
  object = [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"] objectAtIndex: selectedItem];

  if ((selectedCategory > -1) || (selectedItem > -1))
    {
      NSMutableDictionary *plist;
      NSString *infoPath, *iconPath;
      ItemInfoPanel *infoPanel;
      NSImage *icon;

      infoPath = [loader pathForResource: @"Info-gnustep"
                                  ofType: @"plist"
                                ofBundle: [object objectForKey: @"bundle"]];
      plist = [NSMutableDictionary dictionaryWithContentsOfFile: infoPath];
      if([plist objectForKey: @"ApplicationName"] == nil)
        {
          [plist setObject: [object objectForKey: @"bundle"]
                    forKey: @"ApplicationName"];
        }

      if([plist objectForKey: @"ApplicationIcon"])
        { 
          iconPath = [[infoPath stringByDeletingLastPathComponent] stringByAppendingPathComponent: [plist objectForKey: @"ApplicationIcon"]];
          icon = [[NSImage alloc] initWithContentsOfFile: iconPath];
          /* iconPath expired because it share the same key of icon */
          iconPath = nil;
          [plist setObject: icon forKey: @"ApplicationIcon"];
          RELEASE(icon);
        }
      infoPanel = [[ItemInfoPanel alloc] initWithDictionary: plist];
      [infoPanel setTitle: @"Toolbox Info Panel"];
      [infoPanel setReleasedWhenClosed: YES];
      [infoPanel orderFront: self];
    }
}

- (void) orderFrontItemHelpPanel: (id) sender
{
  NSString *bundle;

  if (sender == [itemPanel helpButton])
    bundle = [[loader allNamesOfBundles] objectAtIndex: [itemBundleButton indexOfSelectedItem]];
  else
    bundle = nil;

  if (helpPanel == nil)
    helpPanel = [[ItemHelpPanel alloc] initWithBundleName: bundle];
  else
    [helpPanel setBundleName: bundle];
  [helpPanel orderFront: self];
}

- (void) reload: (id) sender
{
  [currentBundle reload];
}

- (void) addCategory: (id) sender
{
  [dataSource addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys: 
               @"New category", @"name", [NSMutableArray new], @"items", nil]];
  [browserView loadColumnZero];
  [browserView selectRow: ([dataSource count]-1) inColumn: 0];
  /* Start in-place editing */
  [browserView doDoubleClick: [browserView matrixInColumn: 0]];
}

- (void) deleteCategory: (id) sender
{
  int index = [browserView selectedRowInColumn: 0];
  if (index > -1)
    {
      int result = NSRunAlertPanel(_(@"Delete..."),
                         _(@"Are you sure you want to delete this category?"),
                         _(@"Cancel"), // default
                         _(@"Yes"),    // alternate
                         NULL);

      if (result == NSAlertAlternateReturn)
        {
          [dataSource removeObjectAtIndex: index];
          [browserView loadColumnZero];
        }
    }
}

- (void) addItem: (id) sender
{
  int i;
  NSArray *allBundles;
  Class bundleClass;

  allBundles = [loader allNamesOfBundles];

  /* Refresh the categories */
  if ([dataSource count] < 1)
    {
      NSRunAlertPanel(@"Warning: No category",
                      @"You should add at least category firstly !",
                      @"O.K.", nil, nil);
      return;
    }

  if ([allBundles count] < 1)
    {
      NSRunAlertPanel(@"Warning: No bundle",
                      @"You should install at least bundle firstly !",
                      @"O.K.", nil, nil);
      return;
    }

  [itemCategoryButton removeAllItems];
  for(i = 0; i < [dataSource count]; i++)
    {
      [itemCategoryButton addItemWithTitle: [[dataSource objectAtIndex: i] objectForKey: @"name"]];
      
    }
  [itemCategoryButton selectItemAtIndex: [browserView selectedRowInColumn: 0]];

  [itemBundleButton removeAllItems];
  for(i = 0; i < [allBundles count]; i++)
    {
      bundleClass = [loader classNameOf: [allBundles objectAtIndex: i]];
      [itemBundleButton addItemWithTitle: [bundleClass bundleDescription]];
    }

  [itemNameField setStringValue: @""];
  [itemLocationField setStringValue: @""];
  [itemPanel makeFirstResponder: itemNameField];

  [NSApp runModalForWindow: itemPanel];
}

- (void) deleteItem: (id) sender
{
  int selectedCategory = [browserView selectedRowInColumn: 0];
  int selectedItem = [browserView selectedRowInColumn: 1];
  if ((selectedCategory > -1) && (selectedItem > -1))
    {
      int result = NSRunAlertPanel(_(@"Delete..."),
                         _(@"Are you sure you want to delete this tool?"),
                         _(@"Cancel"), // default
                         _(@"Yes"),    // alternate
                         NULL);

      if (result == NSAlertAlternateReturn)
        {
          [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"]
                                           removeObjectAtIndex: selectedItem];
          [browserView reloadColumn: 1];
          [self browserAction: browserView];
        }
    }
}

- (void) importItem: (id) sender
{
  int i;
  NSArray *allBundles;
  Class bundleClass;

  allBundles = [loader allNamesOfBundles];

  /* Refresh the categories */
  if ([dataSource count] < 1)
    {
      NSRunAlertPanel(@"Warning: No category",
                      @"You should add at least category firstly !",
                      @"O.K.", nil, nil);
      return;
    }

  if ([allBundles count] < 1)
    {
      NSRunAlertPanel(@"Warning: No bundle",
                      @"You should install at least bundle firstly !",
                      @"O.K.", nil, nil);
      return;
    }

  [importCategoryButton removeAllItems];
  for(i = 0; i < [dataSource count]; i++)
    {
      [importCategoryButton addItemWithTitle: [[dataSource objectAtIndex: i] objectForKey: @"name"]];
    }
  [importCategoryButton selectItemAtIndex: [browserView selectedRowInColumn: 0]];

  [importBundleButton removeAllItems];
  for(i = 0; i < [allBundles count]; i++)
    {
      bundleClass = [loader classNameOf: [allBundles objectAtIndex: i]];
      [importBundleButton addItemWithTitle: [bundleClass bundleDescription]];
    }
  [importBundleButton addItemWithTitle: @"Local File"];

  [importLocationField setStringValue: @""];

  [importPanel makeFirstResponder: importLocationField];

  /* Reset the locationField and itemButton */
  [self importButtonAction: importBundleButton];

  [NSApp runModalForWindow: importPanel];
}

- (void) itemCancelAction: (id) sender
{
  [NSApp abortModal];
}

- (void) itemOKAction: (id) sender
{
  NSMutableDictionary *dict = [NSMutableDictionary new];
  NSArray *allBundles = [loader allNamesOfBundles];
  int index = [itemCategoryButton indexOfSelectedItem];
  
  [dict setObject: [itemNameField stringValue] forKey: @"name"];
  [dict setObject: [itemLocationField stringValue] forKey: @"location"];
  [dict setObject: [allBundles objectAtIndex: [itemBundleButton indexOfSelectedItem]] 
           forKey: @"bundle"];
  [[[dataSource objectAtIndex: index] objectForKey: @"items"] addObject: dict];
  RELEASE(dict);

  [NSApp stopModal];
  [itemPanel close];
  [browserView selectRow: index inColumn: 0];
}

- (void) itemButtonAction: (id) sender
{
}

-  (void) importOKAction: (id) sender
{
  NSMutableDictionary *dict = [NSMutableDictionary new];
  NSArray *allBundles = [loader allNamesOfBundles];
  int selectedCategory = [importCategoryButton indexOfSelectedItem];
  int selectedBundle = [importBundleButton indexOfSelectedItem];
  id object;

  if ([importItemButton superview]) // using item button 
    { 
      int selectedItem = [importItemButton indexOfSelectedItem];
      object = [defaultItems objectAtIndex: selectedItem];
      [dict setObject: [object objectForKey: @"name"] forKey: @"name"];
      [dict setObject: [object objectForKey: @"location"] forKey: @"location"];
      [dict setObject: [allBundles objectAtIndex: selectedBundle] 
               forKey: @"bundle"];
      [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"] addObject: dict];
    }
  else // using location field
    {
      NSString *path = [[importLocationField stringValue] stringByStandardizingPath];
      object = [NSArray arrayWithContentsOfFile: path];
      if (object)
        {
          [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"] addObjectsFromArray: object];
        }
    }
  RELEASE(dict);
  [NSApp stopModal];
  [importPanel close];
  [browserView selectRow: selectedCategory inColumn: 0];
}

- (void) importCancelAction: (id) sender
{
  [NSApp abortModal];
}

- (void) importButtonAction: (id) sender
{
  NSString *path, *plistName;
  int index, i;
  id object;

  if (sender == importCategoryButton)
    return;

  [importDescriptionField setStringValue: @""];

  if (sender == importBundleButton)
    {
      if ([sender indexOfSelectedItem] == [[loader allNamesOfBundles] count])
        {
          if ([importLocationField superview]) /* Already in panel */
            return;
          else /* Add importLocationField */
            {
              RETAIN(importItemButton);
              [importItemButton removeFromSuperview];
              [[importPanel contentView] addSubview: importLocationField];
              RELEASE(importLocationField);
            }
        }
      else
        {
          if (![importItemButton superview]) /* Add importItemButton */
            {
              RETAIN(importLocationField);
              [importLocationField removeFromSuperview];
              [[importPanel contentView] addSubview: importItemButton];
              RELEASE(importItemButton);
            }

          /* Set up the items */
          index = [importBundleButton indexOfSelectedItem];
          object = [[loader allNamesOfBundles] objectAtIndex: index]; 
          plistName = [[object stringByDeletingPathExtension] 
                               stringByAppendingString: @"Defaults"];

          path = [loader pathForResource: plistName
                                  ofType: @"plist"
                                ofBundle: object];

          [importItemButton removeAllItems];

          if([[NSFileManager defaultManager] fileExistsAtPath: path])
            {
              if ((object = [[NSString stringWithContentsOfFile: path] propertyList]))
                {
                  for(i = 0; i < [object count]; i++)
                   {
                     [importItemButton addItemWithTitle: [[object objectAtIndex: i] objectForKey: @"name"]];
                   }
                   [importItemButton setEnabled: YES];
                   [importDescriptionField setStringValue: [[object objectAtIndex: 0] objectForKey: @"description"]];
                   ASSIGN(defaultItems, object);
                   return;
                }
            }

          [importItemButton addItemWithTitle: @"No Built-in Item"];
          [importItemButton setEnabled: NO];
          DESTROY(defaultItems);
        }
    }
  else if (sender == importItemButton)
    {
      /* Display the description */
      if(defaultItems)
        {
          index = [importItemButton indexOfSelectedItem];
          [importDescriptionField setStringValue: [[defaultItems objectAtIndex: index] objectForKey: @"description"]];
        }
    }
}

/* Drag & Drop */
- (BOOL) matrix: (ExtendedMatrix *) view
         writeRows: (int) row inColumn: (int) column
         toPasteboard: (NSPasteboard *) pboard
{
  NSData *data;
  int index;

  if (view == (ExtendedMatrix *)[browserView matrixInColumn: 0])
    {
      data = [NSArchiver archivedDataWithRootObject: [dataSource objectAtIndex: row]];
    }
  else
    {
      int index = [browserView selectedRowInColumn: 0];
      data = [NSArchiver archivedDataWithRootObject: [[[dataSource objectAtIndex: index] objectForKey: @"items"] objectAtIndex: row]];
    }
  [pboard declareTypes: [NSArray arrayWithObject: @"NSGeneralPboardType"]
                 owner: nil];
  [pboard setData: data forType: @"NSGeneralPboardType"];
  return YES;
}

- (NSDragOperation) matrix: (ExtendedMatrix *) view
              validateDrop: (id <NSDraggingInfo>) info
               proposedRow: (int) row
     proposedDropOperation: (ExtendedMatrixDropOperation)operation
{
  if ([info draggingSource] == [browserView matrixInColumn: 0])
    {
      /* Category to Category */
      if (view == (ExtendedMatrix *)[browserView matrixInColumn: 0])
        [view setDropRow: row dropOperation: ExtendedMatrixDropAbove];
      else /* Category to Item */
        return NSDragOperationNone;
    }
  else /* from item */
    {
      /* Item to Category */
      if (view == (ExtendedMatrix *)[browserView matrixInColumn: 0]) 
        [view setDropRow: row dropOperation: ExtendedMatrixDropOn];
      else /* Item to Item */
        [view setDropRow: row dropOperation: ExtendedMatrixDropAbove];
    }
  return NSDragOperationMove;
}

- (BOOL) matrix: (ExtendedMatrix *) view
         acceptDrop: (id <NSDraggingInfo>) info
         row: (int) row
         proposedDropOperation: (ExtendedMatrixDropOperation)operation       
{
  NSPasteboard *pboard;
  NSData *data;
  NSMutableDictionary *dict;
  int selectedCategory = [browserView selectedRowInColumn: 0];
  int selectedItem = [browserView selectedRowInColumn: 1];
  id object;
  int index;

  pboard = [info draggingPasteboard];
  data = [pboard dataForType: @"NSGeneralPboardType"];
  dict = [NSUnarchiver unarchiveObjectWithData: data];

  if (nil == [info draggingSource]) /* other application */
    return NO;
  if (![[info draggingSource] isKindOfClass: [view class]])
    return NO;

  if (operation == ExtendedMatrixDropAbove)
    {
      if ([dict objectForKey: @"bundle"]) /* item */
        {
          object = [[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"];
          index = selectedItem;
        }
      else /* category */
        {
          object = dataSource;
          index = selectedCategory;
        }

      if (index > row) /* move up (forward) */
        {
           [object removeObjectAtIndex: index];
           [object insertObject: dict atIndex: row];
        }
      else if (index == row)
        {
           return YES;
        }
      else  /* move down (backward) */
        {
           [object insertObject: dict atIndex: row];
           [object removeObjectAtIndex: index];
        }
      // FIXME: Should only reload one column
      [browserView reloadColumn: 0];
      [browserView selectRow: selectedCategory inColumn: 0];
      [browserView reloadColumn: 1];
    }
  else
    {
      if (selectedCategory == row) /* move to the same category */
        return NO;

      [[[dataSource objectAtIndex: row] objectForKey: @"items"] addObject: dict];
      [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"] removeObjectAtIndex: selectedItem];
      [browserView reloadColumn: 1];
    }
  return YES;
}

/* Editing */
- (void) matrix: (NSMatrix *) matrix setObjectValue: (id) object
         forRow: (int) row column: (int) column
{
  /* Don't use column because it must be 0 from NSBrowser */
  if (matrix == [browserView matrixInColumn: 0])
    {
      [[dataSource objectAtIndex: row] setObject: object forKey: @"name"];
    }
  else if (matrix == [browserView matrixInColumn: 1])
    {
      int index = [browserView selectedRowInColumn: 0];
      if (index > -1)
        {
          NSMutableArray *array = [[dataSource objectAtIndex: index] objectForKey: @"items"];
          [[array objectAtIndex: row] setObject: object forKey: @"name"];
        }
    }
}

/*
- (BOOL) browser: (NSBrowser *) browser selectRow: (int) row
                                        inColumn: (int) column
{
  [browserView selectRow:row inColumn: column];
  return YES;
}
*/

- (void) browserAction: (id) sender
{
  int selectedCategory = [sender selectedRowInColumn: 0];
  int selectedItem = [sender selectedRowInColumn: 1];
  NSRect browserFrame = [browserView frame];
  NSRect windowFrame = [[window contentView] frame];
  NSRect viewFrame;
  Class bundleClass;
  id object;

  [currentView removeFromSuperview];
  RELEASE(currentBundle);
  currentView = nil;
  currentBundle = nil;

  if (([browserView selectedColumn] == 0) || (selectedItem < 0))
    return;

  object =  [[[dataSource objectAtIndex: selectedCategory] objectForKey: @"items"] objectAtIndex: selectedItem];

  bundleClass = [loader classNameOf: [object objectForKey: @"bundle"]];

  viewFrame = NSMakeRect(10, 10, browserFrame.size.width, browserFrame.origin.y - 10 - 10);

  currentBundle = [[bundleClass alloc] initWithFrame: viewFrame
                                       andLocation: [object objectForKey: @"location"]];
  currentView = [currentBundle view];
  if (currentView)
    {
      [currentView setFrame: viewFrame];
      [[window contentView] addSubview: currentView];
      [currentView setNeedsDisplay: YES];
      [currentView displayIfNeeded];
    }
}

- (NSString *) browser: (NSBrowser *) browser titleOfColumn: (int) column
{
  if (column == 0)
    return @"Category";
  else
    {
      if ([browser selectedRowInColumn: column-1] > -1)
        return [[browser selectedCellInColumn: column-1] stringValue];
      else
        return nil;
    }
}

- (void) browser: (NSBrowser *) browser createRowsForColumn: (int) column
         inMatrix: (NSMatrix *) matrix
{
  id cell;
  int i;

  if (column == 0)
    {
      if ([dataSource count] < 1)
        return;

      [matrix addColumn];
  
      for (i = 0; i < [dataSource count]; i++)
        {
          if (i != 0) // First row is created when column is added
            [matrix insertRow: i];

          cell = [matrix cellAtRow: i column: 0];  
          [cell setStringValue: [[dataSource objectAtIndex: i] objectForKey: @"name"]];
        }
      /* set editorDelegate for browser */
      [(ExtendedMatrix *) matrix setEditorDelegate: self];
      [matrix registerForDraggedTypes: [NSArray arrayWithObject: NSGeneralPboardType]];

    }
  else if (column == 1)
   {
     int index = [browserView selectedRowInColumn: 0];
     if (index > -1)
       {
         NSMutableArray *array = [[dataSource objectAtIndex: index] objectForKey: @"items"];
         if ([array count] < 1)
           return;

         [matrix addColumn];
         for (i = 0; i < [array count]; i++)
            {
              if (i != 0) // First row is created when column is added
                [matrix insertRow: i];

              cell = [matrix cellAtRow: i column: 0];
              [cell setStringValue: [[array objectAtIndex: i] objectForKey: @"name"]];
              [cell setLeaf: YES];
            }
         /* set editorDelegate for browser */
         [(ExtendedMatrix *) matrix setEditorDelegate: self];
         [matrix registerForDraggedTypes: [NSArray arrayWithObject: NSGeneralPboardType]];
       }
   }
}

- (void) applicationDidFinishLaunching: (NSNotification *) not
{
  /* Create item panel */
  itemPanel = [[ItemPanel alloc] initWithContentRect: NSMakeRect(300, 300, 420, 170)
                                 styleMask: NSTitledWindowMask
                                   backing: NSBackingStoreBuffered
                                     defer: YES];
  [itemPanel layoutWindow];
  [itemPanel makeFirstResponder: itemNameField];
  [itemPanel setTitle: _(@"Add Item")];

  itemCategoryButton = [itemPanel categoryButton];
  itemNameField = [itemPanel nameField];
  itemLocationField = [itemPanel locationField];
  itemBundleButton = [itemPanel bundleButton];

  [[itemPanel cancelButton] setTarget: self];
  [[itemPanel cancelButton] setAction: @selector(itemCancelAction:)];
  [[itemPanel okButton] setTarget: self];
  [[itemPanel okButton] setAction: @selector(itemOKAction:)];
  [[itemPanel helpButton] setTarget: self];
  [[itemPanel helpButton] setAction: @selector(orderFrontItemHelpPanel:)];
  [itemCategoryButton setTarget: self];
  [itemCategoryButton setAction: @selector(itemButtonAction:)];
  [itemBundleButton setTarget: self];
  [itemBundleButton setAction: @selector(itemButtonAction:)];

  /* Create item import panel */
  importPanel = [[ItemImportPanel alloc] initWithContentRect: NSMakeRect(300, 300, 420, 170)
                                 styleMask: NSTitledWindowMask
                                   backing: NSBackingStoreBuffered
                                     defer: YES];
  [importPanel layoutWindow];
  [importPanel makeFirstResponder: importLocationField];
  [importPanel setTitle: _(@"Import Item")];

  importCategoryButton = [importPanel categoryButton];
  importBundleButton = [importPanel bundleButton];  
  importLocationField = [importPanel locationField];
  importItemButton = [importPanel itemButton];
  importDescriptionField = [importPanel descriptionField];

  [[importPanel cancelButton] setTarget: self];
  [[importPanel cancelButton] setAction: @selector(importCancelAction:)];
  [[importPanel okButton] setTarget: self];
  [[importPanel okButton] setAction: @selector(importOKAction:)];
  [[importPanel helpButton] setTarget: self];
  [[importPanel helpButton] setAction: @selector(orderFrontItemHelpPanel:)];
  [importCategoryButton setTarget: self];
  [importCategoryButton setAction: @selector(importButtonAction:)];
  [importBundleButton setTarget: self];
  [importBundleButton setAction: @selector(importButtonAction:)];
  [importItemButton setTarget: self];
  [importItemButton setAction: @selector(importButtonAction:)];

  [window makeKeyAndOrderFront: self];
  [browserView loadColumnZero];
  
  if ([dataSource count])
    {
      [browserView selectRow: 0 inColumn: 0];
      [self browserAction: browserView];
    }
}

- (void) applicationWillFinishLaunching: (NSNotification *) not
{
  NSMenu *menu;
  NSMenu *toolMenu;
  NSMenu *editMenu;
  NSMenu *servicesMenu;
  NSString *path;

  /* Set up data source */
  path = [@"~/.Toolbox" stringByStandardizingPath];
  if (![[NSFileManager defaultManager] fileExistsAtPath: path])
    {
      NSBundle *b = [NSBundle mainBundle];
      path = [b pathForResource: @"ToolboxDefaults" ofType: @"plist"];
    }
  [dataSource setArray: [NSArray arrayWithContentsOfFile: path]];

  /* Set up menu */
  menu = [[NSMenu alloc] initWithTitle: _(@"Toolbox")];

  [menu addItemWithTitle: _(@"Tool")
                  action: NULL
           keyEquivalent: @""];
  [menu addItemWithTitle: _(@"Edit")
                  action: NULL
           keyEquivalent: @""];
  [menu addItemWithTitle: _(@"Services")
                  action: NULL
           keyEquivalent: @""];
  [menu addItemWithTitle: _(@"Hide")
                  action: @selector(hide:)
           keyEquivalent: @"h"];
  [menu addItemWithTitle: _(@"Quit")
                  action: @selector(terminate:)
           keyEquivalent: @"q"];

  // Create the tool submenu
  toolMenu = [[NSMenu alloc] initWithTitle: _(@"Tool")];

  [toolMenu addItemWithTitle: _(@"Tool Info...")
                      action: @selector(orderFrontItemInfoPanel:)
               keyEquivalent: @"i"];

  [toolMenu addItemWithTitle: _(@"Help")
                      action: @selector(orderFrontItemHelpPanel:)
               keyEquivalent: @"?"];

  [toolMenu addItemWithTitle: _(@"Reload")
                      action: @selector(reload:)
               keyEquivalent: @"r"];

  [menu setSubmenu: toolMenu
           forItem: [menu itemWithTitle: _(@"Tool")]];

  RELEASE(toolMenu);

  // Create the edit submenu
  editMenu = [[NSMenu alloc] initWithTitle: _(@"Edit")];

  [editMenu addItemWithTitle: _(@"Add Category")
                      action: @selector(addCategory:)
               keyEquivalent: @"A"]; 
 
  [editMenu addItemWithTitle: _(@"Delete Category")
                      action: @selector(deleteCategory:)
               keyEquivalent: @"D"];
  
  [editMenu addItemWithTitle: _(@"Add Item")
                      action: @selector(addItem:)
               keyEquivalent: @"a"];

  [editMenu addItemWithTitle: _(@"Delete Item")
                      action: @selector(deleteItem:)
               keyEquivalent: @"d"];

  [editMenu addItemWithTitle: _(@"Import Item")
                      action: @selector(importItem:)
               keyEquivalent: @"x"];

  [menu setSubmenu: editMenu
           forItem: [menu itemWithTitle: _(@"Edit")]];
  
  RELEASE(editMenu);

  servicesMenu = [[NSMenu alloc] initWithTitle: _(@"Services")];
  
  [menu setSubmenu: servicesMenu
           forItem: [menu itemWithTitle: _(@"Services")]];
  [NSApp setServicesMenu: servicesMenu];

  RELEASE(servicesMenu);

  [NSApp setMainMenu: menu];

  RELEASE(menu);

  /* Set up toolbox window */
  window = [[ToolboxWindow alloc]  initWithContentRect: NSMakeRect(200, 200, 350, 270)
                                 styleMask: (NSTitledWindowMask |
                                           NSClosableWindowMask | 
                                     NSMiniaturizableWindowMask |
                                          NSResizableWindowMask)
                                   backing: NSBackingStoreBuffered
                                     defer: YES];
  [window setDelegate: self];
  [window layoutWindow];
  [window setFrameAutosaveName: @"ToolboxWindow"];
  [window setFrameUsingName: @"ToolboxWindow"];
  [window setMinSize: NSMakeSize(350, 310)];


  browserView = [window browser];
  [browserView setMatrixClass: [ExtendedMatrix class]];
  [browserView setDelegate: self];
  [browserView setTarget: self];
  [browserView setAction: @selector(browserAction:)];
  [browserView setMaxVisibleColumns: 2];
  [browserView setAllowsEmptySelection: NO];
  [browserView setAllowsMultipleSelection: NO];

  loader = [BundleLoader defaultLoader];
}

- (BOOL) applicationShouldTerminateAfterLastWindowClosed: (id) sender
{
  return YES;
}

- (void) applicationWillTerminate: (NSNotification *) not
{
  NSString *path = [@"~/.Toolbox" stringByStandardizingPath];
  [dataSource writeToFile: path atomically: YES];
}

- (id) init
{
  self = [super init];
  dataSource = [NSMutableArray new];
  return self;
}

- (void) dealloc
{
  RELEASE(currentBundle);
  RELEASE(dataSource);
  RELEASE(defaultItems);
  [super dealloc];
}

@end
