Home | History | Annotate | Download | only in dialogs
      1 /*******************************************************************************
      2  * Copyright (c) 2011 Google, Inc.
      3  * All rights reserved. This program and the accompanying materials
      4  * are made available under the terms of the Eclipse Public License v1.0
      5  * which accompanies this distribution, and is available at
      6  * http://www.eclipse.org/legal/epl-v10.html
      7  *
      8  * Contributors:
      9  *    Google, Inc. - initial API and implementation
     10  *******************************************************************************/
     11 package org.eclipse.wb.internal.core.utils.ui.dialogs;
     12 
     13 import org.eclipse.jface.dialogs.Dialog;
     14 import org.eclipse.jface.dialogs.IDialogSettings;
     15 import org.eclipse.swt.SWT;
     16 import org.eclipse.swt.events.ControlEvent;
     17 import org.eclipse.swt.events.ControlListener;
     18 import org.eclipse.swt.graphics.Point;
     19 import org.eclipse.swt.graphics.Rectangle;
     20 import org.eclipse.swt.widgets.Shell;
     21 import org.eclipse.ui.plugin.AbstractUIPlugin;
     22 
     23 /**
     24  * {@link Dialog} that remembers location/size between usage sessions.
     25  *
     26  * @author scheglov_ke
     27  * @coverage core.ui
     28  */
     29 public abstract class ResizableDialog extends Dialog {
     30   /**
     31    * Key for accessing {@link Dialog} from its {@link Shell}.
     32    */
     33   public static final String KEY_DIALOG = "KEY_DIALOG";
     34   ////////////////////////////////////////////////////////////////////////////
     35   //
     36   // Internal constants
     37   //
     38   ////////////////////////////////////////////////////////////////////////////
     39   private static final String X = "x";
     40   private static final String Y = "y";
     41   private static final String WIDTH = "width";
     42   private static final String HEIGHT = "height";
     43   ////////////////////////////////////////////////////////////////////////////
     44   //
     45   // Instance fields
     46   //
     47   ////////////////////////////////////////////////////////////////////////////
     48   private final AbstractUIPlugin m_plugin;
     49 
     50   ////////////////////////////////////////////////////////////////////////////
     51   //
     52   // Constructor
     53   //
     54   ////////////////////////////////////////////////////////////////////////////
     55   public ResizableDialog(Shell parentShell, AbstractUIPlugin plugin) {
     56     super(parentShell);
     57     m_plugin = plugin;
     58     setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
     59   }
     60 
     61   ////////////////////////////////////////////////////////////////////////////
     62   //
     63   // Size
     64   //
     65   ////////////////////////////////////////////////////////////////////////////
     66   @Override
     67   protected Point getInitialSize() {
     68     // track the current dialog bounds
     69     installDialogBoundsTracker();
     70     // answer the size from the previous incarnation
     71     Point defaultSize = getDefaultSize();
     72     if ((getShellStyle() & SWT.RESIZE) != 0) {
     73       Rectangle oldBounds = loadBounds();
     74       if (oldBounds != null) {
     75         Rectangle displayBounds = getShell().getDisplay().getBounds();
     76         int width = Math.min(displayBounds.width, Math.max(oldBounds.width, defaultSize.x));
     77         int height = Math.min(displayBounds.height, Math.max(oldBounds.height, defaultSize.y));
     78         return new Point(width, height);
     79       }
     80     }
     81     // use default size
     82     return defaultSize;
     83   }
     84 
     85   /**
     86    * @return the default size of dialog.
     87    */
     88   protected Point getDefaultSize() {
     89     return super.getInitialSize();
     90   }
     91 
     92   ////////////////////////////////////////////////////////////////////////////
     93   //
     94   // Location
     95   //
     96   ////////////////////////////////////////////////////////////////////////////
     97   @Override
     98   protected Point getInitialLocation(Point initialSize) {
     99     Rectangle windowBounds;
    100     {
    101       Shell windowShell = m_plugin.getWorkbench().getActiveWorkbenchWindow().getShell();
    102       windowBounds = windowShell.getBounds();
    103     }
    104     // answer the location from the previous incarnation
    105     Rectangle bounds = loadBounds();
    106     if (bounds != null) {
    107       int x = bounds.x;
    108       int y = bounds.y;
    109       int maxX = windowBounds.x + windowBounds.width - initialSize.x;
    110       int maxY = windowBounds.y + windowBounds.height - initialSize.y;
    111       if (x > maxX) {
    112         x = maxX;
    113       }
    114       if (y > maxY) {
    115         y = maxY;
    116       }
    117       if (x < windowBounds.x) {
    118         x = windowBounds.x;
    119       }
    120       if (y < windowBounds.y) {
    121         y = windowBounds.y;
    122       }
    123       return new Point(x, y);
    124     }
    125     // default location - centered on workbench window
    126     int x = windowBounds.x + (windowBounds.width - initialSize.x) / 2;
    127     int y = windowBounds.y + (windowBounds.height - initialSize.y) / 2;
    128     return new Point(x, y);
    129   }
    130 
    131   ////////////////////////////////////////////////////////////////////////////
    132   //
    133   // Bounds
    134   //
    135   ////////////////////////////////////////////////////////////////////////////
    136   /**
    137    * Loads bounds from {@link IDialogSettings}.
    138    */
    139   private Rectangle loadBounds() {
    140     IDialogSettings settings = getDialogSettings();
    141     try {
    142       return new Rectangle(settings.getInt(X),
    143           settings.getInt(Y),
    144           settings.getInt(WIDTH),
    145           settings.getInt(HEIGHT));
    146     } catch (NumberFormatException e) {
    147       return null;
    148     }
    149   }
    150 
    151   /**
    152    * Saves bounds to {@link IDialogSettings}.
    153    */
    154   private void saveBounds(Rectangle bounds) {
    155     IDialogSettings settings = getDialogSettings();
    156     settings.put(X, bounds.x);
    157     settings.put(Y, bounds.y);
    158     settings.put(WIDTH, bounds.width);
    159     settings.put(HEIGHT, bounds.height);
    160   }
    161 
    162   /**
    163    * @return the {@link IDialogSettings} for this dialog with this type.
    164    */
    165   protected IDialogSettings getDialogSettings() {
    166     IDialogSettings settings = m_plugin.getDialogSettings();
    167     String sectionName = getDialogSettingsSectionName();
    168     if (settings.getSection(sectionName) == null) {
    169       return settings.addNewSection(sectionName);
    170     }
    171     return settings.getSection(sectionName);
    172   }
    173 
    174   /**
    175    * @return the name of section for dialog specific bounds. By default uses name of {@link Class},
    176    *         but if same dialog is used for displaying different content, then may be overridden.
    177    */
    178   protected String getDialogSettingsSectionName() {
    179     return getClass().getName();
    180   }
    181 
    182   ////////////////////////////////////////////////////////////////////////////
    183   //
    184   // Size tracking
    185   //
    186   ////////////////////////////////////////////////////////////////////////////
    187   protected Rectangle cachedBounds;
    188 
    189   private void installDialogBoundsTracker() {
    190     getShell().addControlListener(new ControlListener() {
    191       public void controlMoved(ControlEvent e) {
    192         cachedBounds = getShell().getBounds();
    193       }
    194 
    195       public void controlResized(ControlEvent e) {
    196         cachedBounds = getShell().getBounds();
    197       }
    198     });
    199   }
    200 
    201   @Override
    202   public boolean close() {
    203     boolean shellMaximized = getShell().getMaximized();
    204     boolean closed = super.close();
    205     if (closed && !shellMaximized && cachedBounds != null) {
    206       saveBounds(cachedBounds);
    207     }
    208     return closed;
    209   }
    210 
    211   ////////////////////////////////////////////////////////////////////////////
    212   //
    213   // Shell
    214   //
    215   ////////////////////////////////////////////////////////////////////////////
    216   @Override
    217   protected void configureShell(Shell newShell) {
    218     super.configureShell(newShell);
    219     newShell.setData(KEY_DIALOG, this);
    220   }
    221 }
    222