Package org.eclipse.jface.dialogs

Source Code of org.eclipse.jface.dialogs.TrayDialog

/*******************************************************************************
* Copyright (c) 2005, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.dialogs;

import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

/**
* A <code>TrayDialog</code> is a specialized <code>Dialog</code> that can contain
* a tray on its side. The tray's content is provided as a <code>DialogTray</code>.
* <p>
* It is recommended to subclass this class instead of <code>Dialog</code> in all
* cases except where the dialog should never show a tray. For example, dialogs
* which are very short, simple, and quick to dismiss (e.g. a message dialog with
* an OK button) should subclass <code>Dialog</code>.
* </p>
* <p>
* Note: Trays are not supported on dialogs that use a custom layout on the <code>
* Shell</code> by overriding <code>Window#getLayout()</code>.
* </p>
*
* @see org.eclipse.jface.dialogs.DialogTray
* @see org.eclipse.jface.window.Window#getLayout()
* @since 3.2
*/
public abstract class TrayDialog extends Dialog {

  private final class ResizeListener extends ControlAdapter {

    private final GridData data;
    private final Shell shell;
    private final int TRAY_RATIO = 100; // Percentage of extra width devoted to tray when resizing
    private int remainder = 0; // Used to prevent rounding errors from accumulating

    private ResizeListener(GridData data, Shell shell) {
      this.data = data;
      this.shell = shell;
    }

    public void controlResized (ControlEvent event) {
        int newWidth = shell.getSize().x;
        if (newWidth != shellWidth) {         
          int shellWidthIncrease = newWidth - shellWidth;
          int trayWidthIncreaseTimes100 = (shellWidthIncrease * TRAY_RATIO) + remainder;
          int trayWidthIncrease = trayWidthIncreaseTimes100/100;
          remainder = trayWidthIncreaseTimes100 - (100 * trayWidthIncrease);
          data.widthHint = data.widthHint + trayWidthIncrease;
          shellWidth = newWidth;
          if (!shell.isDisposed()) {
            shell.layout();
          }
        }
      }
  }

  private static boolean dialogHelpAvailable;

  /**
   * The dialog's tray (null if none).
   */
  private DialogTray tray;

  /**
   * The tray's control (null if none).
   */
  private Control trayControl;
 
  /**
   * The control that had focus before the tray was opened (null if none).
   */
  private Control nonTrayFocusControl;
 
  /*
   * The separator to the left of the sash.
   */
  private Label leftSeparator;
 
  /*
   * The separator to the right of the sash.
   */
  private Label rightSeparator;
 
  /*
   * The sash that allows the user to resize the tray.
   */
  private Sash sash;
 
  /*
   * Whether or not help is available for this dialog.
   */
  private boolean helpAvailable = isDialogHelpAvailable();
 
  private int shellWidth;

  private ControlAdapter resizeListener;

  /**
   * The help button (null if none).
   */
  private ToolItem fHelpButton;

  /**
   * Creates a tray dialog instance. Note that the window will have no visual
   * representation (no widgets) until it is told to open.
   *
   * @param shell the parent shell, or <code>null</code> to create a top-level shell
   */
  protected TrayDialog(Shell shell) {
    super(shell);
  }
 
  /**
   * Creates a tray dialog with the given parent.
   *
   * @param parentShell the object that returns the current parent shell
   */
  protected TrayDialog(IShellProvider parentShell) {
    super(parentShell);
  }

  /**
   * Closes this dialog's tray, disposing its widgets.
   *
   * @throws IllegalStateException if the tray was not open
   */
  public void closeTray() throws IllegalStateException {
    if (getTray() == null) {
      throw new IllegalStateException("Tray was not open"); //$NON-NLS-1$
    }
    Shell shell = getShell();
    Control focusControl = shell.getDisplay().getFocusControl();
    if (focusControl!= null && isContained(trayControl, focusControl)) {
      if (nonTrayFocusControl!= null && !nonTrayFocusControl.isDisposed()) {
        nonTrayFocusControl.setFocus();
      } else {
        shell.setFocus();
      }
    }
    nonTrayFocusControl= null;
    shell.removeControlListener (resizeListener);
    resizeListener = null;
    int trayWidth = trayControl.getSize().x + leftSeparator.getSize().x + sash.getSize().x + rightSeparator.getSize().x;
    trayControl.dispose();
    trayControl = null;
    tray = null;
    leftSeparator.dispose();
    leftSeparator = null;
    rightSeparator.dispose();
    rightSeparator = null;
    sash.dispose();
    sash = null;
    Rectangle bounds = shell.getBounds();
    shell.setBounds(bounds.x + ((getDefaultOrientation() == SWT.RIGHT_TO_LEFT) ? trayWidth : 0), bounds.y, bounds.width - trayWidth, bounds.height);
    if (fHelpButton != null) {
      fHelpButton.setSelection(false);
    }
  }
 
  /**
   * Returns true if the given Control is a direct or indirect child of
   * container.
   *
   * @param container
   *            the potential parent
   * @param control
   * @return boolean <code>true</code> if control is a child of container
   */
  private boolean isContained(Control container, Control control) {
    Composite parent;
    while ((parent = control.getParent()) != null) {
      if (parent == container) {
        return true;
      }
      control = parent;
    }
    return false;
  }

