/******************************************************************************* * Copyright (c) 2011 Google, Inc. * 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: * Google, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.wb.internal.core.utils.ui.dialogs; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.plugin.AbstractUIPlugin; /** * {@link Dialog} that remembers location/size between usage sessions. * * @author scheglov_ke * @coverage core.ui */ public abstract class ResizableDialog extends Dialog { /** * Key for accessing {@link Dialog} from its {@link Shell}. */ public static final String KEY_DIALOG = "KEY_DIALOG"; //////////////////////////////////////////////////////////////////////////// // // Internal constants // //////////////////////////////////////////////////////////////////////////// private static final String X = "x"; private static final String Y = "y"; private static final String WIDTH = "width"; private static final String HEIGHT = "height"; //////////////////////////////////////////////////////////////////////////// // // Instance fields // //////////////////////////////////////////////////////////////////////////// private final AbstractUIPlugin m_plugin; //////////////////////////////////////////////////////////////////////////// // // Constructor // //////////////////////////////////////////////////////////////////////////// public ResizableDialog(Shell parentShell, AbstractUIPlugin plugin) { super(parentShell); m_plugin = plugin; setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX); } //////////////////////////////////////////////////////////////////////////// // // Size // //////////////////////////////////////////////////////////////////////////// @Override protected Point getInitialSize() { // track the current dialog bounds installDialogBoundsTracker(); // answer the size from the previous incarnation Point defaultSize = getDefaultSize(); if ((getShellStyle() & SWT.RESIZE) != 0) { Rectangle oldBounds = loadBounds(); if (oldBounds != null) { Rectangle displayBounds = getShell().getDisplay().getBounds(); int width = Math.min(displayBounds.width, Math.max(oldBounds.width, defaultSize.x)); int height = Math.min(displayBounds.height, Math.max(oldBounds.height, defaultSize.y)); return new Point(width, height); } } // use default size return defaultSize; } /** * @return the default size of dialog. */ protected Point getDefaultSize() { return super.getInitialSize(); } //////////////////////////////////////////////////////////////////////////// // // Location // //////////////////////////////////////////////////////////////////////////// @Override protected Point getInitialLocation(Point initialSize) { Rectangle windowBounds; { Shell windowShell = m_plugin.getWorkbench().getActiveWorkbenchWindow().getShell(); windowBounds = windowShell.getBounds(); } // answer the location from the previous incarnation Rectangle bounds = loadBounds(); if (bounds != null) { int x = bounds.x; int y = bounds.y; int maxX = windowBounds.x + windowBounds.width - initialSize.x; int maxY = windowBounds.y + windowBounds.height - initialSize.y; if (x > maxX) { x = maxX; } if (y > maxY) { y = maxY; } if (x < windowBounds.x) { x = windowBounds.x; } if (y < windowBounds.y) { y = windowBounds.y; } return new Point(x, y); } // default location - centered on workbench window int x = windowBounds.x + (windowBounds.width - initialSize.x) / 2; int y = windowBounds.y + (windowBounds.height - initialSize.y) / 2; return new Point(x, y); } //////////////////////////////////////////////////////////////////////////// // // Bounds // //////////////////////////////////////////////////////////////////////////// /** * Loads bounds from {@link IDialogSettings}. */ private Rectangle loadBounds() { IDialogSettings settings = getDialogSettings(); try { return new Rectangle(settings.getInt(X), settings.getInt(Y), settings.getInt(WIDTH), settings.getInt(HEIGHT)); } catch (NumberFormatException e) { return null; } } /** * Saves bounds to {@link IDialogSettings}. */ private void saveBounds(Rectangle bounds) { IDialogSettings settings = getDialogSettings(); settings.put(X, bounds.x); settings.put(Y, bounds.y); settings.put(WIDTH, bounds.width); settings.put(HEIGHT, bounds.height); } /** * @return the {@link IDialogSettings} for this dialog with this type. */ protected IDialogSettings getDialogSettings() { IDialogSettings settings = m_plugin.getDialogSettings(); String sectionName = getDialogSettingsSectionName(); if (settings.getSection(sectionName) == null) { return settings.addNewSection(sectionName); } return settings.getSection(sectionName); } /** * @return the name of section for dialog specific bounds. By default uses name of {@link Class}, * but if same dialog is used for displaying different content, then may be overridden. */ protected String getDialogSettingsSectionName() { return getClass().getName(); } //////////////////////////////////////////////////////////////////////////// // // Size tracking // //////////////////////////////////////////////////////////////////////////// protected Rectangle cachedBounds; private void installDialogBoundsTracker() { getShell().addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { cachedBounds = getShell().getBounds(); } public void controlResized(ControlEvent e) { cachedBounds = getShell().getBounds(); } }); } @Override public boolean close() { boolean shellMaximized = getShell().getMaximized(); boolean closed = super.close(); if (closed && !shellMaximized && cachedBounds != null) { saveBounds(cachedBounds); } return closed; } //////////////////////////////////////////////////////////////////////////// // // Shell // //////////////////////////////////////////////////////////////////////////// @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setData(KEY_DIALOG, this); } }