Java tutorial
/* uDig - User Friendly Desktop Internet GIS client * http://udig.refractions.net * (C) 2004, Refractions Research Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package net.refractions.udig.ui; import net.refractions.udig.internal.ui.UiPlugin; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; 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.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; /** * A dialog that, on opening, will zoom from the start location/size the location of the provided dialog. * <p> * IMPORTANT: Since there is no way for ZoomingDialog to determine whether setBlockOnOpen is * set on the wrapped/decorated Dialog setBlockOnOpen <em>MUST</em> be set on ZoomingDialog * </p> * @author Jesse * @since 1.1.0 */ public class ZoomingDialog extends Dialog { public static final int FAST = 1; public static final int MEDIUM = 4; public static final int SLOW = 8; private static final int BASE_NUMBER_STEPS = 15; private final Dialog delegate; private final Point size; private final Point location; private Rectangle end; private int zoomSpeed = FAST; private boolean shouldBlock; /** * Creates a new instance. * @param parentShell shell to use as a parent * @param delegate The dialog to open * @param start the rectangle, in Display coordinates, to zoom from when opening. */ public ZoomingDialog(Shell parentShell, Dialog delegate, Rectangle start) { super(new ZoomShellProvider(parentShell)); this.delegate = delegate; this.location = new Point(start.x, start.y); this.size = new Point(start.width, start.height); setShellStyle(SWT.ON_TOP | SWT.NO_FOCUS | SWT.NO_TRIM | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE); } /** * Create new instance. Will zoom from the provided rectangle to the dialog location. * * @param parentShell shell to use as a parent * @param dialog dialog to open * @param x * @param y * @param width * @param height */ public ZoomingDialog(Shell parentShell, Dialog dialog, int x, int y, int width, int height) { this(parentShell, dialog, new Rectangle(x, y, width, height)); } /** * Sets how long it takes for the Dialog to open, default is {@link #FAST}. Is one of * * {@link #FAST} * {@link #MEDIUM} * {@link #SLOW} * * @param speed a constant indicating the speed at which the dialog zooms */ public void setZoomSpeed(int speed) { this.zoomSpeed = speed; } @Override public void setBlockOnOpen(boolean shouldBlock) { this.shouldBlock = shouldBlock; } public boolean close() { boolean result = delegate.close(); return result; } private void closeInternal() { super.getShell().setVisible(true); delegate.getShell().setVisible(false); zoom(false); super.close(); } public void create() { super.create(); if (delegate.getShell() == null) delegate.create(); } public int getReturnCode() { return delegate.getReturnCode(); } @Override protected Point getInitialLocation(Point initialSize) { return location; } @Override protected Point getInitialSize() { return size; } /** * Opens the dialog. * * <p> * IMPORTANT: Since there is no way for ZoomingDialog to determine whether setBlockOnOpen is * set on the wrapped/decorated Dialog setBlockOnOpen <em>MUST</em> be set on ZoomingDialog * </p> * */ public int open() { if (delegate.getShell() == null) delegate.create(); end = delegate.getShell().getBounds(); // end=new Rectangle(300, 300, 800,600); super.setBlockOnOpen(false); super.open(); zoom(true); // Must add listeners after delegate is open. // Therefore blocking must be false on the delegate so that // listeners can be added. delegate.setBlockOnOpen(false); int open = delegate.open(); addClosingListeners(); if (shouldBlock) runEventLoop(getShell()); return open; } private void runEventLoop(Shell loopShell) { //Use the display provided by the shell if possible Display display; if (getShell() == null) { display = Display.getCurrent(); } else { display = loopShell.getDisplay(); } while (loopShell != null && !loopShell.isDisposed()) { try { if (!display.readAndDispatch()) { display.sleep(); } } catch (Throwable e) { UiPlugin.log("Exception in UI thread while waiting", e); //$NON-NLS-1$ } } display.update(); } private void addClosingListeners() { delegate.getShell().addListener(SWT.Close | SWT.Dispose, new Listener() { public void handleEvent(Event event) { closeInternal(); } }); delegate.getShell().addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { closeInternal(); } }); } private void zoom(boolean grow) { Point location = this.location; Point size = this.size; int totalSteps = BASE_NUMBER_STEPS * zoomSpeed; int xstep = (end.x - location.x) / totalSteps; int ystep = (end.y - location.y) / totalSteps; int xsize = (end.width - size.x) / totalSteps; int ysize = (end.height - size.y) / totalSteps; if (grow) { int steps = 0; while (steps < totalSteps) { int nextX = location.x + steps * xstep; int nextY = location.y + steps * ystep; int nextWidth = size.x + steps * xsize; int nextHeight = size.y + steps * ysize; super.getShell().setBounds(new Rectangle(nextX, nextY, nextWidth, nextHeight)); steps++; } } else { int steps = totalSteps; while (steps > -1) { int nextX = location.x + steps * xstep; int nextY = location.y + steps * ystep; int nextWidth = size.x + steps * xsize; int nextHeight = size.y + steps * ysize; super.getShell().setBounds(new Rectangle(nextX, nextY, nextWidth, nextHeight)); steps--; } } super.getShell().setVisible(false); } public String toString() { return delegate.toString(); } @Override protected Control createButtonBar(Composite parent) { return new Composite(parent, SWT.NONE); } /** * Create a message dialog. Notethat the dialog will have no visual * representation (no widgets) until it is told to open. * <p> * The labels of the buttons to appear in the button bar are supplied in * this constructor as an array. The <code>open</code> method will return * the index of the label in this array corresponding to the button that was * pressed to close the dialog. If the dialog was dismissed without pressing * a button (ESC, etc.) then -1 is returned. Note that the <code>open</code> * method blocks. * </p> * * @param start * the location to zoom from. * @param parentShell * the parent shell * @param dialogTitle * the dialog title, or <code>null</code> if none * @param dialogTitleImage * the dialog title image, or <code>null</code> if none * @param dialogMessage * the dialog message * @param dialogImageType * one of the following values: * <ul> * <li><code>MessageDialog.NONE</code> for a dialog with no * image</li> * <li><code>MessageDialog.ERROR</code> for a dialog with an * error image</li> * <li><code>MessageDialog.INFORMATION</code> for a dialog * with an information image</li> * <li><code>MessageDialog.QUESTION </code> for a dialog with a * question image</li> * <li><code>MessageDialog.WARNING</code> for a dialog with a * warning image</li> * </ul> * @param dialogButtonLabels * an array of labels for the buttons in the button bar * @param defaultIndex * the index in the button label array of the default button * @return */ public static int openMessageDialog(Rectangle start, Shell parentShell, String dialogTitle, Image dialogImage, String dialogMessage, int dialogImageType, String[] buttonLabels, int defaultIndex) { MessageDialog dialog = new MessageDialog(parentShell, dialogTitle, dialogImage, dialogMessage, dialogImageType, buttonLabels, defaultIndex); ZoomingDialog zd = new ZoomingDialog(parentShell, dialog, start); zd.open(); return zd.getReturnCode(); } public static void openErrorMessage(Rectangle start, Shell parentShell, String dialogTitle, String dialogMessage) { openMessageDialog(start, parentShell, dialogTitle, null, dialogMessage, MessageDialog.ERROR, new String[] { IDialogConstants.OK_LABEL }, 1); } public static void openWarningMessage(Rectangle start, Shell parentShell, String dialogTitle, String dialogMessage) { openMessageDialog(start, parentShell, dialogTitle, null, dialogMessage, MessageDialog.WARNING, new String[] { IDialogConstants.OK_LABEL }, 1); } public static void openInformationMessage(Rectangle start, Shell parentShell, String dialogTitle, String dialogMessage) { openMessageDialog(start, parentShell, dialogTitle, null, dialogMessage, MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 1); } public static boolean openQuestionMessage(Rectangle start, Shell parentShell, String dialogTitle, String dialogMessage) { int result = openMessageDialog(start, parentShell, dialogTitle, null, dialogMessage, MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1); return result == IDialogConstants.YES_ID; } /** * Calculates the bounds of the Control in Display coordinates (Required by ZoomingDialog constructor). * * @param control control to use as the starting position * @return the bounds of the Control in Display coordinates */ public static Rectangle calculateBounds(Control control) { Point ul = control.toDisplay(0, 0); Point size2 = control.getSize(); Rectangle start = new Rectangle(ul.x, ul.y, size2.x, size2.y); return start; } /** * Calculates the bounds of the Control in Display coordinates (Required by ZoomingDialog constructor). * * @param item TreeItem to use as the starting position * @param columnIndex the index of the column to find the bounds for. If -1 bounds of entire item are found * @return the bounds of the Control in Display coordinates */ public static Rectangle calculateBounds(TreeItem item, int columnIndex) { Point ulTree = item.getParent().toDisplay(0, 0); Rectangle bounds; if (columnIndex > -1) { bounds = item.getBounds(columnIndex); bounds.x += ulTree.x; bounds.y += ulTree.y; } else { Rectangle bounds2 = item.getBounds(0); bounds = new Rectangle(ulTree.x, ulTree.y, 0, 0); bounds.width = item.getParent().getSize().x; bounds.height = bounds2.height; } return bounds; } private static class ZoomShellProvider implements IShellProvider { private Shell template; public ZoomShellProvider(Shell shell) { this.template = shell; } public Shell getShell() { Shell shell; if (template == null) shell = new Shell(); else shell = new Shell(template.getDisplay()); return shell; } } }