  /* (non-Javadoc)
   * @see org.eclipse.jface.window.Window#handleShellCloseEvent()
   */
  protected void handleShellCloseEvent() {
    /*
     * Close the tray to ensure that those dialogs that remember their
     * size do not store the tray size.
     */
    if (getTray() != null) {
      closeTray();
    }

    super.handleShellCloseEvent();
  }
 
    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#createButtonBar(org.eclipse.swt.widgets.Composite)
     */
  protected Control createButtonBar(Composite parent) {
      Composite composite = new Composite(parent, SWT.NONE);
      GridLayout layout = new GridLayout();
      layout.marginWidth = 0;
      layout.marginHeight = 0;
      layout.horizontalSpacing = 0;
      composite.setLayout(layout);
      composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
      composite.setFont(parent.getFont());

    // create help control if needed
        if (isHelpAvailable()) {
          Control helpControl = createHelpControl(composite);
          ((GridData) helpControl.getLayoutData()).horizontalIndent = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
    }
        Control buttonSection = super.createButtonBar(composite);
        ((GridData) buttonSection.getLayoutData()).grabExcessHorizontalSpace = true;
        return composite;
  }

  /**
   * Creates a new help control that provides access to context help.
   * <p>
   * The <code>TrayDialog</code> implementation of this method creates
   * the control, registers it for selection events including selection,
   * Note that the parent's layout is assumed to be a <code>GridLayout</code>
   * and the number of columns in this layout is incremented. Subclasses may
   * override.
   * </p>
   *
   * @param parent the parent composite
   * @return the help control
   */
    protected Control createHelpControl(Composite parent) {
    Image helpImage = JFaceResources.getImage(DLG_IMG_HELP);
    if (helpImage != null) {
      return createHelpImageButton(parent, helpImage);
    }
    return createHelpLink(parent);
    }
   
