/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2003-2006 RSSOwl Development Team                                  **
 **   http://www.rssowl.org/                                                 **
 **                                                                          **
 **   All rights reserved                                                    **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the Eclipse Public License 1.0 which accompanies this     **
 **   distribution, and is available at:                                     **
 **   http://www.rssowl.org/legal/epl-v10.html                               **
 **                                                                          **
 **   A copy is found in the file epl-v10.html and important notices to the  **
 **   license from the team is found in the textfile LICENSE.txt distributed **
 **   in this package.                                                       **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Contributors:                                                          **
 **     RSSOwl - initial API and implementation (bpasero@rssowl.org)         **
 **                                                                          **
 **  **********************************************************************  */

package net.sourceforge.rssowl.controller.dialog;

import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.controller.Quickview;
import net.sourceforge.rssowl.controller.thread.SettingsManager;
import net.sourceforge.rssowl.util.GlobalSettings;
import net.sourceforge.rssowl.util.i18n.ITranslatable;
import net.sourceforge.rssowl.util.shop.FontShop;
import net.sourceforge.rssowl.util.shop.LayoutDataShop;
import net.sourceforge.rssowl.util.shop.LayoutShop;
import net.sourceforge.rssowl.util.shop.PaintShop;
import net.sourceforge.rssowl.util.shop.StringShop;
import net.sourceforge.rssowl.util.shop.WidgetShop;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

