Index: src/org/eclipse/jface/dialogs/PopupDialog.java =================================================================== RCS file: src/org/eclipse/jface/dialogs/PopupDialog.java diff -N src/org/eclipse/jface/dialogs/PopupDialog.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/jface/dialogs/PopupDialog.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,1085 @@ +/******************************************************************************* + * 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 + ******************************************************************************/ +package org.eclipse.jface.dialogs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +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.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +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.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.eclipse.swt.widgets.Tracker; + +/** + * 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. + *

+ * 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. + *

+ * 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. + * + * @experimental - This API is considered experimental. It is still evolving + * during 3.2 and is subject to change. It is being released to + * obtain feedback from early adopters. + * + * @since 3.2 + */ +public class PopupDialog extends Window { + + /** + * The dialog settings key name for stored dialog x location. + */ + private static final String DIALOG_ORIGIN_X = "DIALOG_X_ORIGIN"; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog y location. + */ + private static final String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog width. + */ + private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$ + + /** + * The dialog settings key name for stored dialog height. + */ + private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$ + + /** + * The dialog settings key name for remembering if the persisted bounds + * should be accessed. + */ + private static final String DIALOG_USE_PERSISTED_BOUNDS = "DIALOG_USE_PERSISTED_BOUNDS"; //$NON-NLS-1$ + + /** + * Move action for the dialog. + */ + private class MoveAction extends Action { + + MoveAction() { + super(JFaceResources.getString("PopupDialog.move"), //$NON-NLS-1$ + IAction.AS_PUSH_BUTTON); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.IAction#run() + */ + public void run() { + performTrackerAction(SWT.NONE); + } + + } + + /** + * Resize action for the dialog. + */ + private class ResizeAction extends Action { + + ResizeAction() { + super(JFaceResources.getString("PopupDialog.resize"), //$NON-NLS-1$ + IAction.AS_PUSH_BUTTON); + } + + /* + * @see org.eclipse.jface.action.Action#run() + */ + public void run() { + performTrackerAction(SWT.RESIZE); + } + } + + /** + * + * Remember bounds action for the dialog. + */ + private class PersistBoundsAction extends Action { + + PersistBoundsAction() { + super(JFaceResources.getString("PopupDialog.persistBounds"), //$NON-NLS-1$ + IAction.AS_CHECK_BOX); + setChecked(persistBounds); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.IAction#run() + */ + public void run() { + persistBounds = isChecked(); + } + } + + /** + * Shell style appropriate for a simple hover popup that cannot get focus. + */ + public final static int HOVER_SHELLSTYLE = SWT.NO_FOCUS | SWT.ON_TOP + | SWT.NO_TRIM; + + /** + * Shell style appropriate for an info popup that can get focus. + */ + public final static int INFOPOPUP_SHELLSTYLE = SWT.NO_TRIM | SWT.ON_TOP; + + /** + * Shell style appropriate for a resizable info popup that can get focus. + */ + public final static int INFOPOPUPRESIZE_SHELLSTYLE = SWT.RESIZE; + + /** + * Border thickness in pixels. + */ + private static final 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; + + /** + * 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; + + /** + * 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 boolean listenToDeactivate; + + private boolean listenToParentDeactivate; + + /** + * Flag indicating whether focus should be taken when the dialog is opened. + */ + private boolean takeFocusOnOpen = false; + + /** + * Flag specifying whether a menu should be shown that allows the user to + * move and resize. + */ + private boolean 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 boolean 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 boolean 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 PopupDialog. + * + * @param parent + * The parent shell. + * @param shellStyle + * The shell style. + * @param takeFocusOnOpen + * A boolean indicating whether focus should be taken by this + * popup when it opens. + * @param persistBounds + * A boolean 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 boolean indicating whether a menu for moving and resizing + * the popup should be provided. + * @param showPersistAction + * A boolean 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 + * showDialogMenu is false. + * @param titleText + * Text to be shown in an upper title area, or null + * if there is no title. + * @param infoText + * Text to be shown in a lower info area, or null + * if there is no info area. + * + * @see PopupDialog#getDialogSettings() + */ + public PopupDialog(Shell parent, int shellStyle, boolean takeFocusOnOpen, + boolean persistBounds, boolean showDialogMenu, + boolean 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 org.eclipse.jface.window.Window#configureShell(Shell) + */ + protected void configureShell(Shell shell) { + GridLayout layout; + GridData gd; + Display display = shell.getDisplay(); + shell.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); + + layout = new GridLayout(1, false); + int border = ((getShellStyle() & SWT.NO_TRIM) == 0) ? 0 + : BORDER_THICKNESS; + layout.marginHeight = border; + layout.marginWidth = border; + shell.setLayout(layout); + gd = new GridData(GridData.FILL_BOTH); + shell.setLayoutData(gd); + + shell.addListener(SWT.Deactivate, new Listener() { + public void handleEvent(Event event) { + if (listenToDeactivate) { + close(); + } + } + }); + // Set this true whenever we activate. It may have been turned + // off by a menu or secondary popup showing. + shell.addListener(SWT.Activate, new Listener() { + public void handleEvent(Event event) { + listenToDeactivate = true; + } + }); + + if ((getShellStyle() & SWT.ON_TOP) != 0 && shell.getParent() != null) { + shell.getParent().addListener(SWT.Deactivate, new Listener() { + public void handleEvent(Event event) { + if (listenToParentDeactivate) { + close(); + } + } + }); + } + } + + /** + * The PopupDialog implementation of this Window + * method creates and lays out the top level composite for the dialog. It + * then calls the createTitleMenuArea, + * createDialogArea, and createInfoTextArea + * 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 createDialogArea and (optionally) + * createTitleMenuArea and createTitleMenuArea + * are recommended rather than overriding this method. + * + * @param parent + * the composite used to parent the contents. + * + * @return the control representing the contents. + */ + protected Control createContents(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + layout.verticalSpacing = 1; + composite.setLayout(layout); + GridData gd = new GridData(GridData.FILL_BOTH); + composite.setLayoutData(gd); + + // Title area + if (hasTitleArea()) { + createTitleMenuArea(composite); + createHorizontalSeparator(composite); + } + // Content + dialogArea = createDialogArea(composite); + + // Info field + if (hasInfoArea()) { + 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. + *

+ * The PopupDialog implementation of this framework method + * creates and returns a new Composite with standard margins + * and spacing. + *

+ * The returned control's layout data must be an instance of + * GridData. This method must not modify the parent's + * layout. + *

+ * Subclasses must override this method but may call super as + * in the following example: + * + *

+	 * Composite composite = (Composite) super.createDialogArea(parent);
+	 * //add controls to composite as necessary
+	 * return composite;
+	 * 
+ * + * @param parent + * the parent composite to contain the dialog area + * @return the dialog area control + */ + protected Control createDialogArea(Composite parent) { + // by default, create an empty composite. + Composite composite = new Composite(parent, SWT.NONE); + 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 boolean 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 true if a title area should be created, + * false if it should not. + */ + protected boolean hasTitleArea() { + return titleText != null || showDialogMenu; + } + + /** + * Returns a boolean 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 true if a title area should be created, + * false if it should not. + */ + protected boolean hasInfoArea() { + return infoText != null; + } + + /** + * Creates the title and menu area. Subclasses typically need not override + * this method, but instead should use the constructor parameters + * showDialogMenu and showPersistAction to + * indicate whether a menu should be shown, and + * createTitleControl to to customize the presentation of the + * title. + * + * @param parent + * The parent composite. + * @return The Control representing the title and menu area. + */ + protected Control createTitleMenuArea(Composite parent) { + + Composite titleAreaComposite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + titleAreaComposite.setLayout(layout); + titleAreaComposite + .setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + 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. + * + * @param parent + * The parent composite. + * @return The Control representing the title area. + */ + protected Control createTitleControl(Composite parent) { + titleLabel = new Label(parent, SWT.NONE); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + if (!showDialogMenu) + gd.horizontalSpan = 2; + titleLabel.setLayoutData(gd); + titleLabel.setFont(JFaceResources.getBannerFont()); + + if (titleText != null) { + titleLabel.setText(titleText); + } + return titleLabel; + } + + /** + * Creates the optional info text area. This method is only called if the + * hasInfoArea() method returns true. Subclasses typically + * need not override this method, but may do so. If a different type of + * title control is desired, subclasses may instead override + * createTitleControl. + * + * @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, SWT.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); + GridData gd = new GridData(GridData.FILL_HORIZONTAL + | GridData.HORIZONTAL_ALIGN_BEGINNING + | GridData.VERTICAL_ALIGN_BEGINNING); + infoLabel.setLayoutData(gd); + infoLabel.setForeground(parent.getDisplay().getSystemColor( + SWT.COLOR_WIDGET_DARK_SHADOW)); + + getShell().addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent event) { + if (infoFont != null && !infoFont.isDisposed()) + infoFont.dispose(); + infoFont = null; + } + }); + 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, SWT.SEPARATOR | SWT.HORIZONTAL + | SWT.LINE_DOT); + separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + 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, SWT.FLAT); + ToolItem viewMenuButton = new ToolItem(toolBar, SWT.PUSH, 0); + + toolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END)); + + menuImage = ImageDescriptor.createFromFile(PopupDialog.class, + "images/popup_menu.gif").createImage();//$NON-NLS-1$ + disabledMenuImage = ImageDescriptor.createFromFile(PopupDialog.class, + "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 SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + showDialogMenu(); + } + }); + viewMenuButton.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + menuImage.dispose(); + menuImage = null; + disabledMenuImage.dispose(); + disabledMenuImage = null; + } + }); + } + + /** + * 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 == null || shell.isDisposed()) + return; + + Tracker tracker = new Tracker(shell.getDisplay(), style); + tracker.setStippled(true); + Rectangle[] r = new Rectangle[] { shell.getBounds() }; + tracker.setRectangles(r); + + if (tracker.open()) { + shell.setBounds(tracker.getRectangles()[0]); + + } + } + + /** + * 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 == null) { + menuManager = new MenuManager(); + fillDialogMenu(menuManager); + } + + // Setting this flag prevents us from closing on the deactivate we + // receive when a menu item is selected + listenToDeactivate = false; + + 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 != 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 != null) + titleLabel.setText(text); + } + + /** + * Return a boolean 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 if the dialogs bounds will be persisted, false if it will + * not. + */ + protected boolean getPersistBounds() { + return persistBounds; + } + + /** + * Opens this window, creating it first if it has not yet been created. + *

+ * This method is reimplemented for special configuration of PopupDialogs. + * It never blocks on open, immediately returning OK if the + * open is successful, or CANCEL if it is not. It provides + * framework hooks that allow subclasses to set the focus and tab order, and + * avoids the use of shell.open() in cases where the focus + * should not be given to the shell initially. + * + * @return the return code + * + * @see org.eclipse.jface.window.Window#open() + */ + public int open() { + + Shell shell = getShell(); + if (shell == 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((Composite) getContents()); + + // open the window + if (takeFocusOnOpen) { + shell.open(); + getFocusControl().setFocus(); + } else { + shell.setVisible(true); + } + + // Ensure we listen to deactivate callbacks. Set this after we + // make the shell active, ensuring we've already received the parent + // shell's initial deactivate event. + listenToDeactivate = true; + listenToParentDeactivate = true; + + return OK; + + } + + /** + * Closes this window, disposes its shell, and removes this window from its + * window manager (if it has one). + *

+ * 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 (super.close must be called). + *

+ * + * @return true if the window is (or was already) closed, and + * false if it is still open + */ + public boolean close() { + saveDialogBounds(getShell()); + boolean returnValue = super.close(); + + // Widgets have been disposed, so null out any state related to them + // that was not handled in dispose listeners. + initializeWidgetState(); + + return returnValue; + } + + /** + * 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 null 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 + * super.saveDialogBounds 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 != null) { + Point shellLocation = shell.getLocation(); + Point shellSize = shell.getSize(); + Shell parent = getParentShell(); + if (parent != null) { + Point parentLocation = parent.getLocation(); + shellLocation.x -= parentLocation.x; + shellLocation.y -= parentLocation.y; + } + if (persistBounds) { + String prefix = getClass().getName(); + 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( + getClass().getName() + DIALOG_USE_PERSISTED_BOUNDS, + persistBounds); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.window.Window#getInitialSize() + */ + protected Point getInitialSize() { + Point result = super.getInitialSize(); + if (persistBounds) { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + try { + int width = settings.getInt(getClass().getName() + + DIALOG_WIDTH); + int height = settings.getInt(getClass().getName() + + 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 org.eclipse.jface.window.Window#getInitialLocation(org.eclipse.swt.graphics.Point) + */ + protected Point getInitialLocation(Point initialSize) { + Point result = super.getInitialLocation(initialSize); + if (persistBounds) { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + try { + int x = settings.getInt(getClass().getName() + + DIALOG_ORIGIN_X); + int y = settings.getInt(getClass().getName() + + 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 != 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( + SWT.COLOR_INFO_FOREGROUND), composite, + getForegroundColorExclusions()); + applyBackgroundColor(getShell().getDisplay().getSystemColor( + SWT.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, + List exclusions) { + if (!exclusions.contains(control)) { + control.setForeground(color); + } + if (control instanceof Composite) { + Control[] children = ((Composite) control).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, + List exclusions) { + if (!exclusions.contains(control)) { + control.setBackground(color); + } + if (control instanceof Composite) { + Control[] children = ((Composite) control).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 + * PopupDialog.getForegroundColorExclusions. + * + * @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 + * PopupDialog.getBackgroundColorExclusions. + * + * @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 + * super.getForegroundColorExclusions to aggregate the list. + * + * + * @return the List of controls + */ + protected List getForegroundColorExclusions() { + List list = new ArrayList(1); + list.add(infoLabel); + return list; + } + + /** + * Return a list of controls which should never have their background color + * reset. Subclasses may extend this method (should always call + * super.getBackgroundColorExclusions to aggregate the list. + * + * @return the List of controls + */ + protected List getBackgroundColorExclusions() { + return new ArrayList(); + } + + /** + * Initialize any state related to the widgetry that should be set up each + * time widgets are created. + */ + private void initializeWidgetState() { + menuManager = null; + listenToDeactivate = true; + listenToParentDeactivate = false; + dialogArea = null; + titleLabel = 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 != null) { + persistBounds = settings.getBoolean(getClass().getName() + + DIALOG_USE_PERSISTED_BOUNDS); + } + } + + } +}