    /*
     * Creates a button with a help image. This is only used if there
     * is an image available.
     */
  private ToolBar createHelpImageButton(Composite parent, Image image) {
        ToolBar toolBar = new ToolBar(parent, SWT.FLAT | SWT.NO_FOCUS);
        ((GridLayout) parent.getLayout()).numColumns++;
    toolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    final Cursor cursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
    toolBar.setCursor(cursor);
    toolBar.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        cursor.dispose();
      }
    });   
        fHelpButton = new ToolItem(toolBar, SWT.CHECK);
    fHelpButton.setImage(image);
    fHelpButton.setToolTipText(JFaceResources.getString("helpToolTip")); //$NON-NLS-1$
    fHelpButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
        helpPressed();
            }
        });
    return toolBar;
  }

  /*
   * Creates a help link. This is used when there is no help image
   * available.
   */
  private Link createHelpLink(Composite parent) {
    Link link = new Link(parent, SWT.WRAP | SWT.NO_FOCUS);
        ((GridLayout) parent.getLayout()).numColumns++;
    link.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    link.setText("<a>"+IDialogConstants.HELP_LABEL+"</a>"); //$NON-NLS-1$ //$NON-NLS-2$
    link.setToolTipText(IDialogConstants.HELP_LABEL);
    link.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
        helpPressed();
            }
        });
    return link;
 
 
  /*
   * Returns whether or not the given layout can support the addition of a tray.
   */
  private boolean isCompatibleLayout(Layout layout) {
    if (layout != null && layout instanceof GridLayout) {
      GridLayout grid = (GridLayout)layout;
      return !grid.makeColumnsEqualWidth && (grid.horizontalSpacing == 0) &&
          (grid.marginWidth == 0) && (grid.marginHeight == 0) &&
          (grid.numColumns == 5);
    }
    return false;
  }

  /**
   * Returns whether or not context help is available for this dialog. This
   * can affect whether or not the dialog will display additional help
   * mechanisms such as a help control in the button bar.
   *
   * @return whether or not context help is available for this dialog
   */
  public boolean isHelpAvailable() {
    return helpAvailable;
  }
 
  /**
   * The tray dialog's default layout is a modified version of the default
   * <code>Window</code> layout that can accomodate a tray, however it still
   * conforms to the description of the <code>Window</code> default layout.
   * <p>
   * Note: Trays may not be supported with all custom layouts on the dialog's
   * Shell. To avoid problems, use a single outer <code>Composite</code> for
   * your dialog area, and set your custom layout on that <code>Composite</code>.
   * </p>
   *
   * @see org.eclipse.jface.window.Window#getLayout()
   * @return a newly created layout or <code>null</code> for no layout
   */
  protected Layout getLayout() {
    GridLayout layout = (GridLayout)super.getLayout();
    layout.numColumns = 5;
    layout.horizontalSpacing = 0;
    return layout;
  }
 
  /**
   * Returns the tray currently shown in the dialog, or <code>null</code>
   * if there is no tray.
   *
   * @return the dialog's current tray, or <code>null</code> if there is none
   */
  public DialogTray getTray() {
    return tray;
  }
 
  /*
   * Called when the help control is invoked. This emulates the keyboard
   * context help behavior (e.g. F1 on Windows). It traverses the widget
   * tree upward until it finds a widget that has a help listener on it,
   * then invokes a help event on that widget.
   * If the help tray is already open, it closes it and doesn't invoke
   * any help listener.
   */
  private void helpPressed() {
    if (getTray() == null ||
        fHelpButton != null && fHelpButton.getSelection()) { // help button was not selected before
      if (getShell() != null) {
        Control c = getShell().getDisplay().getFocusControl();
        while (c != null) {
          if (c.isListening(SWT.Help)) {
            c.notifyListeners(SWT.Help, new Event());
            break;
          }
          c = c.getParent();
        }
        if (fHelpButton != null && getTray() != null) {
          fHelpButton.setSelection(true);
        }
      }

    } else {
      closeTray();
    }
  }
 
  /**
   * Constructs the tray's widgets and displays the tray in this dialog. The
   * dialog's size will be adjusted to accommodate the tray.
   *
   * @param tray the tray to show in this dialog
   * @throws IllegalStateException if the dialog already has a tray open
   * @throws UnsupportedOperationException if the dialog does not support trays,
   *            for example if it uses a custom layout.
   */
  public void openTray(DialogTray tray) throws IllegalStateException, UnsupportedOperationException {
    if (tray == null) {
      throw new NullPointerException("Tray was null"); //$NON-NLS-1$
    }
    if (getTray() != null) {
      throw new IllegalStateException("Tray was already open"); //$NON-NLS-1$
    }
    if (!isCompatibleLayout(getShell().getLayout())) {
      throw new UnsupportedOperationException("Trays not supported with custom layouts"); //$NON-NLS-1$
    }
    final Shell shell = getShell();
    Control focusControl = shell.getDisplay().getFocusControl();
    if (focusControl != null && isContained(shell, focusControl)) {
      nonTrayFocusControl = focusControl;
    }
    leftSeparator = new Label(shell, SWT.SEPARATOR | SWT.VERTICAL);
    leftSeparator.setLayoutData(new GridData(GridData.FILL_VERTICAL));
    sash = new Sash(shell, SWT.VERTICAL);
    sash.setLayoutData(new GridData(GridData.FILL_VERTICAL));
    rightSeparator = new Label(shell, SWT.SEPARATOR | SWT.VERTICAL);
    rightSeparator.setLayoutData(new GridData(GridData.FILL_VERTICAL));
    trayControl = tray.createContents(shell);
    Rectangle clientArea = shell.getClientArea();
    final GridData data = new GridData(GridData.FILL_VERTICAL);
    data.widthHint = trayControl.computeSize(SWT.DEFAULT, clientArea.height).x;
    trayControl.setLayoutData(data);
    int trayWidth = leftSeparator.computeSize(SWT.DEFAULT, clientArea.height).x + sash.computeSize(SWT.DEFAULT, clientArea.height).x + rightSeparator.computeSize(SWT.DEFAULT, clientArea.height).x + data.widthHint;
    Rectangle bounds = shell.getBounds();
    shell.setBounds(bounds.x - ((getDefaultOrientation() == SWT.RIGHT_TO_LEFT) ? trayWidth : 0), bounds.y, bounds.width + trayWidth, bounds.height);
    sash.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        if (event.detail != SWT.DRAG) {
          Rectangle clientArea = shell.getClientArea();
          int newWidth = clientArea.width - event.x - (sash.getSize().x + rightSeparator.getSize().x);
          if (newWidth != data.widthHint) {
            data.widthHint = newWidth;
            shell.layout();
          }
        }
      }
    });
    shellWidth = shell.getSize().x;
   
    resizeListener = new ResizeListener(data, shell);
    shell.addControlListener (resizeListener);
      
    this.tray = tray;
  }
 
  /**
   * Sets whether or not context help is available for this dialog. This
   * can affect whether or not the dialog will display additional help
   * mechanisms such as a help control in the button bar.
   *
   * @param helpAvailable whether or not context help is available for the dialog
   */
  public void setHelpAvailable(boolean helpAvailable) {
    this.helpAvailable = helpAvailable;
  }
 
  /**
   * Tests if dialogs that have help control should show it
   * all the time or only when explicitly requested for
   * each dialog instance.
   *
   * @return <code>true</code> if dialogs that support help
   * control should show it by default, <code>false</code> otherwise.
   * @since 3.2
   */
  public static boolean isDialogHelpAvailable() {
    return dialogHelpAvailable;
  }
 
  /**
   * Sets whether JFace dialogs that support help control should
   * show the control by default. If set to <code>false</code>,
   * help control can still be shown on a per-dialog basis.
   *
   * @param helpAvailable <code>true</code> to show the help
   * control, <code>false</code> otherwise.
   * @since 3.2
   */
  public static void setDialogHelpAvailable(boolean helpAvailable) {
    dialogHelpAvailable = helpAvailable;
  }
}
TOP

Related Classes of org.eclipse.jface.dialogs.TrayDialog

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.