/**
 * The ToolBar Dialog allows to customize the ToolBar. This includes the list of
 * ToolItems to display and the order. In addition it is possible to add
 * Separators between ToolItems. A dropdown allows to switch between "Icons and
 * Text", "Text" and "Icons" display mode.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class ToolBarDialog extends Dialog implements ITranslatable {

  /** ToolItem: Close */
  public static final String TOOLITEM_CLOSE = "MENU_CLOSE";

  /** ToolItem: Close All */
  public static final String TOOLITEM_CLOSE_ALL = "MENU_CLOSE_ALL";

  /** ToolItem: Close Others */
  public static final String TOOLITEM_CLOSE_OTHERS = "POP_KEEP_CURRENT";

  /** ToolItem: Export */
  public static final String TOOLITEM_EXPORT = "BUTTON_EXPORT";

  /** ToolItem: Favorites */
  public static final String TOOLITEM_FAVORITES = "HEADER_RSS_FAVORITES";

  /** ToolItem: History */
  public static final String TOOLITEM_HISTORY = "TOOL_HISTORY";

  /** ToolItem: Import */
  public static final String TOOLITEM_IMPORT = "POP_IMPORT";

  /** ToolItem: Mark Read */
  public static final String TOOLITEM_MARK = "TOOL_MARK";

  /** ToolItem: New */
  public static final String TOOLITEM_NEW = "POP_NEW";

  /** ToolItem: NewsTip */
  public static final String TOOLITEM_NEWSTIP = "TOOL_NEWSTIP";

  /** ToolItem: Next Message */
  public static final String TOOLITEM_NEXT = "TOOL_NEXT";

  /** ToolItem: Next Tab */
  public static final String TOOLITEM_NEXT_TAB = "MENU_NEXT_TAB";

  /** ToolItem: Previous Tab */
  public static final String TOOLITEM_PREVIOUS_TAB = "MENU_PREVIOUS_TAB";

  /** ToolItem: Rate (Disabled as of ver. 1.2.3) */
  // public static final String TOOLITEM_RATE = "TOOL_RATE";
  
  /** ToolItem: Reload */
  public static final String TOOLITEM_RELOAD = "MENU_RELOAD";

  /** ToolItem: Search */
  public static final String TOOLITEM_SEARCH = "BUTTON_SEARCH";

  /** ToolItem: Separator */
  public static final String TOOLITEM_SEPARATOR = "TOOL_SEPARATOR";

  /** ToolItem: Tools */
  public static final String TOOLITEM_TOOLS = "MENU_TOOLS";

  /** Apply Button Id */
  private static final int APPLY_ID = 10;

  /** Width of the dialog in DLUs */
  private static final int DIALOG_WIDTH = 350;

  /** Appended left and right to a Separator */
  private static final String SEPARATOR_WINGS = "----";

  private Button addSepButton;
  private Button applyButton;
  private Button cancelButton;
  private ArrayList defaultOrder;
  private Button downButton;
  private DragSource dragSource;
  private DropTarget dropTarget;
  private HashMap itemIcons;
  private Button okButton;
  private Quickview quickview;
  private Button restoreDefaults;
  private Label separatorLabel;
  private Label showLabel;
  private String title;
  private String toolBarItems;
  private int toolBarMode;
  private Button upButton;
  private boolean useSmallIcons;
  TableItem draggedItem;
  Table itemTable;
  Button removeSepButton;
  Combo showCombo;
  Button useSmallIconsCheck;

  /**
   * Initialize a new ToolBarDialog to customize the ToolBar.
   * 
   * @param quickview The ToolBar management control.
   * @param parentShell The parent Shell of this Dialog.
   * @param dialogTitle The Title for this Dialog.
   */
  public ToolBarDialog(Quickview quickview, Shell parentShell, String dialogTitle) {
    super(parentShell);
    this.quickview = quickview;
    this.title = dialogTitle;
    itemIcons = new HashMap();
    defaultOrder = new ArrayList();
    toolBarItems = GlobalSettings.toolBarItems;
    initItemIcons();
    initDefaultOrder();
  }

  /**
   * Get the default ToolBar Items.
   * 
   * @return String The Default ToolBar Items.
   */
  public static String getDefaultToolBarItems() {
    StringBuffer strBuf = new StringBuffer();
    strBuf.append(TOOLITEM_NEW).append(",");
    strBuf.append(TOOLITEM_IMPORT).append(",");
    strBuf.append(TOOLITEM_EXPORT).append(",");
    strBuf.append(TOOLITEM_SEPARATOR).append(",");
    strBuf.append(TOOLITEM_RELOAD).append(",");
    strBuf.append(TOOLITEM_SEARCH).append(",");
    strBuf.append(TOOLITEM_MARK).append(",");
    strBuf.append(TOOLITEM_SEPARATOR).append(",");
    strBuf.append(TOOLITEM_NEXT).append(",");
    strBuf.append(TOOLITEM_SEPARATOR).append(",");
    strBuf.append(TOOLITEM_FAVORITES).append(",");
    strBuf.append(TOOLITEM_SEPARATOR).append(",");
    strBuf.append(TOOLITEM_HISTORY).append(",");
    strBuf.append(TOOLITEM_TOOLS).append(",");

    return strBuf.toString();
  }

  /**
   * Dispose the Images used for the Item Table and the DND Support.
   */
  public void dispose() {

    /** Dispose used Images */
    for (Iterator iter = itemIcons.values().iterator(); iter.hasNext();)
      ((Image) iter.next()).dispose();

    /** Dispose DND Support */
    dragSource.dispose();
    dropTarget.dispose();
  }

  /**
   * Get the new ToolBar Items.
   * 
   * @return String The new ToolBar Items.
   */
  public String getToolBarItems() {
    return toolBarItems;
  }

  /**
   * Get the new ToolBar Mode.
   * 
   * @return int The new ToolBar Mode.
   */
  public int getToolBarMode() {
    return toolBarMode;
  }

  /**
   * @return TRUE if the Toolbar should use small Icons.
   */
  public boolean isUseSmallIcons() {
    return useSmallIcons;
  }

  /**
   * @see net.sourceforge.rssowl.util.i18n.ITranslatable#updateI18N()
   */
  public void updateI18N() {

    /** Buttons and Labels */
    getShell().setText(GUI.i18n.getTranslation("POP_CUSTOMIZE_TOOLBAR"));
    okButton.setText(GUI.i18n.getTranslation("BUTTON_OK"));
    cancelButton.setText(GUI.i18n.getTranslation("BUTTON_CANCLE"));
    applyButton.setText(GUI.i18n.getTranslation("BUTTON_APPLY"));
    upButton.setText(GUI.i18n.getTranslation("BUTTON_UP"));
    downButton.setText(GUI.i18n.getTranslation("BUTTON_DOWN"));
    separatorLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, true));
    addSepButton.setText(GUI.i18n.getTranslation("BUTTON_ADD"));
    removeSepButton.setText(GUI.i18n.getTranslation("BUTTON_REMOVE"));
    showLabel.setText(GUI.i18n.getTranslation("LABEL_SHOW") + ": ");
    useSmallIconsCheck.setText(GUI.i18n.getTranslation("BUTTON_SMALL_ICONS"));
    restoreDefaults.setText(GUI.i18n.getTranslation("BUTTON_RESTORE_DEFAULTS"));

    /** Mode List - Restore Selection after Update */
    int selection = showCombo.getSelectionIndex();
    showCombo.removeAll();
    showCombo.add(GUI.i18n.getTranslation("TOOL_ICONS_TEXT"));
    showCombo.add(GUI.i18n.getTranslation("TOOL_ICONS"));
    showCombo.add(GUI.i18n.getTranslation("TOOL_TEXT"));
    showCombo.select(selection);

    /** Tool Item Table */
    int itemCount = itemTable.getItemCount();
    for (int i = 0; i < itemCount; i++) {
      TableItem item = itemTable.getItem(i);
      String data = (String) item.getData();

      /** Special highlight Separators */
      if (TOOLITEM_SEPARATOR.equals(data))
        item.setText(SEPARATOR_WINGS + " " + GUI.i18n.getTranslation(TOOLITEM_SEPARATOR) + " " + SEPARATOR_WINGS);
      else
        item.setText(GUI.i18n.getTranslation(data));
    }

    /** Apply Mnemonics */
    WidgetShop.initMnemonics(new Button[] { addSepButton, removeSepButton, applyButton, upButton, downButton, useSmallIconsCheck, restoreDefaults });

    /** Layout All */
    LayoutShop.setLayoutForAll(getShell());

    /** Check if the Shell size has to be changed */
    Point preferredSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
    if (preferredSize.x > getShell().getSize().x)
      getShell().setSize(preferredSize.x, getShell().getSize().y);
  }

  /**
   * Create a Separator as TableItem.
   * 
   * @param index The Index this Separator will be inserted to.
   * @return TableItem The new Separator as TableItem.
   */
  private TableItem createSeparator(int index) {
    TableItem item = new TableItem(itemTable, SWT.NONE, index);
    item.setText(SEPARATOR_WINGS + " " + GUI.i18n.getTranslation(TOOLITEM_SEPARATOR) + " " + SEPARATOR_WINGS);
    item.setImage((Image) itemIcons.get(TOOLITEM_SEPARATOR));
    item.setChecked(true);
    item.setData(TOOLITEM_SEPARATOR);

    return item;
  }

  /**
   * Copy all states of TableItem 1 into TableItem 2 and vice versa.
   * 
   * @param item1 The first item to Flip.
   * @param item2 The second item to Flip.
   */
  private void flip(TableItem item1, TableItem item2) {

    /** Flip Text */
    String text1 = item1.getText();
    String text2 = item2.getText();

    /** Flip Data */
    Object data1 = item1.getData();
    Object data2 = item2.getData();

    /** Flip Image */
    Image image1 = item1.getImage();
    Image image2 = item2.getImage();

    /** Flip Checked State */
    boolean item1Checked = item1.getChecked();
    boolean item2Checked = item2.getChecked();

    /** Update Item 1 */
    item1.setText(text2);
    item1.setData(data2);
    item1.setImage(image2);
    item1.setChecked(item2Checked);

    /** Update Item 2 */
    item2.setText(text1);
    item2.setData(data1);
    item2.setImage(image1);
    item2.setChecked(item1Checked);
  }

  /**
   * Get the new ToolBar as String value.
   * 
   * @return String The new ToolBar as String value.
   */
  private String getItemStringValue() {
    StringBuffer strBuf = new StringBuffer();
    boolean lastItemWasSeparator = false;

    /** Foreach Item in the Table */
    int itemCount = itemTable.getItemCount();
    for (int i = 0; i < itemCount; i++) {
      TableItem item = itemTable.getItem(i);

      /** Only consider checked Items */
      if (item.getChecked()) {

        /** Do not allow more than one Separator after a ToolItem */
        if (!TOOLITEM_SEPARATOR.equals(item.getData()) || !lastItemWasSeparator) {
          strBuf.append(",").append(item.getData());
          lastItemWasSeparator = TOOLITEM_SEPARATOR.equals(item.getData());
        }
      }
    }

    /** Strip first semicolon */
    String itemValue = strBuf.toString();
    if (StringShop.isset(itemValue))
      itemValue = itemValue.substring(1);

    /** Do not allow a single Separator */
    if (TOOLITEM_SEPARATOR.equals(itemValue))
      itemValue = "";

    return itemValue;
  }

  /**
   * Fill a List with the default Order of ToolItems, which are not Separators.
   */
  private void initDefaultOrder() {
    defaultOrder.clear();
    defaultOrder.add(TOOLITEM_NEW);
    defaultOrder.add(TOOLITEM_IMPORT);
    defaultOrder.add(TOOLITEM_EXPORT);
    defaultOrder.add(TOOLITEM_RELOAD);
    defaultOrder.add(TOOLITEM_SEARCH);
    defaultOrder.add(TOOLITEM_MARK);
    defaultOrder.add(TOOLITEM_NEXT);
    defaultOrder.add(TOOLITEM_FAVORITES);
    defaultOrder.add(TOOLITEM_HISTORY);
    defaultOrder.add(TOOLITEM_TOOLS);
    defaultOrder.add(TOOLITEM_CLOSE);
    defaultOrder.add(TOOLITEM_CLOSE_OTHERS);
    defaultOrder.add(TOOLITEM_CLOSE_ALL);
    defaultOrder.add(TOOLITEM_PREVIOUS_TAB);
    defaultOrder.add(TOOLITEM_NEXT_TAB);
    // defaultOrder.add(TOOLITEM_RATE);
    defaultOrder.add(TOOLITEM_NEWSTIP);
  }

  /**
   * Fill a Map with Images that are representing the given ToolItem.
   */
  private void initItemIcons() {
    itemIcons.put(TOOLITEM_NEW, PaintShop.sizeTo(GUI.display, PaintShop.iconNew, 20, 20, false));
    itemIcons.put(TOOLITEM_IMPORT, PaintShop.sizeTo(GUI.display, PaintShop.iconImport, 20, 20, false));
    itemIcons.put(TOOLITEM_EXPORT, PaintShop.sizeTo(GUI.display, PaintShop.iconExport, 20, 20, false));
    itemIcons.put(TOOLITEM_RELOAD, PaintShop.sizeTo(GUI.display, PaintShop.iconReload, 20, 20, false));
    itemIcons.put(TOOLITEM_SEARCH, PaintShop.sizeTo(GUI.display, PaintShop.iconFind, 20, 20, false));
    itemIcons.put(TOOLITEM_MARK, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/mark_feed_read.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_NEXT, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/next_unread.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_FAVORITES, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/favorites.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_TOOLS, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/tools.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_CLOSE, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/close_tab.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_CLOSE_OTHERS, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/close_others.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_CLOSE_ALL, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/close_all_tabs.gif"), 20, 20, true));
    // itemIcons.put(TOOLITEM_RATE, PaintShop.sizeTo(GUI.display,
    // PaintShop.loadImage("/img/icons/rate.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_NEWSTIP, PaintShop.sizeTo(GUI.display, PaintShop.iconMail, 20, 20, false));
    itemIcons.put(TOOLITEM_HISTORY, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/history.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_PREVIOUS_TAB, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/backward_small.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_NEXT_TAB, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/forward_small.gif"), 20, 20, true));
    itemIcons.put(TOOLITEM_SEPARATOR, PaintShop.sizeTo(GUI.display, PaintShop.loadImage("/img/icons/separator.gif"), 20, 20, true));
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
   */
  protected void buttonPressed(int buttonId) {

    /** Ok Button pressed - Update fields with new Values */
    if (buttonId == IDialogConstants.OK_ID) {
      toolBarItems = getItemStringValue();
      toolBarMode = showCombo.getSelectionIndex();
      useSmallIcons = useSmallIconsCheck.getSelection();
    }

    /** Apply Button pressed - Update ToolBar */
    else if (buttonId == APPLY_ID) {

      /** Update Global Settings */
      GlobalSettings.toolBarItems = getItemStringValue();
      GlobalSettings.toolBarMode = showCombo.getSelectionIndex();
      GlobalSettings.useSmallIcons = useSmallIconsCheck.getSelection();

      /** Re-Create ToolBar */
      quickview.createToolBar();
      SettingsManager.getInstance().requestSave();

      /** Show the ToolBar in case hidden */
      if (!GlobalSettings.isToolBarShown)
        quickview.setShowToolBar(true, true);
    }

    super.buttonPressed(buttonId);
  }

  /**
   * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
   */
  protected void configureShell(Shell shell) {
    super.configureShell(shell);

    /** On Mac do not set Shell Image since it will change the Dock Image */
    if (!GlobalSettings.isMac())
      shell.setImages(PaintShop.iconOwl);

    /** Trigger Dispose */
    shell.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        dispose();
      }
    });

    shell.setText(title);
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
   */
  protected void createButtonsForButtonBar(Composite parent) {

    /** Button order on Mac is different */
    if (GUI.display.getDismissalAlignment() == SWT.RIGHT) {

      /** Create cancel Button */
      cancelButton = createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false);

      /** Create OK Button */
      okButton = createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true);

      /** Create apply Button */
      applyButton = createButton(parent, APPLY_ID, GUI.i18n.getTranslation("BUTTON_APPLY"), false);
    } else {

      /** Create OK Button */
      okButton = createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true);

      /** Create cancel Button */
      cancelButton = createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false);

      /** Create apply Button */
      applyButton = createButton(parent, APPLY_ID, GUI.i18n.getTranslation("BUTTON_APPLY"), false);
    }

    /** Apply Dialog Font */
    okButton.setFont(FontShop.dialogFont);
    cancelButton.setFont(FontShop.dialogFont);
    applyButton.setFont(FontShop.dialogFont);

    /** Apply Mnemonics */
    WidgetShop.initMnemonics(new Button[] { addSepButton, removeSepButton, applyButton, upButton, downButton, useSmallIconsCheck, restoreDefaults });
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
   */
  protected Control createDialogArea(Composite parent) {

    /** Composite to hold all components */
    Composite composite = (Composite) super.createDialogArea(parent);
    composite.setLayout(new GridLayout(2, false));

    /** Table for the ToolItems */
    itemTable = new Table(composite, SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK);
    itemTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
    itemTable.setFont(FontShop.dialogFont);
    itemTable.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
    itemTable.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {

        /** Only enable this button in case a Separator is selected */
        if (itemTable.getSelectionCount() > 0) {
          TableItem item = itemTable.getSelection()[0];
          removeSepButton.setEnabled(TOOLITEM_SEPARATOR.equals(item.getData()));
        }
      }
    });

    /** Listen for the Delete Key */
    itemTable.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {

        /** User has pressed DEL key (or Backspace on Mac) */
        if (e.keyCode == SWT.DEL || (GlobalSettings.isMac() && e.keyCode == SWT.BS)) {

          /** Selection is over Separator, delete it */
          if (itemTable.getSelectionCount() > 0 && TOOLITEM_SEPARATOR.equals(itemTable.getSelection()[0].getData()))
            removeSeparator();

          /** Selection is over Toolitem, uncheck it */
          else if (itemTable.getSelectionCount() > 0)
            itemTable.getSelection()[0].setChecked(false);
        }
      }
    });

    /** Toggle Checked State on Double-Click */
    itemTable.addMouseListener(new MouseAdapter() {
      public void mouseDoubleClick(MouseEvent e) {
        if (itemTable.getSelectionCount() > 0) {
          TableItem item = itemTable.getSelection()[0];
          item.setChecked(!item.getChecked());
        }
      }
    });

    /** Allow to drag a single TableItem */
    dragSource = new DragSource(itemTable, DND.DROP_MOVE);
    dragSource.setTransfer(new Transfer[] { TextTransfer.getInstance() });
    dragSource.addDragListener(new DragSourceAdapter() {

      /** Clean-Up */
      public void dragFinished(DragSourceEvent event) {
        draggedItem = null;
      }

      /** Use empty Data since it is not read later anyways */
      public void dragSetData(DragSourceEvent event) {
        if (WidgetShop.isset(draggedItem))
          event.data = StringShop.EMPTY_TEXT_DATA;
      }

      /** Only allow DND in case an Item is selected */
      public void dragStart(DragSourceEvent event) {
        event.doit = itemTable.getSelectionCount() == 1;
        if (event.doit)
          draggedItem = itemTable.getSelection()[0];
      }
    });

    /** Allow to drop the single TableItem */
    dropTarget = new DropTarget(itemTable, DND.DROP_MOVE);
    dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance() });
    dropTarget.addDropListener(new DropTargetAdapter() {

      /** Check that a valid Item is dragged over */
      public void dragOver(DropTargetEvent event) {
        TableItem targetItem = (TableItem) event.item;
        boolean allowOperation = WidgetShop.isset(targetItem) && WidgetShop.isset(draggedItem);
        event.detail = allowOperation ? DND.DROP_MOVE : DND.DROP_NONE;
        event.feedback = allowOperation ? DND.FEEDBACK_SCROLL | DND.FEEDBACK_SELECT : DND.FEEDBACK_NONE;
      }

      /** Move dragged Item to the new position */
      public void drop(DropTargetEvent event) {
        TableItem targetItem = (TableItem) event.item;

        /** Make sure that Source and Target are valid */
        if (WidgetShop.isset(targetItem) && WidgetShop.isset(draggedItem)) {
          int sourceIndex = itemTable.indexOf(draggedItem);
          int targetIndex = itemTable.indexOf(targetItem);
          int newIndex;

          /** Source Index is bigger than Target Index */
          if (sourceIndex > targetIndex)
            newIndex = targetIndex;

          /** Source Index is smaller than Target Index */
          else
            newIndex = targetIndex + 1;

          /** Create the new Item */
          TableItem item = new TableItem(itemTable, SWT.NONE, newIndex);
          item.setText(draggedItem.getText());
          item.setData(draggedItem.getData());
          item.setImage(draggedItem.getImage());
          item.setChecked(draggedItem.getChecked());

          /** Dispose the old Item */
          draggedItem.dispose();

          /** Update Selection */
          itemTable.setSelection(new TableItem[] { item });
        }
      }
    });

    /** Fill Items into the Table */
    fillTable(GlobalSettings.toolBarItems);

    /** Select the first Item */
    itemTable.setSelection(0);

    /** Move items upwards */
    upButton = new Button(composite, SWT.PUSH);
    upButton.setText(GUI.i18n.getTranslation("BUTTON_UP"));
    upButton.setFont(FontShop.dialogFont);
    upButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        moveTableElementUp();
      }
    });

    /** Move items downwards */
    downButton = new Button(composite, SWT.PUSH);
    downButton.setText(GUI.i18n.getTranslation("BUTTON_DOWN"));
    downButton.setFont(FontShop.dialogFont);
    downButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        moveTableElementDown();
      }
    });

    /** Apply layout data to buttons */
    setButtonLayoutData(upButton, new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
    setButtonLayoutData(downButton, new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));

    /** Container for Bottom Controls */
    Composite bottomContainer = new Composite(composite, SWT.NONE);
    bottomContainer.setLayout(LayoutShop.createGridLayout(3, 0, 0, 20, 5, false));
    bottomContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));

    /** Label: Separator */
    separatorLabel = new Label(bottomContainer, SWT.NONE);
    separatorLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, true));
    separatorLabel.setText(GUI.i18n.getTranslation("TOOL_SEPARATOR") + ": ");
    separatorLabel.setFont(FontShop.dialogFont);

    /** Container for Separator Buttons */
    Composite sepButtonContainer = new Composite(bottomContainer, SWT.NONE);
    sepButtonContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
    sepButtonContainer.setLayout(LayoutShop.createGridLayout(2, 0, 0));

    /** Add a new Separator */
    addSepButton = new Button(sepButtonContainer, SWT.PUSH);
    addSepButton.setText(GUI.i18n.getTranslation("BUTTON_ADD"));
    addSepButton.setFont(FontShop.dialogFont);
    addSepButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        addSeparator();
      }
    });

    /** Remove selected Separator */
    removeSepButton = new Button(sepButtonContainer, SWT.PUSH);
    removeSepButton.setText(GUI.i18n.getTranslation("BUTTON_REMOVE"));
    removeSepButton.setFont(FontShop.dialogFont);
    removeSepButton.setEnabled(false);
    removeSepButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        removeSeparator();
      }
    });

    /** Apply layout data to buttons */
    setButtonLayoutData(addSepButton, new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
    setButtonLayoutData(removeSepButton, new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));

    /** Container for the Combo */
    Composite showContainer = new Composite(bottomContainer, SWT.NONE);
    showContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
    showContainer.setLayout(LayoutShop.createGridLayout(3, 0, 0));

    /** Label: Show */
    showLabel = new Label(showContainer, SWT.NONE);
    showLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, true));
    showLabel.setText(GUI.i18n.getTranslation("LABEL_SHOW") + ": ");
    showLabel.setFont(FontShop.dialogFont);

    /** Combo to select ToolBar Mode */
    showCombo = new Combo(showContainer, SWT.READ_ONLY);
    showCombo.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
    showCombo.setFont(FontShop.dialogFont);
    showCombo.add(GUI.i18n.getTranslation("TOOL_ICONS_TEXT"));
    showCombo.add(GUI.i18n.getTranslation("TOOL_ICONS"));
    showCombo.add(GUI.i18n.getTranslation("TOOL_TEXT"));
    showCombo.select(GlobalSettings.toolBarMode);

    /** Composite for Check */
    Composite useSmallIconsContainer = new Composite(showContainer, SWT.NONE);
    useSmallIconsContainer.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
    useSmallIconsContainer.setLayout(LayoutShop.createGridLayout(1, 10, 0));

    /** Check to switch the Icon Mode to Small / Big */
    useSmallIconsCheck = new Button(useSmallIconsContainer, SWT.CHECK);
    useSmallIconsCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
    useSmallIconsCheck.setText(GUI.i18n.getTranslation("BUTTON_SMALL_ICONS"));
    useSmallIconsCheck.setFont(FontShop.dialogFont);
    useSmallIconsCheck.setSelection(GlobalSettings.useSmallIcons);

    /** Restore Defaults */
    restoreDefaults = new Button(bottomContainer, SWT.PUSH);
    restoreDefaults.setText(GUI.i18n.getTranslation("BUTTON_RESTORE_DEFAULTS"));
    restoreDefaults.setFont(FontShop.dialogFont);
    restoreDefaults.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
    restoreDefaults.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        fillTable(getDefaultToolBarItems());
        showCombo.select(0);
        useSmallIconsCheck.setSelection(true);
      }
    });

    /** Holder for the separator to the OK and Cancel buttons */
    Composite sepHolder = new Composite(parent, SWT.NONE);
    sepHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    sepHolder.setLayout(LayoutShop.createGridLayout(1, 0, 0));

    /** Separator */
    Label separator = new Label(sepHolder, SWT.SEPARATOR | SWT.HORIZONTAL);
    separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    return composite;
  }

  /**
   * @see org.eclipse.jface.window.Window#getShellStyle()
   */
  protected int getShellStyle() {
    int style = SWT.DIALOG_TRIM | SWT.RESIZE | getDefaultOrientation();

    /** Follow Apple's Human Interface Guidelines for Application Modal Dialogs */
    if (GlobalSettings.isMac())
      style = style | SWT.MIN | SWT.MAX;

    return style;
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
   */
  protected void initializeBounds() {
    Point requiredSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
    Point preferredSize = getShell().computeSize(convertHorizontalDLUsToPixels(DIALOG_WIDTH), SWT.DEFAULT);
    Point location = getInitialLocation(preferredSize);
    getShell().setBounds(location.x, location.y, preferredSize.x > requiredSize.x ? preferredSize.x : requiredSize.x, preferredSize.y);
  }

  /**
   * Set the layout data of the button to a GridData with appropriate widths
   * This method was slightly modified so that it is not setting a heightHint.
   * 
   * @param button The button to layout
   */
  protected void setButtonLayoutData(Button button) {
    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
    data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
    button.setLayoutData(data);
  }

  /**
   * Set the layout data of the button to a GridData with appropriate heights
   * and widths.
   * 
   * @param button The button to set the layoutdata
   * @param data The GridData to use
   */
  protected void setButtonLayoutData(Button button, GridData data) {

    /** GC to retrieve fontmetrics object */
    GC gc = new GC(button);
    FontMetrics fontMetrics = gc.getFontMetrics();

    /** Apply appropiate gridata */
    int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
    data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
    button.setLayoutData(data);

    /** Dispose GC */
    gc.dispose();
  }

  /**
   * Add a new Separator to the current selected Index.
   */
  void addSeparator() {
    int index = itemTable.getSelectionIndex();

    /** Create */
    TableItem separator = createSeparator(index + 1);

    /** Select */
    itemTable.setSelection(new TableItem[] { separator });

    /** Update Button */
    removeSepButton.setEnabled(true);
  }

  /**
   * Fill the ToolBar item Table with the given Elements.
   * 
   * @param toolBarItems A String describing the ToolBar items.
   */
  void fillTable(String toolBarItems) {

    /** First remove all existing Items */
    if (WidgetShop.isset(itemTable))
      itemTable.removeAll();

    /** ToolBar Items are given */
    if (StringShop.isset(toolBarItems)) {

      /** Split into Items */
      String items[] = toolBarItems.split(",");

      /** Foreach checked ToolItem */
      for (int i = 0; i < items.length; i++) {
        TableItem item = new TableItem(itemTable, SWT.NONE);
        item.setChecked(true);

        /** Add some symbols if this is a Separator */
        if (items[i].equals(TOOLITEM_SEPARATOR))
          item.setText(SEPARATOR_WINGS + " " + GUI.i18n.getTranslation(items[i]) + " " + SEPARATOR_WINGS);
        else
          item.setText(GUI.i18n.getTranslation(items[i]));

        /** Apply Image and Date */
        item.setImage((Image) itemIcons.get(items[i]));
        item.setData(items[i]);

        /** Mark as Added */
        defaultOrder.remove(items[i]);
      }
    }

    /** Foreach non-checked ToolItem */
    for (Iterator iter = defaultOrder.iterator(); iter.hasNext();) {
      String itemValue = (String) iter.next();

      /** Create new */
      TableItem item = new TableItem(itemTable, SWT.NONE);
      item.setChecked(false);
      item.setText(GUI.i18n.getTranslation(itemValue));
      item.setImage((Image) itemIcons.get(itemValue));
      item.setData(itemValue);
    }

    /** Restore the default Order for following calls */
    initDefaultOrder();
  }

  /**
   * Replace the selected item with the item beyond it.
   */
  void moveTableElementDown() {
    int index = itemTable.getSelectionIndex();

    /** There must be a selection and an item beyond the selection */
    if (index != (itemTable.getItemCount() - 1)) {
      TableItem selection = itemTable.getItem(index);
      TableItem target = itemTable.getItem(index + 1);

      /** Flip Items */
      flip(selection, target);

      /** Update Selection */
      itemTable.setSelection(index + 1);
    }
  }

  /**
   * Replace the selected item with the item above it.
   */
  void moveTableElementUp() {
    int index = itemTable.getSelectionIndex();

    /** There must be a selection and an item above the selection */
    if (index != 0) {
      TableItem selection = itemTable.getItem(index);
      TableItem target = itemTable.getItem(index - 1);

      /** Flip Items */
      flip(selection, target);

      /** Update Selection */
      itemTable.setSelection(index - 1);
    }
  }

  /**
   * Remove the selected Separator.
   */
  void removeSeparator() {
    int index = itemTable.getSelectionIndex();

    /** Remove */
    itemTable.remove(index);

    /** Update Selection */
    itemTable.setSelection(index == itemTable.getItemCount() ? index - 1 : index);

    /** Update Button */
    removeSepButton.setEnabled(TOOLITEM_SEPARATOR.equals(itemTable.getSelection()[0].getData()));
  }
}