Mercurial > projects > dwt-addons
view dwtx/jface/dialogs/PopupDialog.d @ 43:ea8ff534f622
Fix override and super aliases
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 11 Apr 2008 01:24:25 +0200 |
parents | 4567a6f54939 |
children | 46a6e0e6ccd4 |
line wrap: on
line source
/******************************************************************************* * 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 * Stefan Xenos, IBM - bug 156790: Adopt GridLayoutFactory within JFace * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.jface.dialogs.PopupDialog; import dwtx.jface.dialogs.IDialogConstants; import dwtx.jface.dialogs.IDialogSettings; import dwtx.jface.dialogs.Dialog; import tango.util.collection.ArraySeq; import tango.util.collection.model.Seq; import tango.util.collection.model.SeqView; import dwt.DWT; import dwt.events.DisposeEvent; import dwt.events.DisposeListener; import dwt.events.MouseAdapter; import dwt.events.MouseEvent; import dwt.events.SelectionAdapter; import dwt.events.SelectionEvent; import dwt.graphics.Color; import dwt.graphics.Font; import dwt.graphics.FontData; import dwt.graphics.Image; import dwt.graphics.Point; import dwt.graphics.Rectangle; import dwt.widgets.Composite; import dwt.widgets.Control; import dwt.widgets.Display; import dwt.widgets.Event; import dwt.widgets.Label; import dwt.widgets.Listener; import dwt.widgets.Menu; import dwt.widgets.Shell; import dwt.widgets.ToolBar; import dwt.widgets.ToolItem; import dwt.widgets.Tracker; import dwtx.jface.action.Action; import dwtx.jface.action.GroupMarker; import dwtx.jface.action.IAction; import dwtx.jface.action.IMenuManager; import dwtx.jface.action.MenuManager; import dwtx.jface.action.Separator; import dwtx.jface.layout.GridDataFactory; import dwtx.jface.layout.GridLayoutFactory; import dwtx.jface.resource.ImageDescriptor; import dwtx.jface.resource.JFaceResources; import dwtx.jface.window.Window; import dwt.dwthelper.utils; /** * A lightweight, transient dialog that is popped up to show contextual or * temporal information and is easily dismissed. Clients control whether the * dialog should be able to receive input focus. An optional title area at the * top and an optional info area at the bottom can be used to provide additional * information. * <p> * Because the dialog is short-lived, most of the configuration of the dialog is * done in the constructor. Set methods are only provided for those values that * are expected to be dynamically computed based on a particular instance's * internal state. * <p> * Clients are expected to override the creation of the main dialog area, and * may optionally override the creation of the title area and info area in order * to add content. In general, however, the creation of stylistic features, such * as the dialog menu, separator styles, and fonts, is kept private so that all * popup dialogs will have a similar appearance. * * @since 3.2 */ public class PopupDialog : Window { /** * */ private static const GridDataFactory LAYOUTDATA_GRAB_BOTH; /** * The dialog settings key name for stored dialog x location. */ private static const String DIALOG_ORIGIN_X = "DIALOG_X_ORIGIN"; //$NON-NLS-1$ /** * The dialog settings key name for stored dialog y location. */ private static const String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$ /** * The dialog settings key name for stored dialog width. */ private static const String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$ /** * The dialog settings key name for stored dialog height. */ private static const String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$ /** * The dialog settings key name for remembering if the persisted bounds * should be accessed. */ private static const String DIALOG_USE_PERSISTED_BOUNDS = "DIALOG_USE_PERSISTED_BOUNDS"; //$NON-NLS-1$ /** * Move action for the dialog. */ private class MoveAction : Action { this() { super(JFaceResources.getString("PopupDialog.move"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON); } /* * (non-Javadoc) * * @see dwtx.jface.action.IAction#run() */ public override void run() { performTrackerAction(DWT.NONE); } } /** * Resize action for the dialog. */ private class ResizeAction : Action { this() { super(JFaceResources.getString("PopupDialog.resize"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON); } /* * @see dwtx.jface.action.Action#run() */ public override void run() { performTrackerAction(DWT.RESIZE); } } /** * * Remember bounds action for the dialog. */ private class PersistBoundsAction : Action { this() { super(JFaceResources.getString("PopupDialog.persistBounds"), //$NON-NLS-1$ IAction.AS_CHECK_BOX); setChecked(persistBounds); } /* * (non-Javadoc) * * @see dwtx.jface.action.IAction#run() */ public override void run() { persistBounds = isChecked(); } } /** * Shell style appropriate for a simple hover popup that cannot get focus. */ public const static int HOVER_SHELLSTYLE = DWT.NO_FOCUS | DWT.ON_TOP | DWT.NO_TRIM; /** * Shell style appropriate for an info popup that can get focus. */ public const static int INFOPOPUP_SHELLSTYLE = DWT.NO_TRIM; /** * Shell style appropriate for a resizable info popup that can get focus. */ public const static int INFOPOPUPRESIZE_SHELLSTYLE = DWT.RESIZE; /** * Margin width (in pixels) to be used in layouts inside popup dialogs * (value is 0). */ public const static int POPUP_MARGINWIDTH = 0; /** * Margin height (in pixels) to be used in layouts inside popup dialogs * (value is 0). */ public const static int POPUP_MARGINHEIGHT = 0; /** * Vertical spacing (in pixels) between cells in the layouts inside popup * dialogs (value is 1). */ public const static int POPUP_VERTICALSPACING = 1; /** * Vertical spacing (in pixels) between cells in the layouts inside popup * dialogs (value is 1). */ public const static int POPUP_HORIZONTALSPACING = 1; /** * */ private static const GridLayoutFactory POPUP_LAYOUT_FACTORY; static this(){ LAYOUTDATA_GRAB_BOTH = GridDataFactory.fillDefaults().grab(true,true); POPUP_LAYOUT_FACTORY = GridLayoutFactory .fillDefaults().margins(POPUP_MARGINWIDTH, POPUP_MARGINHEIGHT) .spacing(POPUP_HORIZONTALSPACING, POPUP_VERTICALSPACING); } /** * Border thickness in pixels. */ private static const int BORDER_THICKNESS = 1; /** * The dialog's toolbar for the move and resize capabilities. */ private ToolBar toolBar = null; /** * The dialog's menu manager. */ private MenuManager menuManager = null; /** * The control representing the main dialog area. */ private Control dialogArea; /** * Labels that contain title and info text. Cached so they can be updated * dynamically if possible. */ private Label titleLabel, infoLabel; /** * Separator controls. Cached so they can be excluded from color changes. */ private Control titleSeparator, infoSeparator; /** * The images for the dialog menu. */ private Image menuImage, disabledMenuImage = null; /** * Font to be used for the info area text. Computed based on the dialog's * font. */ private Font infoFont; /** * Font to be used for the title area text. Computed based on the dialog's * font. */ private Font titleFont; /** * Flags indicating whether we are listening for shell deactivate events, * either those or our parent's. Used to prevent closure when a menu command * is chosen or a secondary popup is launched. */ private bool listenToDeactivate; private bool listenToParentDeactivate; private Listener parentDeactivateListener; /** * Flag indicating whether focus should be taken when the dialog is opened. */ private bool takeFocusOnOpen = false; /** * Flag specifying whether a menu should be shown that allows the user to * move and resize. */ private bool showDialogMenu_ = false; /** * Flag specifying whether a menu action allowing the user to choose whether * the dialog bounds should be persisted is to be shown. */ private bool showPersistAction = false; /** * Flag specifying whether the bounds of the popup should be persisted. This * flag is updated by a menu if the menu is shown. */ private bool persistBounds = false; /** * Text to be shown in an optional title area (on top). */ private String titleText; /** * Text to be shown in an optional info area (at the bottom). */ private String infoText; /** * Constructs a new instance of <code>PopupDialog</code>. * * @param parent * The parent shell. * @param shellStyle * The shell style. * @param takeFocusOnOpen * A bool indicating whether focus should be taken by this * popup when it opens. * @param persistBounds * A bool indicating whether the bounds should be persisted * upon close of the dialog. The bounds can only be persisted if * the dialog settings for persisting the bounds are also * specified. If a menu action will be provided that allows the * user to control this feature, then the last known value of the * user's setting will be used instead of this flag. * @param showDialogMenu * A bool indicating whether a menu for moving and resizing * the popup should be provided. * @param showPersistAction * A bool indicating whether an action allowing the user to * control the persisting of the dialog bounds should be shown in * the dialog menu. This parameter has no effect if * <code>showDialogMenu</code> is <code>false</code>. * @param titleText * Text to be shown in an upper title area, or <code>null</code> * if there is no title. * @param infoText * Text to be shown in a lower info area, or <code>null</code> * if there is no info area. * * @see PopupDialog#getDialogSettings() */ public this(Shell parent, int shellStyle, bool takeFocusOnOpen, bool persistBounds, bool showDialogMenu_, bool showPersistAction, String titleText, String infoText) { super(parent); setShellStyle(shellStyle); this.takeFocusOnOpen = takeFocusOnOpen; this.showDialogMenu_ = showDialogMenu_; this.showPersistAction = showPersistAction; this.titleText = titleText; this.infoText = infoText; setBlockOnOpen(false); this.persistBounds = persistBounds; initializeWidgetState(); } /* * (non-Javadoc) * * @see dwtx.jface.window.Window#configureShell(Shell) */ protected override void configureShell(Shell shell) { Display display = shell.getDisplay(); shell.setBackground(display.getSystemColor(DWT.COLOR_BLACK)); int border = ((getShellStyle() & DWT.NO_TRIM) is 0) ? 0 : BORDER_THICKNESS; GridLayoutFactory.fillDefaults().margins(border, border).spacing(5,5).applyTo(shell); shell.addListener(DWT.Deactivate, new class Listener { public void handleEvent(Event event) { /* * Close if we are deactivating and have no child shells. If we * have child shells, we are deactivating due to their opening. * On X, we receive this when a menu child (such as the system * menu) of the shell opens, but I have not found a way to * distinguish that case here. Hence bug #113577 still exists. */ if (listenToDeactivate && event.widget is getShell() && getShell().getShells().length is 0) { close(); } else { /* We typically ignore deactivates to work around platform-specific * event ordering. Now that we've ignored whatever we were supposed to, * start listening to deactivates. Example issues can be found in * https://bugs.eclipse.org/bugs/show_bug.cgi?id=123392 */ listenToDeactivate = true; } } }); // Set this true whenever we activate. It may have been turned // off by a menu or secondary popup showing. shell.addListener(DWT.Activate, new class Listener { public void handleEvent(Event event) { // ignore this event if we have launched a child if (event.widget is getShell() && getShell().getShells().length is 0) { listenToDeactivate = true; // Typically we start listening for parent deactivate after // we are activated, except on the Mac, where the deactivate // is received after activate. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=100668 listenToParentDeactivate = !"carbon".equals(DWT.getPlatform()); //$NON-NLS-1$ } } }); if ((getShellStyle() & DWT.ON_TOP) !is 0 && shell.getParent() !is null) { parentDeactivateListener= new class Listener { public void handleEvent(Event event) { if (listenToParentDeactivate) { close(); } else { // Our first deactivate, now start listening on the Mac. listenToParentDeactivate = listenToDeactivate; } } }; shell.getParent().addListener(DWT.Deactivate, parentDeactivateListener); } shell.addDisposeListener(new class DisposeListener { public void widgetDisposed(DisposeEvent event) { handleDispose(); } }); } /** * The <code>PopupDialog</code> implementation of this <code>Window</code> * method creates and lays out the top level composite for the dialog. It * then calls the <code>createTitleMenuArea</code>, * <code>createDialogArea</code>, and <code>createInfoTextArea</code> * methods to create an optional title and menu area on the top, a dialog * area in the center, and an optional info text area at the bottom. * Overriding <code>createDialogArea</code> and (optionally) * <code>createTitleMenuArea</code> and <code>createTitleMenuArea</code> * are recommended rather than overriding this method. * * @param parent * the composite used to parent the contents. * * @return the control representing the contents. */ protected override Control createContents(Composite parent) { Composite composite = new Composite(parent, DWT.NONE); POPUP_LAYOUT_FACTORY.applyTo(composite); LAYOUTDATA_GRAB_BOTH.applyTo(composite); // Title area if (hasTitleArea()) { createTitleMenuArea(composite); titleSeparator = createHorizontalSeparator(composite); } // Content dialogArea = createDialogArea(composite); // Create a grid data layout data if one was not provided. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=118025 if (dialogArea.getLayoutData() is null) { LAYOUTDATA_GRAB_BOTH.applyTo(dialogArea); } // Info field if (hasInfoArea()) { infoSeparator = createHorizontalSeparator(composite); createInfoTextArea(composite); } applyColors(composite); applyFonts(composite); return composite; } /** * Creates and returns the contents of the dialog (the area below the title * area and above the info text area. * <p> * The <code>PopupDialog</code> implementation of this framework method * creates and returns a new <code>Composite</code> with standard margins * and spacing. * <p> * The returned control's layout data must be an instance of * <code>GridData</code>. This method must not modify the parent's * layout. * <p> * Subclasses must override this method but may call <code>super</code> as * in the following example: * * <pre> * Composite composite = (Composite) super.createDialogArea(parent); * //add controls to composite as necessary * return composite; * </pre> * * @param parent * the parent composite to contain the dialog area * @return the dialog area control */ protected Control createDialogArea(Composite parent) { Composite composite = new Composite(parent, DWT.NONE); POPUP_LAYOUT_FACTORY.applyTo(composite); LAYOUTDATA_GRAB_BOTH.applyTo(composite); return composite; } /** * Returns the control that should get initial focus. Subclasses may * override this method. * * @return the Control that should receive focus when the popup opens. */ protected Control getFocusControl() { return dialogArea; } /** * Sets the tab order for the popup. Clients should override to introduce * specific tab ordering. * * @param composite * the composite in which all content, including the title area * and info area, was created. This composite's parent is the * shell. */ protected void setTabOrder(Composite composite) { // default is to do nothing } /** * Returns a bool indicating whether the popup should have a title area * at the top of the dialog. Subclasses may override. Default behavior is to * have a title area if there is to be a menu or title text. * * @return <code>true</code> if a title area should be created, * <code>false</code> if it should not. */ protected bool hasTitleArea() { return titleText !is null || showDialogMenu_; } /** * Returns a bool indicating whether the popup should have an info area * at the bottom of the dialog. Subclasses may override. Default behavior is * to have an info area if info text was provided at the time of creation. * * @return <code>true</code> if a title area should be created, * <code>false</code> if it should not. */ protected bool hasInfoArea() { return infoText !is null; } /** * Creates the title and menu area. Subclasses typically need not override * this method, but instead should use the constructor parameters * <code>showDialogMenu</code> and <code>showPersistAction</code> to * indicate whether a menu should be shown, and * <code>createTitleControl</code> to to customize the presentation of the * title. * * <p> * If this method is overridden, the returned control's layout data must be * an instance of <code>GridData</code>. This method must not modify the * parent's layout. * * @param parent * The parent composite. * @return The Control representing the title and menu area. */ protected Control createTitleMenuArea(Composite parent) { Composite titleAreaComposite = new Composite(parent, DWT.NONE); POPUP_LAYOUT_FACTORY.copy().numColumns(2).applyTo(titleAreaComposite); GridDataFactory.fillDefaults() .align_(DWT.FILL, DWT.CENTER).grab(true, false) .applyTo(titleAreaComposite); createTitleControl(titleAreaComposite); if (showDialogMenu_) { createDialogMenu(titleAreaComposite); } return titleAreaComposite; } /** * Creates the control to be used to represent the dialog's title text. * Subclasses may override if a different control is desired for * representing the title text, or if something different than the title * should be displayed in location where the title text typically is shown. * * <p> * If this method is overridden, the returned control's layout data must be * an instance of <code>GridData</code>. This method must not modify the * parent's layout. * * @param parent * The parent composite. * @return The Control representing the title area. */ protected Control createTitleControl(Composite parent) { titleLabel = new Label(parent, DWT.NONE); GridDataFactory.fillDefaults() .align_(DWT.FILL, DWT.CENTER) .grab(true, false) .span(showDialogMenu_ ? 1 : 2, 1) .applyTo(titleLabel); Font font = titleLabel.getFont(); FontData[] fontDatas = font.getFontData(); for (int i = 0; i < fontDatas.length; i++) { fontDatas[i].setStyle(DWT.BOLD); } titleFont = new Font(titleLabel.getDisplay(), fontDatas); titleLabel.setFont(titleFont); if (titleText !is null) { titleLabel.setText(titleText); } return titleLabel; } /** * Creates the optional info text area. This method is only called if the * <code>hasInfoArea()</code> method returns true. Subclasses typically * need not override this method, but may do so. * * <p> * If this method is overridden, the returned control's layout data must be * an instance of <code>GridData</code>. This method must not modify the * parent's layout. * * * @param parent * The parent composite. * @return The control representing the info text area. * * @see PopupDialog#hasInfoArea() * @see PopupDialog#createTitleControl(Composite) */ protected Control createInfoTextArea(Composite parent) { // Status label infoLabel = new Label(parent, DWT.RIGHT); infoLabel.setText(infoText); Font font = infoLabel.getFont(); FontData[] fontDatas = font.getFontData(); for (int i = 0; i < fontDatas.length; i++) { fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10); } infoFont = new Font(infoLabel.getDisplay(), fontDatas); infoLabel.setFont(infoFont); GridDataFactory.fillDefaults().grab(true, false).align_(DWT.FILL, DWT.BEGINNING) .applyTo(infoLabel); infoLabel.setForeground(parent.getDisplay().getSystemColor( DWT.COLOR_WIDGET_DARK_SHADOW)); return infoLabel; } /** * Create a horizontal separator for the given parent. * * @param parent * The parent composite. * @return The Control representing the horizontal separator. */ private Control createHorizontalSeparator(Composite parent) { Label separator = new Label(parent, DWT.SEPARATOR | DWT.HORIZONTAL | DWT.LINE_DOT); GridDataFactory.fillDefaults().align_(DWT.FILL, DWT.CENTER).grab(true, false).applyTo(separator); return separator; } /** * Create the dialog's menu for the move and resize actions. * * @param parent * The parent composite. */ private void createDialogMenu(Composite parent) { toolBar = new ToolBar(parent, DWT.FLAT); ToolItem viewMenuButton = new ToolItem(toolBar, DWT.PUSH, 0); GridDataFactory.fillDefaults().align_(DWT.END, DWT.CENTER).applyTo(toolBar); menuImage = ImageDescriptor.createFromFile( getImportData!("dwtx.jface.dialogs.images.popup_menu.gif")).createImage();//$NON-NLS-1$ disabledMenuImage = ImageDescriptor.createFromFile( getImportData!("dwtx.jface.dialogs.images.popup_menu_disabled.gif")).createImage();//$NON-NLS-1$ viewMenuButton.setImage(menuImage); viewMenuButton.setDisabledImage(disabledMenuImage); viewMenuButton.setToolTipText(JFaceResources .getString("PopupDialog.menuTooltip")); //$NON-NLS-1$ viewMenuButton.addSelectionListener(new class SelectionAdapter { public void widgetSelected(SelectionEvent e) { showDialogMenu(); } }); viewMenuButton.addDisposeListener(new class DisposeListener { public void widgetDisposed(DisposeEvent e) { menuImage.dispose(); menuImage = null; disabledMenuImage.dispose(); disabledMenuImage = null; } }); // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=177183 toolBar.addMouseListener(new class MouseAdapter { public void mouseDown(MouseEvent e) { showDialogMenu(); } }); } /** * Fill the dialog's menu. Subclasses may extend or override. * * @param dialogMenu * The dialog's menu. */ protected void fillDialogMenu(IMenuManager dialogMenu) { dialogMenu.add(new GroupMarker("SystemMenuStart")); //$NON-NLS-1$ dialogMenu.add(new MoveAction()); dialogMenu.add(new ResizeAction()); if (showPersistAction) { dialogMenu.add(new PersistBoundsAction()); } dialogMenu.add(new Separator("SystemMenuEnd")); //$NON-NLS-1$ } /** * Perform the requested tracker action (resize or move). * * @param style * The track style (resize or move). */ private void performTrackerAction(int style) { Shell shell = getShell(); if (shell is null || shell.isDisposed()) { return; } Tracker tracker = new Tracker(shell.getDisplay(), style); tracker.setStippled(true); Rectangle[] r = [ shell.getBounds() ]; tracker.setRectangles(r); // Ignore any deactivate events caused by opening the tracker. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=120656 bool oldListenToDeactivate = listenToDeactivate; listenToDeactivate = false; if (tracker.open()) { if (shell !is null && !shell.isDisposed()) { shell.setBounds(tracker.getRectangles()[0]); } } listenToDeactivate = oldListenToDeactivate; } /** * Show the dialog's menu. This message has no effect if the receiver was * not configured to show a menu. Clients may call this method in order to * trigger the menu via keystrokes or other gestures. Subclasses typically * do not override method. */ protected void showDialogMenu() { if (!showDialogMenu_) { return; } if (menuManager is null) { menuManager = new MenuManager(); fillDialogMenu(menuManager); } // Setting this flag works around a problem that remains on X only, // whereby activating the menu deactivates our shell. listenToDeactivate = !"gtk".equals(DWT.getPlatform()); //$NON-NLS-1$ Menu menu = menuManager.createContextMenu(getShell()); Rectangle bounds = toolBar.getBounds(); Point topLeft = new Point(bounds.x, bounds.y + bounds.height); topLeft = getShell().toDisplay(topLeft); menu.setLocation(topLeft.x, topLeft.y); menu.setVisible(true); } /** * Set the text to be shown in the popup's info area. This message has no * effect if there was no info text supplied when the dialog first opened. * Subclasses may override this method. * * @param text * the text to be shown when the info area is displayed. * */ protected void setInfoText(String text) { infoText = text; if (infoLabel !is null) { infoLabel.setText(text); } } /** * Set the text to be shown in the popup's title area. This message has no * effect if there was no title label specified when the dialog was * originally opened. Subclasses may override this method. * * @param text * the text to be shown when the title area is displayed. * */ protected void setTitleText(String text) { titleText = text; if (titleLabel !is null) { titleLabel.setText(text); } } /** * Return a bool indicating whether this dialog will persist its bounds. * This value is initially set in the dialog's constructor, but can be * modified if the persist bounds action is shown on the menu and the user * has changed its value. Subclasses may override this method. * * @return <true> if the dialogs bounds will be persisted, false if it will * not. */ protected bool getPersistBounds() { return persistBounds; } /** * Opens this window, creating it first if it has not yet been created. * <p> * This method is reimplemented for special configuration of PopupDialogs. * It never blocks on open, immediately returning <code>OK</code> if the * open is successful, or <code>CANCEL</code> if it is not. It provides * framework hooks that allow subclasses to set the focus and tab order, and * avoids the use of <code>shell.open()</code> in cases where the focus * should not be given to the shell initially. * * @return the return code * * @see dwtx.jface.window.Window#open() */ public override int open() { Shell shell = getShell(); if (shell is null || shell.isDisposed()) { shell = null; // create the window create(); shell = getShell(); } // provide a hook for adjusting the bounds. This is only // necessary when there is content driven sizing that must be // adjusted each time the dialog is opened. adjustBounds(); // limit the shell size to the display size constrainShellSize(); // set up the tab order for the dialog setTabOrder(cast(Composite) getContents()); // initialize flags for listening to deactivate listenToDeactivate = false; listenToParentDeactivate = false; // open the window if (takeFocusOnOpen) { shell.open(); getFocusControl().setFocus(); } else { shell.setVisible(true); } return OK; } /** * Closes this window, disposes its shell, and removes this window from its * window manager (if it has one). * <p> * This method is extended to save the dialog bounds and initialize widget * state so that the widgets can be recreated if the dialog is reopened. * This method may be extended (<code>super.close</code> must be called). * </p> * * @return <code>true</code> if the window is (or was already) closed, and * <code>false</code> if it is still open */ public override bool close() { // If already closed, there is nothing to do. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=127505 if (getShell() is null || getShell().isDisposed()) { return true; } saveDialogBounds(getShell()); // Widgets are about to be disposed, so null out any state // related to them that was not handled in dispose listeners. // We do this before disposal so that any received activate or // deactivate events are duly ignored. initializeWidgetState(); if (parentDeactivateListener !is null) { getShell().getParent().removeListener(DWT.Deactivate, parentDeactivateListener); parentDeactivateListener = null; } return super.close(); } /** * Gets the dialog settings that should be used for remembering the bounds * of the dialog. Subclasses should override this method when they wish to * persist the bounds of the dialog. * * @return settings the dialog settings used to store the dialog's location * and/or size, or <code>null</code> if the dialog's bounds should * never be stored. */ protected IDialogSettings getDialogSettings() { return null; } /** * Saves the bounds of the shell in the appropriate dialog settings. The * bounds are recorded relative to the parent shell, if there is one, or * display coordinates if there is no parent shell. Subclasses typically * need not override this method, but may extend it (calling * <code>super.saveDialogBounds</code> if additional bounds information * should be stored. Clients may also call this method to persist the bounds * at times other than closing the dialog. * * @param shell * The shell whose bounds are to be stored */ protected void saveDialogBounds(Shell shell) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { Point shellLocation = shell.getLocation(); Point shellSize = shell.getSize(); Shell parent = getParentShell(); if (parent !is null) { Point parentLocation = parent.getLocation(); shellLocation.x -= parentLocation.x; shellLocation.y -= parentLocation.y; } if (persistBounds) { String prefix = this.classinfo.name; settings.put(prefix ~ DIALOG_ORIGIN_X, shellLocation.x); settings.put(prefix ~ DIALOG_ORIGIN_Y, shellLocation.y); settings.put(prefix ~ DIALOG_WIDTH, shellSize.x); settings.put(prefix ~ DIALOG_HEIGHT, shellSize.y); } if (showPersistAction && showDialogMenu_) { settings.put( this.classinfo.name ~ DIALOG_USE_PERSISTED_BOUNDS, persistBounds); } } } /* * (non-Javadoc) * * @see dwtx.jface.window.Window#getInitialSize() */ protected override Point getInitialSize() { Point result = super.getInitialSize(); if (persistBounds) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { try { int width = settings.getInt(this.classinfo.name ~ DIALOG_WIDTH); int height = settings.getInt(this.classinfo.name ~ DIALOG_HEIGHT); result = new Point(width, height); } catch (NumberFormatException e) { } } } // No attempt is made to constrain the bounds. The default // constraining behavior in Window will be used. return result; } /** * Adjust the bounds of the popup as necessary prior to opening the dialog. * Default is to do nothing, which honors any bounds set directly by clients * or those that have been saved in the dialog settings. Subclasses should * override this method when there are bounds computations that must be * checked each time the dialog is opened. */ protected void adjustBounds() { } /** * (non-Javadoc) * * @see dwtx.jface.window.Window#getInitialLocation(dwt.graphics.Point) */ protected override Point getInitialLocation(Point initialSize) { Point result = super.getInitialLocation(initialSize); if (persistBounds) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { try { int x = settings.getInt(this.classinfo.name ~ DIALOG_ORIGIN_X); int y = settings.getInt(this.classinfo.name ~ DIALOG_ORIGIN_Y); result = new Point(x, y); // The coordinates were stored relative to the parent shell. // Convert to display coordinates. Shell parent = getParentShell(); if (parent !is null) { Point parentLocation = parent.getLocation(); result.x += parentLocation.x; result.y += parentLocation.y; } } catch (NumberFormatException e) { } } } // No attempt is made to constrain the bounds. The default // constraining behavior in Window will be used. return result; } /** * Apply any desired color to the specified composite and its children. * * @param composite * the contents composite */ private void applyColors(Composite composite) { applyForegroundColor(getShell().getDisplay().getSystemColor( DWT.COLOR_INFO_FOREGROUND), composite, getForegroundColorExclusions()); applyBackgroundColor(getShell().getDisplay().getSystemColor( DWT.COLOR_INFO_BACKGROUND), composite, getBackgroundColorExclusions()); } /** * Apply any desired fonts to the specified composite and its children. * * @param composite * the contents composite */ private void applyFonts(Composite composite) { Dialog.applyDialogFont(composite); } /** * Set the specified foreground color for the specified control and all of * its children, except for those specified in the list of exclusions. * * @param color * the color to use as the foreground color * @param control * the control whose color is to be changed * @param exclusions * a list of controls who are to be excluded from getting their * color assigned */ private void applyForegroundColor(Color color, Control control, SeqView!(Control) exclusions) { if (!exclusions.contains(control)) { control.setForeground(color); } if ( auto comp = cast(Composite)control ) { Control[] children = comp.getChildren(); for (int i = 0; i < children.length; i++) { applyForegroundColor(color, children[i], exclusions); } } } /** * Set the specified background color for the specified control and all of * its children. * * @param color * the color to use as the background color * @param control * the control whose color is to be changed * @param exclusions * a list of controls who are to be excluded from getting their * color assigned */ private void applyBackgroundColor(Color color, Control control, SeqView!(Control) exclusions) { if (!exclusions.contains(control)) { control.setBackground(color); } if (auto comp = cast(Composite)control ) { Control[] children = comp.getChildren(); for (int i = 0; i < children.length; i++) { applyBackgroundColor(color, children[i], exclusions); } } } /** * Set the specified foreground color for the specified control and all of * its children. Subclasses may override this method, but typically do not. * If a subclass wishes to exclude a particular control in its contents from * getting the specified foreground color, it may instead override * <code>PopupDialog.getForegroundColorExclusions</code>. * * @param color * the color to use as the background color * @param control * the control whose color is to be changed * @see PopupDialog#getBackgroundColorExclusions() */ protected void applyForegroundColor(Color color, Control control) { applyForegroundColor(color, control, getForegroundColorExclusions()); } /** * Set the specified background color for the specified control and all of * its children. Subclasses may override this method, but typically do not. * If a subclass wishes to exclude a particular control in its contents from * getting the specified background color, it may instead override * <code>PopupDialog.getBackgroundColorExclusions</code>. * * @param color * the color to use as the background color * @param control * the control whose color is to be changed * @see PopupDialog#getBackgroundColorExclusions() */ protected void applyBackgroundColor(Color color, Control control) { applyBackgroundColor(color, control, getBackgroundColorExclusions()); } /** * Return a list of controls which should never have their foreground color * reset. Subclasses may extend this method (should always call * <code>super.getForegroundColorExclusions</code> to aggregate the list. * * * @return the List of controls */ protected SeqView!(Control) getForegroundColorExclusions() { auto list = new ArraySeq!(Control); list.capacity(3); if (infoLabel !is null) { list.append(infoLabel); } if (titleSeparator !is null) { list.append(titleSeparator); } if (infoSeparator !is null) { list.append(infoSeparator); } return list; } /** * Return a list of controls which should never have their background color * reset. Subclasses may extend this method (should always call * <code>super.getBackgroundColorExclusions</code> to aggregate the list. * * @return the List of controls */ protected SeqView!(Control) getBackgroundColorExclusions() { auto list = new ArraySeq!(Control); list.capacity(2); if (titleSeparator !is null) { list.append(titleSeparator); } if (infoSeparator !is null) { list.append(infoSeparator); } return list; } /** * Initialize any state related to the widgetry that should be set up each * time widgets are created. */ private void initializeWidgetState() { menuManager = null; dialogArea = null; titleLabel = null; titleSeparator = null; infoSeparator = null; infoLabel = null; toolBar = null; // If the menu item for persisting bounds is displayed, use the stored // value to determine whether any persisted bounds should be honored at // all. if (showDialogMenu_ && showPersistAction) { IDialogSettings settings = getDialogSettings(); if (settings !is null) { persistBounds = settings.getBoolean(this.classinfo.name ~ DIALOG_USE_PERSISTED_BOUNDS); } } } /** * The dialog is being disposed. Dispose of any resources allocated. * */ private void handleDispose() { if (infoFont !is null && !infoFont.isDisposed()) { infoFont.dispose(); } infoFont = null; if (titleFont !is null && !titleFont.isDisposed()) { titleFont.dispose(); } titleFont = null; } }