0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Chris Gross (schtoo@schtoo.com) - patch for bug 16179
0011: *******************************************************************************/package org.eclipse.jface.wizard;
0012:
0013: import java.lang.reflect.InvocationTargetException;
0014: import java.util.ArrayList;
0015: import java.util.HashMap;
0016: import java.util.Map;
0017:
0018: import org.eclipse.core.runtime.Assert;
0019: import org.eclipse.core.runtime.IProgressMonitor;
0020: import org.eclipse.core.runtime.IStatus;
0021: import org.eclipse.core.runtime.ListenerList;
0022: import org.eclipse.jface.dialogs.ControlEnableState;
0023: import org.eclipse.jface.dialogs.IDialogConstants;
0024: import org.eclipse.jface.dialogs.IMessageProvider;
0025: import org.eclipse.jface.dialogs.IPageChangeProvider;
0026: import org.eclipse.jface.dialogs.IPageChangedListener;
0027: import org.eclipse.jface.dialogs.IPageChangingListener;
0028: import org.eclipse.jface.dialogs.MessageDialog;
0029: import org.eclipse.jface.dialogs.PageChangedEvent;
0030: import org.eclipse.jface.dialogs.PageChangingEvent;
0031: import org.eclipse.jface.dialogs.TitleAreaDialog;
0032: import org.eclipse.jface.operation.IRunnableWithProgress;
0033: import org.eclipse.jface.operation.ModalContext;
0034: import org.eclipse.jface.resource.JFaceResources;
0035: import org.eclipse.jface.util.SafeRunnable;
0036: import org.eclipse.swt.SWT;
0037: import org.eclipse.swt.custom.BusyIndicator;
0038: import org.eclipse.swt.events.HelpEvent;
0039: import org.eclipse.swt.events.HelpListener;
0040: import org.eclipse.swt.events.SelectionAdapter;
0041: import org.eclipse.swt.events.SelectionEvent;
0042: import org.eclipse.swt.graphics.Cursor;
0043: import org.eclipse.swt.graphics.Point;
0044: import org.eclipse.swt.graphics.Rectangle;
0045: import org.eclipse.swt.layout.GridData;
0046: import org.eclipse.swt.layout.GridLayout;
0047: import org.eclipse.swt.widgets.Button;
0048: import org.eclipse.swt.widgets.Composite;
0049: import org.eclipse.swt.widgets.Control;
0050: import org.eclipse.swt.widgets.Display;
0051: import org.eclipse.swt.widgets.Label;
0052: import org.eclipse.swt.widgets.Layout;
0053: import org.eclipse.swt.widgets.Shell;
0054:
0055: /**
0056: * A dialog to show a wizard to the end user.
0057: * <p>
0058: * In typical usage, the client instantiates this class with a particular
0059: * wizard. The dialog serves as the wizard container and orchestrates the
0060: * presentation of its pages.
0061: * <p>
0062: * The standard layout is roughly as follows: it has an area at the top
0063: * containing both the wizard's title, description, and image; the actual wizard
0064: * page appears in the middle; below that is a progress indicator (which is made
0065: * visible if needed); and at the bottom of the page is message line and a
0066: * button bar containing Help, Next, Back, Finish, and Cancel buttons (or some
0067: * subset).
0068: * </p>
0069: * <p>
0070: * Clients may subclass <code>WizardDialog</code>, although this is rarely
0071: * required.
0072: * </p>
0073: */
0074: public class WizardDialog extends TitleAreaDialog implements
0075: IWizardContainer2, IPageChangeProvider {
0076: /**
0077: * Image registry key for error message image (value
0078: * <code>"dialog_title_error_image"</code>).
0079: */
0080: public static final String WIZ_IMG_ERROR = "dialog_title_error_image"; //$NON-NLS-1$
0081:
0082: // The wizard the dialog is currently showing.
0083: private IWizard wizard;
0084:
0085: // Wizards to dispose
0086: private ArrayList createdWizards = new ArrayList();
0087:
0088: // Current nested wizards
0089: private ArrayList nestedWizards = new ArrayList();
0090:
0091: // The currently displayed page.
0092: private IWizardPage currentPage = null;
0093:
0094: // The number of long running operation executed from the dialog.
0095: private long activeRunningOperations = 0;
0096:
0097: // The current page message and description
0098: private String pageMessage;
0099:
0100: private int pageMessageType = IMessageProvider.NONE;
0101:
0102: private String pageDescription;
0103:
0104: // The progress monitor
0105: private ProgressMonitorPart progressMonitorPart;
0106:
0107: private Cursor waitCursor;
0108:
0109: private Cursor arrowCursor;
0110:
0111: private MessageDialog windowClosingDialog;
0112:
0113: // Navigation buttons
0114: private Button backButton;
0115:
0116: private Button nextButton;
0117:
0118: private Button finishButton;
0119:
0120: private Button cancelButton;
0121:
0122: private Button helpButton;
0123:
0124: private SelectionAdapter cancelListener;
0125:
0126: private boolean isMovingToPreviousPage = false;
0127:
0128: private Composite pageContainer;
0129:
0130: private PageContainerFillLayout pageContainerLayout = new PageContainerFillLayout(
0131: 5, 5, 300, 225);
0132:
0133: private int pageWidth = SWT.DEFAULT;
0134:
0135: private int pageHeight = SWT.DEFAULT;
0136:
0137: private static final String FOCUS_CONTROL = "focusControl"; //$NON-NLS-1$
0138:
0139: private boolean lockedUI = false;
0140:
0141: private ListenerList pageChangedListeners = new ListenerList();
0142:
0143: private ListenerList pageChangingListeners = new ListenerList();
0144:
0145: /**
0146: * A layout for a container which includes several pages, like a notebook,
0147: * wizard, or preference dialog. The size computed by this layout is the
0148: * maximum width and height of all pages currently inserted into the
0149: * container.
0150: */
0151: protected class PageContainerFillLayout extends Layout {
0152: /**
0153: * The margin width; <code>5</code> pixels by default.
0154: */
0155: public int marginWidth = 5;
0156:
0157: /**
0158: * The margin height; <code>5</code> pixels by default.
0159: */
0160: public int marginHeight = 5;
0161:
0162: /**
0163: * The minimum width; <code>0</code> pixels by default.
0164: */
0165: public int minimumWidth = 0;
0166:
0167: /**
0168: * The minimum height; <code>0</code> pixels by default.
0169: */
0170: public int minimumHeight = 0;
0171:
0172: /**
0173: * Creates new layout object.
0174: *
0175: * @param mw
0176: * the margin width
0177: * @param mh
0178: * the margin height
0179: * @param minW
0180: * the minimum width
0181: * @param minH
0182: * the minimum height
0183: */
0184: public PageContainerFillLayout(int mw, int mh, int minW,
0185: int minH) {
0186: marginWidth = mw;
0187: marginHeight = mh;
0188: minimumWidth = minW;
0189: minimumHeight = minH;
0190: }
0191:
0192: /*
0193: * (non-Javadoc) Method declared on Layout.
0194: */
0195: public Point computeSize(Composite composite, int wHint,
0196: int hHint, boolean force) {
0197: if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
0198: return new Point(wHint, hHint);
0199: }
0200: Point result = null;
0201: Control[] children = composite.getChildren();
0202: if (children.length > 0) {
0203: result = new Point(0, 0);
0204: for (int i = 0; i < children.length; i++) {
0205: Point cp = children[i].computeSize(wHint, hHint,
0206: force);
0207: result.x = Math.max(result.x, cp.x);
0208: result.y = Math.max(result.y, cp.y);
0209: }
0210: result.x = result.x + 2 * marginWidth;
0211: result.y = result.y + 2 * marginHeight;
0212: } else {
0213: Rectangle rect = composite.getClientArea();
0214: result = new Point(rect.width, rect.height);
0215: }
0216: result.x = Math.max(result.x, minimumWidth);
0217: result.y = Math.max(result.y, minimumHeight);
0218: if (wHint != SWT.DEFAULT) {
0219: result.x = wHint;
0220: }
0221: if (hHint != SWT.DEFAULT) {
0222: result.y = hHint;
0223: }
0224: return result;
0225: }
0226:
0227: /**
0228: * Returns the client area for the given composite according to this
0229: * layout.
0230: *
0231: * @param c
0232: * the composite
0233: * @return the client area rectangle
0234: */
0235: public Rectangle getClientArea(Composite c) {
0236: Rectangle rect = c.getClientArea();
0237: rect.x = rect.x + marginWidth;
0238: rect.y = rect.y + marginHeight;
0239: rect.width = rect.width - 2 * marginWidth;
0240: rect.height = rect.height - 2 * marginHeight;
0241: return rect;
0242: }
0243:
0244: /*
0245: * (non-Javadoc) Method declared on Layout.
0246: */
0247: public void layout(Composite composite, boolean force) {
0248: Rectangle rect = getClientArea(composite);
0249: Control[] children = composite.getChildren();
0250: for (int i = 0; i < children.length; i++) {
0251: children[i].setBounds(rect);
0252: }
0253: }
0254:
0255: /**
0256: * Lays outs the page according to this layout.
0257: *
0258: * @param w
0259: * the control
0260: */
0261: public void layoutPage(Control w) {
0262: w.setBounds(getClientArea(w.getParent()));
0263: }
0264:
0265: /**
0266: * Sets the location of the page so that its origin is in the upper left
0267: * corner.
0268: *
0269: * @param w
0270: * the control
0271: */
0272: public void setPageLocation(Control w) {
0273: w.setLocation(marginWidth, marginHeight);
0274: }
0275: }
0276:
0277: /**
0278: * Creates a new wizard dialog for the given wizard.
0279: *
0280: * @param parentShell
0281: * the parent shell
0282: * @param newWizard
0283: * the wizard this dialog is working on
0284: */
0285: public WizardDialog(Shell parentShell, IWizard newWizard) {
0286: super (parentShell);
0287: setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER
0288: | SWT.APPLICATION_MODAL | SWT.RESIZE
0289: | getDefaultOrientation());
0290: setWizard(newWizard);
0291: // since VAJava can't initialize an instance var with an anonymous
0292: // class outside a constructor we do it here:
0293: cancelListener = new SelectionAdapter() {
0294: public void widgetSelected(SelectionEvent e) {
0295: cancelPressed();
0296: }
0297: };
0298: }
0299:
0300: /**
0301: * About to start a long running operation triggered through the wizard.
0302: * Shows the progress monitor and disables the wizard's buttons and
0303: * controls.
0304: *
0305: * @param enableCancelButton
0306: * <code>true</code> if the Cancel button should be enabled,
0307: * and <code>false</code> if it should be disabled
0308: * @return the saved UI state
0309: */
0310: private Object aboutToStart(boolean enableCancelButton) {
0311: Map savedState = null;
0312: if (getShell() != null) {
0313: // Save focus control
0314: Control focusControl = getShell().getDisplay()
0315: .getFocusControl();
0316: if (focusControl != null
0317: && focusControl.getShell() != getShell()) {
0318: focusControl = null;
0319: }
0320: boolean needsProgressMonitor = wizard
0321: .needsProgressMonitor();
0322: cancelButton.removeSelectionListener(cancelListener);
0323: // Set the busy cursor to all shells.
0324: Display d = getShell().getDisplay();
0325: waitCursor = new Cursor(d, SWT.CURSOR_WAIT);
0326: setDisplayCursor(waitCursor);
0327: // Set the arrow cursor to the cancel component.
0328: arrowCursor = new Cursor(d, SWT.CURSOR_ARROW);
0329: cancelButton.setCursor(arrowCursor);
0330: // Deactivate shell
0331: savedState = saveUIState(needsProgressMonitor
0332: && enableCancelButton);
0333: if (focusControl != null) {
0334: savedState.put(FOCUS_CONTROL, focusControl);
0335: }
0336: // Attach the progress monitor part to the cancel button
0337: if (needsProgressMonitor) {
0338: progressMonitorPart
0339: .attachToCancelComponent(cancelButton);
0340: progressMonitorPart.setVisible(true);
0341: }
0342: }
0343: return savedState;
0344: }
0345:
0346: /**
0347: * The Back button has been pressed.
0348: */
0349: protected void backPressed() {
0350: IWizardPage page = currentPage.getPreviousPage();
0351: if (page == null) {
0352: // should never happen since we have already visited the page
0353: return;
0354: }
0355:
0356: // set flag to indicate that we are moving back
0357: isMovingToPreviousPage = true;
0358: // show the page
0359: showPage(page);
0360: }
0361:
0362: /*
0363: * (non-Javadoc) Method declared on Dialog.
0364: */
0365: protected void buttonPressed(int buttonId) {
0366: switch (buttonId) {
0367: case IDialogConstants.HELP_ID: {
0368: helpPressed();
0369: break;
0370: }
0371: case IDialogConstants.BACK_ID: {
0372: backPressed();
0373: break;
0374: }
0375: case IDialogConstants.NEXT_ID: {
0376: nextPressed();
0377: break;
0378: }
0379: case IDialogConstants.FINISH_ID: {
0380: finishPressed();
0381: break;
0382: }
0383: // The Cancel button has a listener which calls cancelPressed
0384: // directly
0385: }
0386: }
0387:
0388: /**
0389: * Calculates the difference in size between the given page and the page
0390: * container. A larger page results in a positive delta.
0391: *
0392: * @param page
0393: * the page
0394: * @return the size difference encoded as a
0395: * <code>new Point(deltaWidth,deltaHeight)</code>
0396: */
0397: private Point calculatePageSizeDelta(IWizardPage page) {
0398: Control pageControl = page.getControl();
0399: if (pageControl == null) {
0400: // control not created yet
0401: return new Point(0, 0);
0402: }
0403: Point contentSize = pageControl.computeSize(SWT.DEFAULT,
0404: SWT.DEFAULT, true);
0405: Rectangle rect = pageContainerLayout
0406: .getClientArea(pageContainer);
0407: Point containerSize = new Point(rect.width, rect.height);
0408: return new Point(Math.max(0, contentSize.x - containerSize.x),
0409: Math.max(0, contentSize.y - containerSize.y));
0410: }
0411:
0412: /*
0413: * (non-Javadoc) Method declared on Dialog.
0414: */
0415: protected void cancelPressed() {
0416: if (activeRunningOperations <= 0) {
0417: // Close the dialog. The check whether the dialog can be
0418: // closed or not is done in <code>okToClose</code>.
0419: // This ensures that the check is also evaluated when the user
0420: // presses the window's close button.
0421: setReturnCode(CANCEL);
0422: close();
0423: } else {
0424: cancelButton.setEnabled(false);
0425: }
0426: }
0427:
0428: /*
0429: * (non-Javadoc)
0430: *
0431: * @see org.eclipse.jface.window.Window#close()
0432: */
0433: public boolean close() {
0434: if (okToClose()) {
0435: return hardClose();
0436: }
0437: return false;
0438: }
0439:
0440: /*
0441: * (non-Javadoc) Method declared on Window.
0442: */
0443: protected void configureShell(Shell newShell) {
0444: super .configureShell(newShell);
0445: // Register help listener on the shell
0446: newShell.addHelpListener(new HelpListener() {
0447: public void helpRequested(HelpEvent event) {
0448: // call perform help on the current page
0449: if (currentPage != null) {
0450: currentPage.performHelp();
0451: }
0452: }
0453: });
0454: }
0455:
0456: /**
0457: * Creates the buttons for this dialog's button bar.
0458: * <p>
0459: * The <code>WizardDialog</code> implementation of this framework method
0460: * prevents the parent composite's columns from being made equal width in
0461: * order to remove the margin between the Back and Next buttons.
0462: * </p>
0463: *
0464: * @param parent
0465: * the parent composite to contain the buttons
0466: */
0467: protected void createButtonsForButtonBar(Composite parent) {
0468: ((GridLayout) parent.getLayout()).makeColumnsEqualWidth = false;
0469: if (wizard.isHelpAvailable()) {
0470: helpButton = createButton(parent, IDialogConstants.HELP_ID,
0471: IDialogConstants.HELP_LABEL, false);
0472: }
0473: if (wizard.needsPreviousAndNextButtons()) {
0474: createPreviousAndNextButtons(parent);
0475: }
0476: finishButton = createButton(parent, IDialogConstants.FINISH_ID,
0477: IDialogConstants.FINISH_LABEL, true);
0478: cancelButton = createCancelButton(parent);
0479: }
0480:
0481: /*
0482: * (non-Javadoc)
0483: *
0484: * @see org.eclipse.jface.dialogs.Dialog#setButtonLayoutData(org.eclipse.swt.widgets.Button)
0485: */
0486: protected void setButtonLayoutData(Button button) {
0487: GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
0488: int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
0489:
0490: // On large fonts this can make this dialog huge
0491: widthHint = Math.min(widthHint,
0492: button.getDisplay().getBounds().width / 5);
0493: Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT,
0494: true);
0495: data.widthHint = Math.max(widthHint, minSize.x);
0496:
0497: button.setLayoutData(data);
0498: }
0499:
0500: /**
0501: * Creates the Cancel button for this wizard dialog. Creates a standard (<code>SWT.PUSH</code>)
0502: * button and registers for its selection events. Note that the number of
0503: * columns in the button bar composite is incremented. The Cancel button is
0504: * created specially to give it a removeable listener.
0505: *
0506: * @param parent
0507: * the parent button bar
0508: * @return the new Cancel button
0509: */
0510: private Button createCancelButton(Composite parent) {
0511: // increment the number of columns in the button bar
0512: ((GridLayout) parent.getLayout()).numColumns++;
0513: Button button = new Button(parent, SWT.PUSH);
0514: button.setText(IDialogConstants.CANCEL_LABEL);
0515: setButtonLayoutData(button);
0516: button.setFont(parent.getFont());
0517: button.setData(new Integer(IDialogConstants.CANCEL_ID));
0518: button.addSelectionListener(cancelListener);
0519: return button;
0520: }
0521:
0522: /**
0523: * Return the cancel button if the id is a the cancel id.
0524: *
0525: * @param id
0526: * the button id
0527: * @return the button corresponding to the button id
0528: */
0529: protected Button getButton(int id) {
0530: if (id == IDialogConstants.CANCEL_ID) {
0531: return cancelButton;
0532: }
0533: return super .getButton(id);
0534: }
0535:
0536: /**
0537: * The <code>WizardDialog</code> implementation of this
0538: * <code>Window</code> method calls call <code>IWizard.addPages</code>
0539: * to allow the current wizard to add extra pages, then
0540: * <code>super.createContents</code> to create the controls. It then calls
0541: * <code>IWizard.createPageControls</code> to allow the wizard to
0542: * pre-create their page controls prior to opening, so that the wizard opens
0543: * to the correct size. And finally it shows the first page.
0544: */
0545: protected Control createContents(Composite parent) {
0546: // Allow the wizard to add pages to itself
0547: // Need to call this now so page count is correct
0548: // for determining if next/previous buttons are needed
0549: wizard.addPages();
0550: Control contents = super .createContents(parent);
0551: // Allow the wizard pages to precreate their page controls
0552: createPageControls();
0553: // Show the first page
0554: showStartingPage();
0555: return contents;
0556: }
0557:
0558: /*
0559: * (non-Javadoc) Method declared on Dialog.
0560: */
0561: protected Control createDialogArea(Composite parent) {
0562: Composite composite = (Composite) super
0563: .createDialogArea(parent);
0564: // Build the Page container
0565: pageContainer = createPageContainer(composite);
0566: GridData gd = new GridData(GridData.FILL_BOTH);
0567: gd.widthHint = pageWidth;
0568: gd.heightHint = pageHeight;
0569: pageContainer.setLayoutData(gd);
0570: pageContainer.setFont(parent.getFont());
0571: // Insert a progress monitor
0572: GridLayout pmlayout = new GridLayout();
0573: pmlayout.numColumns = 1;
0574: progressMonitorPart = createProgressMonitorPart(composite,
0575: pmlayout);
0576: GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
0577: progressMonitorPart.setLayoutData(gridData);
0578: progressMonitorPart.setVisible(false);
0579: // Build the separator line
0580: Label separator = new Label(composite, SWT.HORIZONTAL
0581: | SWT.SEPARATOR);
0582: separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
0583:
0584: applyDialogFont(progressMonitorPart);
0585: return composite;
0586: }
0587:
0588: /**
0589: * Create the progress monitor part in the receiver.
0590: *
0591: * @param composite
0592: * @param pmlayout
0593: * @return ProgressMonitorPart
0594: */
0595: protected ProgressMonitorPart createProgressMonitorPart(
0596: Composite composite, GridLayout pmlayout) {
0597: return new ProgressMonitorPart(composite, pmlayout, SWT.DEFAULT) {
0598: String currentTask = null;
0599:
0600: /*
0601: * (non-Javadoc)
0602: *
0603: * @see org.eclipse.jface.wizard.ProgressMonitorPart#setBlocked(org.eclipse.core.runtime.IStatus)
0604: */
0605: public void setBlocked(IStatus reason) {
0606: super .setBlocked(reason);
0607: if (!lockedUI) {
0608: getBlockedHandler().showBlocked(getShell(), this ,
0609: reason, currentTask);
0610: }
0611: }
0612:
0613: /*
0614: * (non-Javadoc)
0615: *
0616: * @see org.eclipse.jface.wizard.ProgressMonitorPart#clearBlocked()
0617: */
0618: public void clearBlocked() {
0619: super .clearBlocked();
0620: if (!lockedUI) {
0621: getBlockedHandler().clearBlocked();
0622: }
0623: }
0624:
0625: /*
0626: * (non-Javadoc)
0627: *
0628: * @see org.eclipse.jface.wizard.ProgressMonitorPart#beginTask(java.lang.String,
0629: * int)
0630: */
0631: public void beginTask(String name, int totalWork) {
0632: super .beginTask(name, totalWork);
0633: currentTask = name;
0634: }
0635:
0636: /*
0637: * (non-Javadoc)
0638: *
0639: * @see org.eclipse.jface.wizard.ProgressMonitorPart#setTaskName(java.lang.String)
0640: */
0641: public void setTaskName(String name) {
0642: super .setTaskName(name);
0643: currentTask = name;
0644: }
0645:
0646: /*
0647: * (non-Javadoc)
0648: *
0649: * @see org.eclipse.jface.wizard.ProgressMonitorPart#subTask(java.lang.String)
0650: */
0651: public void subTask(String name) {
0652: super .subTask(name);
0653: // If we haven't got anything yet use this value for more
0654: // context
0655: if (currentTask == null) {
0656: currentTask = name;
0657: }
0658: }
0659: };
0660: }
0661:
0662: /**
0663: * Creates the container that holds all pages.
0664: *
0665: * @param parent
0666: * @return Composite
0667: */
0668: private Composite createPageContainer(Composite parent) {
0669: Composite result = new Composite(parent, SWT.NULL);
0670: result.setLayout(pageContainerLayout);
0671: return result;
0672: }
0673:
0674: /**
0675: * Allow the wizard's pages to pre-create their page controls. This allows
0676: * the wizard dialog to open to the correct size.
0677: */
0678: private void createPageControls() {
0679: // Allow the wizard pages to precreate their page controls
0680: // This allows the wizard to open to the correct size
0681: wizard.createPageControls(pageContainer);
0682: // Ensure that all of the created pages are initially not visible
0683: IWizardPage[] pages = wizard.getPages();
0684: for (int i = 0; i < pages.length; i++) {
0685: IWizardPage page = pages[i];
0686: if (page.getControl() != null) {
0687: page.getControl().setVisible(false);
0688: }
0689: }
0690: }
0691:
0692: /**
0693: * Creates the Previous and Next buttons for this wizard dialog. Creates
0694: * standard (<code>SWT.PUSH</code>) buttons and registers for their
0695: * selection events. Note that the number of columns in the button bar
0696: * composite is incremented. These buttons are created specially to prevent
0697: * any space between them.
0698: *
0699: * @param parent
0700: * the parent button bar
0701: * @return a composite containing the new buttons
0702: */
0703: private Composite createPreviousAndNextButtons(Composite parent) {
0704: // increment the number of columns in the button bar
0705: ((GridLayout) parent.getLayout()).numColumns++;
0706: Composite composite = new Composite(parent, SWT.NONE);
0707: // create a layout with spacing and margins appropriate for the font
0708: // size.
0709: GridLayout layout = new GridLayout();
0710: layout.numColumns = 0; // will be incremented by createButton
0711: layout.marginWidth = 0;
0712: layout.marginHeight = 0;
0713: layout.horizontalSpacing = 0;
0714: layout.verticalSpacing = 0;
0715: composite.setLayout(layout);
0716: GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER
0717: | GridData.VERTICAL_ALIGN_CENTER);
0718: composite.setLayoutData(data);
0719: composite.setFont(parent.getFont());
0720: backButton = createButton(composite, IDialogConstants.BACK_ID,
0721: IDialogConstants.BACK_LABEL, false);
0722: nextButton = createButton(composite, IDialogConstants.NEXT_ID,
0723: IDialogConstants.NEXT_LABEL, false);
0724: return composite;
0725: }
0726:
0727: /**
0728: * Creates and return a new wizard closing dialog without openiong it.
0729: *
0730: * @return MessageDalog
0731: */
0732: private MessageDialog createWizardClosingDialog() {
0733: MessageDialog result = new MessageDialog(
0734: getShell(),
0735: JFaceResources.getString("WizardClosingDialog.title"), //$NON-NLS-1$
0736: null,
0737: JFaceResources.getString("WizardClosingDialog.message"), //$NON-NLS-1$
0738: MessageDialog.QUESTION,
0739: new String[] { IDialogConstants.OK_LABEL }, 0);
0740: return result;
0741: }
0742:
0743: /**
0744: * The Finish button has been pressed.
0745: */
0746: protected void finishPressed() {
0747: // Wizards are added to the nested wizards list in setWizard.
0748: // This means that the current wizard is always the last wizard in the
0749: // list.
0750: // Note that we first call the current wizard directly (to give it a
0751: // chance to
0752: // abort, do work, and save state) then call the remaining n-1 wizards
0753: // in the
0754: // list (to save state).
0755: if (wizard.performFinish()) {
0756: // Call perform finish on outer wizards in the nested chain
0757: // (to allow them to save state for example)
0758: for (int i = 0; i < nestedWizards.size() - 1; i++) {
0759: ((IWizard) nestedWizards.get(i)).performFinish();
0760: }
0761: // Hard close the dialog.
0762: setReturnCode(OK);
0763: hardClose();
0764: }
0765: }
0766:
0767: /*
0768: * (non-Javadoc) Method declared on IWizardContainer.
0769: */
0770: public IWizardPage getCurrentPage() {
0771: return currentPage;
0772: }
0773:
0774: /**
0775: * Returns the progress monitor for this wizard dialog (if it has one).
0776: *
0777: * @return the progress monitor, or <code>null</code> if this wizard
0778: * dialog does not have one
0779: */
0780: protected IProgressMonitor getProgressMonitor() {
0781: return progressMonitorPart;
0782: }
0783:
0784: /**
0785: * Returns the wizard this dialog is currently displaying.
0786: *
0787: * @return the current wizard
0788: */
0789: protected IWizard getWizard() {
0790: return wizard;
0791: }
0792:
0793: /**
0794: * Closes this window.
0795: *
0796: * @return <code>true</code> if the window is (or was already) closed, and
0797: * <code>false</code> if it is still open
0798: */
0799: private boolean hardClose() {
0800: // inform wizards
0801: for (int i = 0; i < createdWizards.size(); i++) {
0802: IWizard createdWizard = (IWizard) createdWizards.get(i);
0803: createdWizard.dispose();
0804: // Remove this dialog as a parent from the managed wizard.
0805: // Note that we do this after calling dispose as the wizard or
0806: // its pages may need access to the container during
0807: // dispose code
0808: createdWizard.setContainer(null);
0809: }
0810: return super .close();
0811: }
0812:
0813: /**
0814: * The Help button has been pressed.
0815: */
0816: protected void helpPressed() {
0817: if (currentPage != null) {
0818: currentPage.performHelp();
0819: }
0820: }
0821:
0822: /**
0823: * The Next button has been pressed.
0824: */
0825: protected void nextPressed() {
0826: IWizardPage page = currentPage.getNextPage();
0827: if (page == null) {
0828: // something must have happend getting the next page
0829: return;
0830: }
0831:
0832: // show the next page
0833: showPage(page);
0834: }
0835:
0836: /**
0837: * Notifies page changing listeners and returns result of page changing
0838: * processing to the sender.
0839: *
0840: * @param eventType
0841: * @return <code>true</code> if page changing listener completes
0842: * successfully, <code>false</code> otherwise
0843: */
0844: private boolean doPageChanging(IWizardPage targetPage) {
0845: PageChangingEvent e = new PageChangingEvent(this ,
0846: getCurrentPage(), targetPage);
0847: firePageChanging(e);
0848: // Prevent navigation if necessary
0849: return e.doit;
0850: }
0851:
0852: /**
0853: * Checks whether it is alright to close this wizard dialog and performed
0854: * standard cancel processing. If there is a long running operation in
0855: * progress, this method posts an alert message saying that the wizard
0856: * cannot be closed.
0857: *
0858: * @return <code>true</code> if it is alright to close this dialog, and
0859: * <code>false</code> if it is not
0860: */
0861: private boolean okToClose() {
0862: if (activeRunningOperations > 0) {
0863: synchronized (this ) {
0864: windowClosingDialog = createWizardClosingDialog();
0865: }
0866: windowClosingDialog.open();
0867: synchronized (this ) {
0868: windowClosingDialog = null;
0869: }
0870: return false;
0871: }
0872: return wizard.performCancel();
0873: }
0874:
0875: /**
0876: * Restores the enabled/disabled state of the given control.
0877: *
0878: * @param w
0879: * the control
0880: * @param h
0881: * the map (key type: <code>String</code>, element type:
0882: * <code>Boolean</code>)
0883: * @param key
0884: * the key
0885: * @see #saveEnableStateAndSet
0886: */
0887: private void restoreEnableState(Control w, Map h, String key) {
0888: if (w != null) {
0889: Boolean b = (Boolean) h.get(key);
0890: if (b != null) {
0891: w.setEnabled(b.booleanValue());
0892: }
0893: }
0894: }
0895:
0896: /**
0897: * Restores the enabled/disabled state of the wizard dialog's buttons and
0898: * the tree of controls for the currently showing page.
0899: *
0900: * @param state
0901: * a map containing the saved state as returned by
0902: * <code>saveUIState</code>
0903: * @see #saveUIState
0904: */
0905: private void restoreUIState(Map state) {
0906: restoreEnableState(backButton, state, "back"); //$NON-NLS-1$
0907: restoreEnableState(nextButton, state, "next"); //$NON-NLS-1$
0908: restoreEnableState(finishButton, state, "finish"); //$NON-NLS-1$
0909: restoreEnableState(cancelButton, state, "cancel"); //$NON-NLS-1$
0910: restoreEnableState(helpButton, state, "help"); //$NON-NLS-1$
0911: Object pageValue = state.get("page"); //$NON-NLS-1$
0912: if (pageValue != null) {
0913: ((ControlEnableState) pageValue).restore();
0914: }
0915: }
0916:
0917: /**
0918: * This implementation of IRunnableContext#run(boolean, boolean,
0919: * IRunnableWithProgress) blocks until the runnable has been run, regardless
0920: * of the value of <code>fork</code>. It is recommended that
0921: * <code>fork</code> is set to true in most cases. If <code>fork</code>
0922: * is set to <code>false</code>, the runnable will run in the UI thread
0923: * and it is the runnable's responsibility to call
0924: * <code>Display.readAndDispatch()</code> to ensure UI responsiveness.
0925: *
0926: * UI state is saved prior to executing the long-running operation and is
0927: * restored after the long-running operation completes executing. Any
0928: * attempt to change the UI state of the wizard in the long-running
0929: * operation will be nullified when original UI state is restored.
0930: *
0931: */
0932: public void run(boolean fork, boolean cancelable,
0933: IRunnableWithProgress runnable)
0934: throws InvocationTargetException, InterruptedException {
0935: // The operation can only be canceled if it is executed in a separate
0936: // thread.
0937: // Otherwise the UI is blocked anyway.
0938: Object state = null;
0939: if (activeRunningOperations == 0) {
0940: state = aboutToStart(fork && cancelable);
0941: }
0942: activeRunningOperations++;
0943: try {
0944: if (!fork) {
0945: lockedUI = true;
0946: }
0947: ModalContext.run(runnable, fork, getProgressMonitor(),
0948: getShell().getDisplay());
0949: lockedUI = false;
0950: } finally {
0951: activeRunningOperations--;
0952: // Stop if this is the last one
0953: if (state != null) {
0954: stopped(state);
0955: }
0956: }
0957: }
0958:
0959: /**
0960: * Saves the enabled/disabled state of the given control in the given map,
0961: * which must be modifiable.
0962: *
0963: * @param w
0964: * the control, or <code>null</code> if none
0965: * @param h
0966: * the map (key type: <code>String</code>, element type:
0967: * <code>Boolean</code>)
0968: * @param key
0969: * the key
0970: * @param enabled
0971: * <code>true</code> to enable the control, and
0972: * <code>false</code> to disable it
0973: * @see #restoreEnableState(Control, Map, String)
0974: */
0975: private void saveEnableStateAndSet(Control w, Map h, String key,
0976: boolean enabled) {
0977: if (w != null) {
0978: h.put(key, w.getEnabled() ? Boolean.TRUE : Boolean.FALSE);
0979: w.setEnabled(enabled);
0980: }
0981: }
0982:
0983: /**
0984: * Captures and returns the enabled/disabled state of the wizard dialog's
0985: * buttons and the tree of controls for the currently showing page. All
0986: * these controls are disabled in the process, with the possible exception
0987: * of the Cancel button.
0988: *
0989: * @param keepCancelEnabled
0990: * <code>true</code> if the Cancel button should remain
0991: * enabled, and <code>false</code> if it should be disabled
0992: * @return a map containing the saved state suitable for restoring later
0993: * with <code>restoreUIState</code>
0994: * @see #restoreUIState
0995: */
0996: private Map saveUIState(boolean keepCancelEnabled) {
0997: Map savedState = new HashMap(10);
0998: saveEnableStateAndSet(backButton, savedState, "back", false); //$NON-NLS-1$
0999: saveEnableStateAndSet(nextButton, savedState, "next", false); //$NON-NLS-1$
1000: saveEnableStateAndSet(finishButton, savedState, "finish", false); //$NON-NLS-1$
1001: saveEnableStateAndSet(cancelButton, savedState,
1002: "cancel", keepCancelEnabled); //$NON-NLS-1$
1003: saveEnableStateAndSet(helpButton, savedState, "help", false); //$NON-NLS-1$
1004: if (currentPage != null) {
1005: savedState
1006: .put(
1007: "page", ControlEnableState.disable(currentPage.getControl())); //$NON-NLS-1$
1008: }
1009: return savedState;
1010: }
1011:
1012: /**
1013: * Sets the given cursor for all shells currently active for this window's
1014: * display.
1015: *
1016: * @param c
1017: * the cursor
1018: */
1019: private void setDisplayCursor(Cursor c) {
1020: Shell[] shells = getShell().getDisplay().getShells();
1021: for (int i = 0; i < shells.length; i++) {
1022: shells[i].setCursor(c);
1023: }
1024: }
1025:
1026: /**
1027: * Sets the minimum page size used for the pages.
1028: *
1029: * @param minWidth
1030: * the minimum page width
1031: * @param minHeight
1032: * the minimum page height
1033: * @see #setMinimumPageSize(Point)
1034: */
1035: public void setMinimumPageSize(int minWidth, int minHeight) {
1036: Assert.isTrue(minWidth >= 0 && minHeight >= 0);
1037: pageContainerLayout.minimumWidth = minWidth;
1038: pageContainerLayout.minimumHeight = minHeight;
1039: }
1040:
1041: /**
1042: * Sets the minimum page size used for the pages.
1043: *
1044: * @param size
1045: * the page size encoded as <code>new Point(width,height)</code>
1046: * @see #setMinimumPageSize(int,int)
1047: */
1048: public void setMinimumPageSize(Point size) {
1049: setMinimumPageSize(size.x, size.y);
1050: }
1051:
1052: /**
1053: * Sets the size of all pages. The given size takes precedence over computed
1054: * sizes.
1055: *
1056: * @param width
1057: * the page width
1058: * @param height
1059: * the page height
1060: * @see #setPageSize(Point)
1061: */
1062: public void setPageSize(int width, int height) {
1063: pageWidth = width;
1064: pageHeight = height;
1065: }
1066:
1067: /**
1068: * Sets the size of all pages. The given size takes precedence over computed
1069: * sizes.
1070: *
1071: * @param size
1072: * the page size encoded as <code>new Point(width,height)</code>
1073: * @see #setPageSize(int,int)
1074: */
1075: public void setPageSize(Point size) {
1076: setPageSize(size.x, size.y);
1077: }
1078:
1079: /**
1080: * Sets the wizard this dialog is currently displaying.
1081: *
1082: * @param newWizard
1083: * the wizard
1084: */
1085: protected void setWizard(IWizard newWizard) {
1086: wizard = newWizard;
1087: wizard.setContainer(this );
1088: if (!createdWizards.contains(wizard)) {
1089: createdWizards.add(wizard);
1090: // New wizard so just add it to the end of our nested list
1091: nestedWizards.add(wizard);
1092: if (pageContainer != null) {
1093: // Dialog is already open
1094: // Allow the wizard pages to precreate their page controls
1095: // This allows the wizard to open to the correct size
1096: createPageControls();
1097: // Ensure the dialog is large enough for the wizard
1098: updateSizeForWizard(wizard);
1099: pageContainer.layout(true);
1100: }
1101: } else {
1102: // We have already seen this wizard, if it is the previous wizard
1103: // on the nested list then we assume we have gone back and remove
1104: // the last wizard from the list
1105: int size = nestedWizards.size();
1106: if (size >= 2 && nestedWizards.get(size - 2) == wizard) {
1107: nestedWizards.remove(size - 1);
1108: } else {
1109: // Assume we are going forward to revisit a wizard
1110: nestedWizards.add(wizard);
1111: }
1112: }
1113: }
1114:
1115: /*
1116: * (non-Javadoc) Method declared on IWizardContainer.
1117: */
1118: public void showPage(IWizardPage page) {
1119: if (page == null || page == currentPage) {
1120: return;
1121: }
1122:
1123: if (!isMovingToPreviousPage) {
1124: // remember my previous page.
1125: page.setPreviousPage(currentPage);
1126: } else {
1127: isMovingToPreviousPage = false;
1128: }
1129:
1130: // If page changing evaluation unsuccessful, do not change the page
1131: if (!doPageChanging(page))
1132: return;
1133:
1134: // Update for the new page in a busy cursor if possible
1135: if (getContents() == null) {
1136: updateForPage(page);
1137: } else {
1138: final IWizardPage finalPage = page;
1139: BusyIndicator.showWhile(getContents().getDisplay(),
1140: new Runnable() {
1141: public void run() {
1142: updateForPage(finalPage);
1143: }
1144: });
1145: }
1146: }
1147:
1148: /**
1149: * Update the receiver for the new page.
1150: *
1151: * @param page
1152: */
1153: private void updateForPage(IWizardPage page) {
1154: // ensure this page belongs to the current wizard
1155: if (wizard != page.getWizard()) {
1156: setWizard(page.getWizard());
1157: }
1158: // ensure that page control has been created
1159: // (this allows lazy page control creation)
1160: if (page.getControl() == null) {
1161: page.createControl(pageContainer);
1162: // the page is responsible for ensuring the created control is
1163: // accessable
1164: // via getControl.
1165: Assert
1166: .isNotNull(
1167: page.getControl(),
1168: JFaceResources
1169: .format(
1170: JFaceResources
1171: .getString("WizardDialog.missingSetControl"), //$NON-NLS-1$
1172: new Object[] { page
1173: .getName() }));
1174: // ensure the dialog is large enough for this page
1175: updateSize(page);
1176: }
1177: // make the new page visible
1178: IWizardPage oldPage = currentPage;
1179: currentPage = page;
1180:
1181: currentPage.setVisible(true);
1182: if (oldPage != null) {
1183: oldPage.setVisible(false);
1184: }
1185: // update the dialog controls
1186: update();
1187: }
1188:
1189: /**
1190: * Shows the starting page of the wizard.
1191: */
1192: private void showStartingPage() {
1193: currentPage = wizard.getStartingPage();
1194: if (currentPage == null) {
1195: // something must have happend getting the page
1196: return;
1197: }
1198: // ensure the page control has been created
1199: if (currentPage.getControl() == null) {
1200: currentPage.createControl(pageContainer);
1201: // the page is responsible for ensuring the created control is
1202: // accessable
1203: // via getControl.
1204: Assert.isNotNull(currentPage.getControl());
1205: // we do not need to update the size since the call
1206: // to initialize bounds has not been made yet.
1207: }
1208: // make the new page visible
1209: currentPage.setVisible(true);
1210: // update the dialog controls
1211: update();
1212: }
1213:
1214: /**
1215: * A long running operation triggered through the wizard was stopped either
1216: * by user input or by normal end. Hides the progress monitor and restores
1217: * the enable state wizard's buttons and controls.
1218: *
1219: * @param savedState
1220: * the saved UI state as returned by <code>aboutToStart</code>
1221: * @see #aboutToStart
1222: */
1223: private void stopped(Object savedState) {
1224: if (getShell() != null) {
1225: if (wizard.needsProgressMonitor()) {
1226: progressMonitorPart.setVisible(false);
1227: progressMonitorPart
1228: .removeFromCancelComponent(cancelButton);
1229: }
1230: Map state = (Map) savedState;
1231: restoreUIState(state);
1232: cancelButton.addSelectionListener(cancelListener);
1233: setDisplayCursor(null);
1234: cancelButton.setCursor(null);
1235: waitCursor.dispose();
1236: waitCursor = null;
1237: arrowCursor.dispose();
1238: arrowCursor = null;
1239: Control focusControl = (Control) state.get(FOCUS_CONTROL);
1240: if (focusControl != null) {
1241: focusControl.setFocus();
1242: }
1243: }
1244: }
1245:
1246: /**
1247: * Updates this dialog's controls to reflect the current page.
1248: */
1249: protected void update() {
1250: // Update the window title
1251: updateWindowTitle();
1252: // Update the title bar
1253: updateTitleBar();
1254: // Update the buttons
1255: updateButtons();
1256:
1257: // Fires the page change event
1258: firePageChanged(new PageChangedEvent(this , getCurrentPage()));
1259: }
1260:
1261: /*
1262: * (non-Javadoc) Method declared on IWizardContainer.
1263: */
1264: public void updateButtons() {
1265: boolean canFlipToNextPage = false;
1266: boolean canFinish = wizard.canFinish();
1267: if (backButton != null) {
1268: backButton
1269: .setEnabled(currentPage.getPreviousPage() != null);
1270: }
1271: if (nextButton != null) {
1272: canFlipToNextPage = currentPage.canFlipToNextPage();
1273: nextButton.setEnabled(canFlipToNextPage);
1274: }
1275: finishButton.setEnabled(canFinish);
1276: // finish is default unless it is diabled and next is enabled
1277: if (canFlipToNextPage && !canFinish) {
1278: getShell().setDefaultButton(nextButton);
1279: } else {
1280: getShell().setDefaultButton(finishButton);
1281: }
1282: }
1283:
1284: /**
1285: * Update the message line with the page's description.
1286: * <p>
1287: * A discription is shown only if there is no message or error message.
1288: * </p>
1289: */
1290: private void updateDescriptionMessage() {
1291: pageDescription = currentPage.getDescription();
1292: setMessage(pageDescription);
1293: }
1294:
1295: /*
1296: * (non-Javadoc) Method declared on IWizardContainer.
1297: */
1298: public void updateMessage() {
1299:
1300: if (currentPage == null) {
1301: return;
1302: }
1303:
1304: pageMessage = currentPage.getMessage();
1305: if (pageMessage != null
1306: && currentPage instanceof IMessageProvider) {
1307: pageMessageType = ((IMessageProvider) currentPage)
1308: .getMessageType();
1309: } else {
1310: pageMessageType = IMessageProvider.NONE;
1311: }
1312: if (pageMessage == null) {
1313: setMessage(pageDescription);
1314: } else {
1315: setMessage(pageMessage, pageMessageType);
1316: }
1317: setErrorMessage(currentPage.getErrorMessage());
1318: }
1319:
1320: /**
1321: * Changes the shell size to the given size, ensuring that it is no larger
1322: * than the display bounds.
1323: *
1324: * @param width
1325: * the shell width
1326: * @param height
1327: * the shell height
1328: */
1329: private void setShellSize(int width, int height) {
1330: Rectangle size = getShell().getBounds();
1331: size.height = height;
1332: size.width = width;
1333: getShell().setBounds(getConstrainedShellBounds(size));
1334: }
1335:
1336: /**
1337: * Computes the correct dialog size for the current page and resizes its
1338: * shell if nessessary. Also causes the container to refresh its layout.
1339: *
1340: * @param page
1341: * the wizard page to use to resize the dialog
1342: * @since 2.0
1343: */
1344: protected void updateSize(IWizardPage page) {
1345: if (page == null || page.getControl() == null) {
1346: return;
1347: }
1348: updateSizeForPage(page);
1349: pageContainerLayout.layoutPage(page.getControl());
1350: }
1351:
1352: /*
1353: * (non-Javadoc)
1354: *
1355: * @see org.eclipse.jface.wizard.IWizardContainer2#updateSize()
1356: */
1357: public void updateSize() {
1358: updateSize(currentPage);
1359: }
1360:
1361: /**
1362: * Computes the correct dialog size for the given page and resizes its shell
1363: * if nessessary.
1364: *
1365: * @param page
1366: * the wizard page
1367: */
1368: private void updateSizeForPage(IWizardPage page) {
1369: // ensure the page container is large enough
1370: Point delta = calculatePageSizeDelta(page);
1371: if (delta.x > 0 || delta.y > 0) {
1372: // increase the size of the shell
1373: Shell shell = getShell();
1374: Point shellSize = shell.getSize();
1375: setShellSize(shellSize.x + delta.x, shellSize.y + delta.y);
1376: constrainShellSize();
1377: }
1378: }
1379:
1380: /**
1381: * Computes the correct dialog size for the given wizard and resizes its
1382: * shell if nessessary.
1383: *
1384: * @param sizingWizard
1385: * the wizard
1386: */
1387: private void updateSizeForWizard(IWizard sizingWizard) {
1388: Point delta = new Point(0, 0);
1389: IWizardPage[] pages = sizingWizard.getPages();
1390: for (int i = 0; i < pages.length; i++) {
1391: // ensure the page container is large enough
1392: Point pageDelta = calculatePageSizeDelta(pages[i]);
1393: delta.x = Math.max(delta.x, pageDelta.x);
1394: delta.y = Math.max(delta.y, pageDelta.y);
1395: }
1396: if (delta.x > 0 || delta.y > 0) {
1397: // increase the size of the shell
1398: Shell shell = getShell();
1399: Point shellSize = shell.getSize();
1400: setShellSize(shellSize.x + delta.x, shellSize.y + delta.y);
1401: }
1402: }
1403:
1404: /*
1405: * (non-Javadoc) Method declared on IWizardContainer.
1406: */
1407: public void updateTitleBar() {
1408: String s = null;
1409: if (currentPage != null) {
1410: s = currentPage.getTitle();
1411: }
1412: if (s == null) {
1413: s = ""; //$NON-NLS-1$
1414: }
1415: setTitle(s);
1416: if (currentPage != null) {
1417: setTitleImage(currentPage.getImage());
1418: updateDescriptionMessage();
1419: }
1420: updateMessage();
1421: }
1422:
1423: /*
1424: * (non-Javadoc) Method declared on IWizardContainer.
1425: */
1426: public void updateWindowTitle() {
1427: if (getShell() == null) {
1428: // Not created yet
1429: return;
1430: }
1431: String title = wizard.getWindowTitle();
1432: if (title == null) {
1433: title = ""; //$NON-NLS-1$
1434: }
1435: getShell().setText(title);
1436: }
1437:
1438: /*
1439: * (non-Javadoc)
1440: *
1441: * @see org.eclipse.jface.dialogs.IPageChangeProvider#getSelectedPage()
1442: */
1443: public Object getSelectedPage() {
1444: return getCurrentPage();
1445: }
1446:
1447: /*
1448: * (non-Javadoc)
1449: *
1450: * @see org.eclipse.jface.dialog.IPageChangeProvider#addPageChangedListener()
1451: */
1452: public void addPageChangedListener(IPageChangedListener listener) {
1453: pageChangedListeners.add(listener);
1454: }
1455:
1456: /*
1457: * (non-Javadoc)
1458: *
1459: * @see org.eclipse.jface.dialog.IPageChangeProvider#removePageChangedListener()
1460: */
1461: public void removePageChangedListener(IPageChangedListener listener) {
1462: pageChangedListeners.remove(listener);
1463: }
1464:
1465: /**
1466: * Notifies any selection changed listeners that the selected page has
1467: * changed. Only listeners registered at the time this method is called are
1468: * notified.
1469: *
1470: * @param event
1471: * a selection changed event
1472: *
1473: * @see IPageChangedListener#pageChanged
1474: *
1475: * @since 3.1
1476: */
1477: protected void firePageChanged(final PageChangedEvent event) {
1478: Object[] listeners = pageChangedListeners.getListeners();
1479: for (int i = 0; i < listeners.length; ++i) {
1480: final IPageChangedListener l = (IPageChangedListener) listeners[i];
1481: SafeRunnable.run(new SafeRunnable() {
1482: public void run() {
1483: l.pageChanged(event);
1484: }
1485: });
1486: }
1487: }
1488:
1489: /**
1490: * Adds a listener for page changes to the list of page changing listeners
1491: * registered for this dialog. Has no effect if an identical listener is
1492: * already registered.
1493: *
1494: * @param listener
1495: * a page changing listener
1496: * @since 3.3
1497: */
1498: public void addPageChangingListener(IPageChangingListener listener) {
1499: pageChangingListeners.add(listener);
1500: }
1501:
1502: /**
1503: * Removes the provided page changing listener from the list of page
1504: * changing listeners registered for the dialog.
1505: *
1506: * @param listener
1507: * a page changing listener
1508: * @since 3.3
1509: */
1510: public void removePageChangingListener(
1511: IPageChangingListener listener) {
1512: pageChangingListeners.remove(listener);
1513: }
1514:
1515: /**
1516: * Notifies any page changing listeners that the currently selected dialog
1517: * page is changing. Only listeners registered at the time this method is
1518: * called are notified.
1519: *
1520: * @param event
1521: * a selection changing event
1522: *
1523: * @see IPageChangingListener#handlePageChanging(PageChangingEvent)
1524: * @since 3.3
1525: */
1526: protected void firePageChanging(final PageChangingEvent event) {
1527: Object[] listeners = pageChangingListeners.getListeners();
1528: for (int i = 0; i < listeners.length; ++i) {
1529: final IPageChangingListener l = (IPageChangingListener) listeners[i];
1530: SafeRunnable.run(new SafeRunnable() {
1531: public void run() {
1532: l.handlePageChanging(event);
1533: }
1534: });
1535: }
1536: }
1537: }
|