# HG changeset patch # User Frank Benoit # Date 1206918187 -7200 # Node ID 11bd25f933328806420ccc62cfd0f506ed4d188a # Parent b6c35faf97c808ffb7e0bd84ba0387a72b183ed5 TrayDialog diff -r b6c35faf97c8 -r 11bd25f93332 dwtx/jface/dialogs/DialogTray.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/dialogs/DialogTray.d Mon Mar 31 01:03:07 2008 +0200 @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2005 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.dialogs.DialogTray; + +import dwt.widgets.Composite; +import dwt.widgets.Control; + +/** + *

+ * This class is the abstract superclass of all dialog trays. A tray can be opened + * in any TrayDialog. + *

+ * + * @see dwtx.jface.dialogs.TrayDialog + * @since 3.2 + */ +public abstract class DialogTray { + + /** + * Creates the contents (widgets) that will be contained in the tray. + *

+ * Tray implementions must not set a layout on the parent composite, or assume + * a particular layout on the parent. The tray dialog will allocate space + * according to the natural size of the tray, and will fill the tray area with the + * tray's contents. + *

+ * + * @param parent the composite that will contain the tray + * @return the contents of the tray, as a Control + */ + protected abstract Control createContents(Composite parent); + package Control createContents_package(Composite parent){ + return createContents(parent); + } +} diff -r b6c35faf97c8 -r 11bd25f93332 dwtx/jface/dialogs/TrayDialog.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/dialogs/TrayDialog.d Mon Mar 31 01:03:07 2008 +0200 @@ -0,0 +1,413 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 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 + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ +module dwtx.jface.dialogs.TrayDialog; + +import dwtx.jface.dialogs.Dialog; +import dwtx.jface.dialogs.DialogTray; +import dwtx.jface.dialogs.IDialogConstants; + +import dwt.DWT; +import dwt.events.DisposeEvent; +import dwt.events.DisposeListener; +import dwt.events.SelectionAdapter; +import dwt.events.SelectionEvent; +import dwt.graphics.Cursor; +import dwt.graphics.Image; +import dwt.graphics.Rectangle; +import dwt.layout.GridData; +import dwt.layout.GridLayout; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Event; +import dwt.widgets.Label; +import dwt.widgets.Layout; +import dwt.widgets.Link; +import dwt.widgets.Listener; +import dwt.widgets.Sash; +import dwt.widgets.Shell; +import dwt.widgets.ToolBar; +import dwt.widgets.ToolItem; +import dwtx.jface.resource.JFaceResources; +import dwtx.jface.window.IShellProvider; + +import dwt.dwthelper.utils; +import tango.core.Exception; + +/** + * A TrayDialog is a specialized Dialog that can contain + * a tray on its side. The tray's content is provided as a DialogTray. + *

+ * It is recommended to subclass this class instead of Dialog 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 Dialog. + *

+ *

+ * Note: Trays are not supported on dialogs that use a custom layout on the + * Shell by overriding Window#getLayout(). + *

+ * + * @see dwtx.jface.dialogs.DialogTray + * @see dwtx.jface.window.Window#getLayout() + * @since 3.2 + */ +public abstract class TrayDialog : Dialog { + + private static bool dialogHelpAvailable = false; + + /* + * The dialog's tray (null if none). + */ + private DialogTray tray; + + /* + * The tray's control. + */ + private Control trayControl; + + /* + * 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 bool helpAvailable; + + /** + * 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 null to create a top-level shell + */ + protected this(Shell shell) { + super(shell); + helpAvailable = isDialogHelpAvailable(); + } + + /** + * Creates a tray dialog with the given parent. + * + * @param parentShell the object that returns the current parent shell + */ + protected this(IShellProvider parentShell) { + super(parentShell); + helpAvailable = isDialogHelpAvailable(); + } + + /** + * Closes this dialog's tray, disposing its widgets. + * + * @throws IllegalStateException if the tray was not open + */ + public void closeTray() { + if (getTray() is null) { + throw new IllegalStateException("Tray was not open"); //$NON-NLS-1$ + } + 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; + Shell shell = getShell(); + Rectangle bounds = shell.getBounds(); + shell.setBounds(bounds.x + ((getDefaultOrientation() is DWT.RIGHT_TO_LEFT) ? trayWidth : 0), bounds.y, bounds.width - trayWidth, bounds.height); + } + + /* (non-Javadoc) + * @see dwtx.jface.dialogs.Dialog#close() + */ + public bool close() { + /* + * Close the tray to ensure that those dialogs that remember their + * size do not store the tray size. + */ + if (getTray() !is null) { + closeTray(); + } + return super.close(); + } + + /* (non-Javadoc) + * @see dwtx.jface.dialogs.Dialog#createButtonBar(dwt.widgets.Composite) + */ + protected Control createButtonBar(Composite parent) { + Composite composite = new Composite(parent, DWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + layout.horizontalSpacing = 0; + composite.setLayout(layout); + composite.setLayoutData(new GridData(DWT.FILL, DWT.CENTER, false, false)); + composite.setFont(parent.getFont()); + + // create help control if needed + if (isHelpAvailable()) { + Control helpControl = createHelpControl(composite); + (cast(GridData) helpControl.getLayoutData()).horizontalIndent = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); + } + Control buttonSection = super.createButtonBar(composite); + (cast(GridData) buttonSection.getLayoutData()).grabExcessHorizontalSpace = true; + return composite; + } + + /** + * Creates a new help control that provides access to context help. + *

+ * The TrayDialog 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 GridLayout + * and the number of columns in this layout is incremented. Subclasses may + * override. + *

+ * + * @param parent the parent composite + * @return the help control + */ + protected Control createHelpControl(Composite parent) { + Image helpImage = JFaceResources.getImage(DLG_IMG_HELP); + if (helpImage !is 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, DWT.FLAT | DWT.NO_FOCUS); + (cast(GridLayout) parent.getLayout()).numColumns++; + toolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); + Cursor cursor = new Cursor(parent.getDisplay(), DWT.CURSOR_HAND); + toolBar.setCursor(cursor); + toolBar.addDisposeListener(new class DisposeListener { + Cursor cursor_; + this(){ + cursor_=cursor; + } + public void widgetDisposed(DisposeEvent e) { + cursor_.dispose(); + } + }); + ToolItem item = new ToolItem(toolBar, DWT.NONE); + item.setImage(image); + item.setToolTipText(JFaceResources.getString("helpToolTip")); //$NON-NLS-1$ + item.addSelectionListener(new class 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, DWT.WRAP | DWT.NO_FOCUS); + (cast(GridLayout) parent.getLayout()).numColumns++; + link.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); + link.setText(""~IDialogConstants.HELP_LABEL~""); //$NON-NLS-1$ //$NON-NLS-2$ + link.setToolTipText(IDialogConstants.HELP_LABEL); + link.addSelectionListener(new class SelectionAdapter { + public void widgetSelected(SelectionEvent e) { + helpPressed(); + } + }); + return link; + } + + /* + * Returns whether or not the given layout can support the addition of a tray. + */ + private bool isCompatibleLayout(Layout layout) { + if (layout !is null && cast(GridLayout)layout ) { + GridLayout grid = cast(GridLayout)layout; + return !grid.makeColumnsEqualWidth && (grid.horizontalSpacing is 0) && + (grid.marginWidth is 0) && (grid.marginHeight is 0) && + (grid.horizontalSpacing is 0) && (grid.numColumns is 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 bool isHelpAvailable() { + return helpAvailable; + } + + /** + * The tray dialog's default layout is a modified version of the default + * Window layout that can accomodate a tray, however it still + * conforms to the description of the Window default layout. + *

+ * Note: Trays may not be supported with all custom layouts on the dialog's + * Shell. To avoid problems, use a single outer Composite for + * your dialog area, and set your custom layout on that Composite. + *

+ * + * @see dwtx.jface.window.Window#getLayout() + * @return a newly created layout or null for no layout + */ + protected Layout getLayout() { + GridLayout layout = cast(GridLayout)super.getLayout(); + layout.numColumns = 5; + layout.horizontalSpacing = 0; + return layout; + } + + /** + * Returns the tray currently shown in the dialog, or null + * if there is no tray. + * + * @return the dialog's current tray, or null 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. + */ + private void helpPressed() { + if (getShell() !is null) { + Control c = getShell().getDisplay().getFocusControl(); + while (c !is null) { + if (c.isListening(DWT.Help)) { + c.notifyListeners(DWT.Help, new Event()); + break; + } + c = c.getParent(); + } + } + } + + /** + * Constructs the tray's widgets and displays the tray in this dialog. The + * dialog's size will be adjusted to accomodate 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) { + if (tray is null) { + throw new NullPointerException("Tray was null"); //$NON-NLS-1$ + } + if (getTray() !is 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$ + } + Shell shell = getShell(); + leftSeparator = new Label(shell, DWT.SEPARATOR | DWT.VERTICAL); + leftSeparator.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + sash = new Sash(shell, DWT.VERTICAL); + sash.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + rightSeparator = new Label(shell, DWT.SEPARATOR | DWT.VERTICAL); + rightSeparator.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + trayControl = tray.createContents_package(shell); + Rectangle clientArea = shell.getClientArea(); + GridData data = new GridData(GridData.FILL_VERTICAL); + data.widthHint = trayControl.computeSize(DWT.DEFAULT, clientArea.height).x; + trayControl.setLayoutData(data); + int trayWidth = leftSeparator.computeSize(DWT.DEFAULT, clientArea.height).x + sash.computeSize(DWT.DEFAULT, clientArea.height).x + rightSeparator.computeSize(DWT.DEFAULT, clientArea.height).x + data.widthHint; + Rectangle bounds = shell.getBounds(); + shell.setBounds(bounds.x - ((getDefaultOrientation() is DWT.RIGHT_TO_LEFT) ? trayWidth : 0), bounds.y, bounds.width + trayWidth, bounds.height); + sash.addListener(DWT.Selection, new class Listener { + Shell shell_; + GridData data_; + this(){ + shell_=shell; + data_=data; + } + public void handleEvent(Event event) { + if (event.detail !is DWT.DRAG) { + Rectangle clientArea = shell_.getClientArea(); + int newWidth = clientArea.width - event.x - (sash.getSize().x + rightSeparator.getSize().x); + if (newWidth !is data_.widthHint) { + data_.widthHint = newWidth; + shell_.layout(); + } + } + } + }); + 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(bool 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 true if dialogs that support help + * control should show it by default, false otherwise. + * @since 3.2 + */ + public static bool isDialogHelpAvailable() { + return dialogHelpAvailable; + } + + /** + * Sets whether JFace dialogs that support help control should + * show the control by default. If set to false, + * help control can still be shown on a per-dialog basis. + * + * @param helpAvailable true to show the help + * control, false otherwise. + * @since 3.2 + */ + public static void setDialogHelpAvailable(bool helpAvailable) { + dialogHelpAvailable = helpAvailable; + } +}