Java tutorial
/* * Copyright 2013 Modeliosoft * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.modelio.api.ui; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.modeliosoft.modelio.javadesigner.annotations.objid; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jface.dialogs.ControlEnableState; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.IPageChangeProvider; import org.eclipse.jface.dialogs.IPageChangedListener; import org.eclipse.jface.dialogs.IPageChangingListener; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.PageChangedEvent; import org.eclipse.jface.dialogs.PageChangingEvent; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.operation.ModalContext; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.wizard.IWizard; import org.eclipse.jface.wizard.IWizardContainer2; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.ProgressMonitorPart; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.HelpEvent; import org.eclipse.swt.events.HelpListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Cursor; 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.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.plugin.AbstractUIPlugin; /** * Version of eclipse's WizardDialog using ModelioDialog instead of TitleAreaDialog. * @see WizardDialog */ @objid("c1fc24d5-910f-11e0-9de7-002564c97630") public class ModelioWizardDialog extends ModelioDialog implements IWizardContainer2, IPageChangeProvider { /** * Image registry key for error message image (value * <code>"dialog_title_error_image"</code>). */ @objid("d6549436-910f-11e0-9de7-002564c97630") public static final String WIZ_IMG_ERROR = "dialog_title_error_image"; // $NON-NLS-1$ /** * The number of long running operation executed from the dialog. */ @objid("d6550968-910f-11e0-9de7-002564c97630") private long activeRunningOperations = 0; /** * The time in milliseconds where the last job finished. 'Enter' key presses are ignored for the * next {@link #RESTORE_ENTER_DELAY} milliseconds. * <p> * The value <code>-1</code> indicates that the traverse listener needs to be installed. * </p> * * @since 3.6 */ @objid("d655096a-910f-11e0-9de7-002564c97630") long timeWhenLastJobFinished = -1; /** * Tells whether a subclass provided the progress monitor part */ @objid("d6553075-910f-11e0-9de7-002564c97630") private boolean useCustomProgressMonitorPart = true; @objid("d6553079-910f-11e0-9de7-002564c97630") private int pageMessageType = IMessageProvider.NONE; @objid("d655307a-910f-11e0-9de7-002564c97630") private String pageDescription; @objid("d655a5a7-910f-11e0-9de7-002564c97630") private boolean isMovingToPreviousPage = false; @objid("d655ccb6-910f-11e0-9de7-002564c97630") private int pageWidth = SWT.DEFAULT; @objid("d655ccb7-910f-11e0-9de7-002564c97630") private int pageHeight = SWT.DEFAULT; @objid("d655ccb8-910f-11e0-9de7-002564c97630") private static final String FOCUS_CONTROL = "focusControl"; // $NON-NLS-1$ /** * A delay in milliseconds that reduces the risk that the user accidentally triggers a * button by pressing the 'Enter' key immediately after a job has finished. * * @since 3.6 */ @objid("d655f3c7-910f-11e0-9de7-002564c97630") private static final int RESTORE_ENTER_DELAY = 500; @objid("d655f3ca-910f-11e0-9de7-002564c97630") boolean lockedUI = false; @objid("d655ccb5-910f-11e0-9de7-002564c97630") private PageContainerFillLayout pageContainerLayout = new PageContainerFillLayout(5, 5, 300, 225); /** * The wizard the dialog is currently showing. */ @objid("bbf20fb3-120f-11e2-b5c6-002564c97630") private IWizard wizard; /** * Wizards to dispose */ @objid("bbf20fb5-120f-11e2-b5c6-002564c97630") private List<IWizard> createdWizards = new ArrayList<>(); /** * Current nested wizards */ @objid("bbf20fb9-120f-11e2-b5c6-002564c97630") private List<IWizard> nestedWizards = new ArrayList<>(); /** * The currently displayed page. */ @objid("bbf20fbd-120f-11e2-b5c6-002564c97630") IWizardPage currentPage = null; /** * The progress monitor */ @objid("bc1362eb-120f-11e2-b5c6-002564c97630") private ProgressMonitorPart progressMonitorPart; @objid("bc1362ed-120f-11e2-b5c6-002564c97630") private Cursor waitCursor; @objid("bc1362ee-120f-11e2-b5c6-002564c97630") private Cursor arrowCursor; @objid("bc1362ef-120f-11e2-b5c6-002564c97630") private MessageDialog windowClosingDialog; /** * Navigation buttons */ @objid("bc1362f0-120f-11e2-b5c6-002564c97630") private Button backButton; @objid("bc1362f2-120f-11e2-b5c6-002564c97630") private Button nextButton; @objid("bc1362f3-120f-11e2-b5c6-002564c97630") private Button finishButton; @objid("bc1362f4-120f-11e2-b5c6-002564c97630") private Button cancelButton; @objid("bc1362f5-120f-11e2-b5c6-002564c97630") private Button helpButton; @objid("bc1362f6-120f-11e2-b5c6-002564c97630") private SelectionAdapter cancelListener; @objid("bc15c44a-120f-11e2-b5c6-002564c97630") private Composite pageContainer; @objid("bc1825ad-120f-11e2-b5c6-002564c97630") private ListenerList pageChangedListeners = new ListenerList(); @objid("bc1825ae-120f-11e2-b5c6-002564c97630") private ListenerList pageChangingListeners = new ListenerList(); /** * About to start a long running operation triggered through the wizard. * Shows the progress monitor and disables the wizard's buttons and * controls. * @param enableCancelButton <code>true</code> if the Cancel button should be enabled, * and <code>false</code> if it should be disabled * @return the saved UI state */ @objid("d6577a69-910f-11e0-9de7-002564c97630") private Object aboutToStart(final boolean enableCancelButton) { Map<String, Object> savedState = null; if (getShell() != null) { // Save focus control Control focusControl = getShell().getDisplay().getFocusControl(); if (focusControl != null && focusControl.getShell() != getShell()) { focusControl = null; } boolean needsProgressMonitor = this.wizard.needsProgressMonitor(); // Set the busy cursor to all shells. Display d = getShell().getDisplay(); this.waitCursor = new Cursor(d, SWT.CURSOR_WAIT); setDisplayCursor(this.waitCursor); if (this.useCustomProgressMonitorPart) { this.cancelButton.removeSelectionListener(this.cancelListener); // Set the arrow cursor to the cancel component. this.arrowCursor = new Cursor(d, SWT.CURSOR_ARROW); this.cancelButton.setCursor(this.arrowCursor); } // Deactivate shell savedState = saveUIState( this.useCustomProgressMonitorPart && needsProgressMonitor && enableCancelButton); if (focusControl != null) { savedState.put(FOCUS_CONTROL, focusControl); } // Activate cancel behavior. if (needsProgressMonitor) { if (enableCancelButton || this.useCustomProgressMonitorPart) { this.progressMonitorPart.attachToCancelComponent(this.cancelButton); } this.progressMonitorPart.setVisible(true); } // Install traverse listener once in order to implement 'Enter' and 'Space' key blocking if (this.timeWhenLastJobFinished == -1) { this.timeWhenLastJobFinished = 0; getShell().addTraverseListener(new TraverseListener() { @Override public void keyTraversed(TraverseEvent e) { if (e.detail == SWT.TRAVERSE_RETURN || (e.detail == SWT.TRAVERSE_MNEMONIC && e.keyCode == 32)) { // We want to ignore the keystroke when we detect that it has been received within the // delay period after the last operation has finished. This prevents the user from accidentally // hitting "Enter" or "Space", intending to cancel an operation, but having it processed exactly // when the operation finished, thus traversing the wizard. If there is another operation still // running, the UI is locked anyway so we are not in this code. This listener should fire only // after the UI state is restored (which by definition means all jobs are done. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=287887 if (ModelioWizardDialog.this.timeWhenLastJobFinished != 0 && System.currentTimeMillis() - ModelioWizardDialog.this.timeWhenLastJobFinished < RESTORE_ENTER_DELAY) { e.doit = false; return; } ModelioWizardDialog.this.timeWhenLastJobFinished = 0; } } }); } } return savedState; } /** * The Back button has been pressed. */ @objid("d657a17a-910f-11e0-9de7-002564c97630") protected void backPressed() { IWizardPage page = this.currentPage.getPreviousPage(); if (page == null) { // should never happen since we have already visited the page return; } // set flag to indicate that we are moving back this.isMovingToPreviousPage = true; // show the page showPage(page); } @objid("d657c887-910f-11e0-9de7-002564c97630") @Override protected void buttonPressed(final int buttonId) { switch (buttonId) { case IDialogConstants.HELP_ID: { helpPressed(); break; } case IDialogConstants.BACK_ID: { backPressed(); break; } case IDialogConstants.NEXT_ID: { nextPressed(); break; } case IDialogConstants.FINISH_ID: { finishPressed(); break; } default: { // Nothing to do // The Cancel button has a listener which calls cancelPressed directly } } } @objid("d65816a8-910f-11e0-9de7-002564c97630") @Override protected void cancelPressed() { if (this.activeRunningOperations <= 0) { // Close the dialog. The check whether the dialog can be // closed or not is done in <code>okToClose</code>. // This ensures that the check is also evaluated when the user // presses the window's close button. setReturnCode(CANCEL); close(); } else { this.cancelButton.setEnabled(false); } } @objid("d6583db6-910f-11e0-9de7-002564c97630") @Override public boolean close() { if (okToClose()) { return hardClose(); } return false; } /** * Allow the wizard's pages to pre-create their page controls. This allows * the wizard dialog to open to the correct size. */ @objid("d659eb69-910f-11e0-9de7-002564c97630") private void createPageControls() { // Allow the wizard pages to precreate their page controls // This allows the wizard to open to the correct size this.wizard.createPageControls(this.pageContainer); // Ensure that all of the created pages are initially not visible IWizardPage[] pages = this.wizard.getPages(); for (int i = 0; i < pages.length; i++) { IWizardPage page = pages[i]; if (page.getControl() != null) { page.getControl().setVisible(false); } } } /** * The Finish button has been pressed. */ @objid("d65a6097-910f-11e0-9de7-002564c97630") protected void finishPressed() { // Wizards are added to the nested wizards list in setWizard. // This means that the current wizard is always the last wizard in the // list. // Note that we first call the current wizard directly (to give it a // chance to // abort, do work, and save state) then call the remaining n-1 wizards // in the // list (to save state). if (this.wizard.performFinish()) { // Call perform finish on outer wizards in the nested chain // (to allow them to save state for example) for (int i = 0; i < this.nestedWizards.size() - 1; i++) { (this.nestedWizards.get(i)).performFinish(); } // Hard close the dialog. setReturnCode(OK); hardClose(); } } /** * Closes this window. * @return <code>true</code> if the window is (or was already) closed, and * <code>false</code> if it is still open */ @objid("d65afcd5-910f-11e0-9de7-002564c97630") private boolean hardClose() { // inform wizards for (int i = 0; i < this.createdWizards.size(); i++) { IWizard createdWizard = this.createdWizards.get(i); createdWizard.dispose(); // Remove this dialog as a parent from the managed wizard. // Note that we do this after calling dispose as the wizard or // its pages may need access to the container during // dispose code createdWizard.setContainer(null); } // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=202534 // disposing the wizards could cause the image currently set in // this dialog to be disposed. A subsequent repaint event during // close would then fail. To prevent this case, we null out the image. setTitleLeftImage(null); return super.close(); } /** * The Help button has been pressed. */ @objid("d65b23e5-910f-11e0-9de7-002564c97630") protected void helpPressed() { if (this.currentPage != null) { this.currentPage.performHelp(); } } /** * The Next button has been pressed. */ @objid("d65b4af5-910f-11e0-9de7-002564c97630") protected void nextPressed() { IWizardPage page = this.currentPage.getNextPage(); if (page == null) { // something must have happened getting the next page return; } // show the next page showPage(page); } /** * Checks whether it is alright to close this wizard dialog and performed * standard cancel processing. If there is a long running operation in * progress, this method posts an alert message saying that the wizard * cannot be closed. * @return <code>true</code> if it is alright to close this dialog, and * <code>false</code> if it is not */ @objid("d65b7208-910f-11e0-9de7-002564c97630") private boolean okToClose() { if (this.activeRunningOperations > 0) { synchronized (this) { this.windowClosingDialog = createWizardClosingDialog(); this.windowClosingDialog.open(); this.windowClosingDialog = null; } return false; } return this.wizard.performCancel(); } /** * Restores the enabled/disabled state of the wizard dialog's buttons and * the tree of controls for the currently showing page. * @see #saveUIState * @param state a map containing the saved state as returned by * <code>saveUIState</code> */ @objid("d65be738-910f-11e0-9de7-002564c97630") private void restoreUIState(final Map<String, Object> state) { restoreEnableState(this.backButton, state, "back"); //$NON-NLS-1$ restoreEnableState(this.nextButton, state, "next"); //$NON-NLS-1$ restoreEnableState(this.finishButton, state, "finish"); //$NON-NLS-1$ restoreEnableState(this.cancelButton, state, "cancel"); //$NON-NLS-1$ restoreEnableState(this.helpButton, state, "help"); //$NON-NLS-1$ Object pageValue = state.get("page"); //$NON-NLS-1$ if (pageValue != null) { ((ControlEnableState) pageValue).restore(); } } /** * Captures and returns the enabled/disabled state of the wizard dialog's * buttons and the tree of controls for the currently showing page. All * these controls are disabled in the process, with the possible exception * of the Cancel button. * @see #restoreUIState * @param keepCancelEnabled <code>true</code> if the Cancel button should remain * enabled, and <code>false</code> if it should be disabled * @return a map containing the saved state suitable for restoring later * with <code>restoreUIState</code> */ @objid("d65c837a-910f-11e0-9de7-002564c97630") private Map<String, Object> saveUIState(final boolean keepCancelEnabled) { Map<String, Object> savedState = new HashMap<>(10); saveEnableStateAndSet(this.backButton, savedState, "back", false); //$NON-NLS-1$ saveEnableStateAndSet(this.nextButton, savedState, "next", false); //$NON-NLS-1$ saveEnableStateAndSet(this.finishButton, savedState, "finish", false); //$NON-NLS-1$ saveEnableStateAndSet(this.cancelButton, savedState, "cancel", keepCancelEnabled); //$NON-NLS-1$ saveEnableStateAndSet(this.helpButton, savedState, "help", false); //$NON-NLS-1$ if (this.currentPage != null) { savedState.put("page", ControlEnableState.disable(this.currentPage.getControl())); //$NON-NLS-1$ } return savedState; } /** * Sets the minimum page size used for the pages. * @see #setMinimumPageSize(Point) * @param minWidth the minimum page width * @param minHeight the minimum page height */ @objid("d65cf8a5-910f-11e0-9de7-002564c97630") public void setMinimumPageSize(final int minWidth, final int minHeight) { Assert.isTrue(minWidth >= 0 && minHeight >= 0); this.pageContainerLayout.minimumWidth = minWidth; this.pageContainerLayout.minimumHeight = minHeight; } /** * Sets the size of all pages. The given size takes precedence over computed * sizes. * @see #setPageSize(Point) * @param width the page width * @param height the page height */ @objid("d65d46c6-910f-11e0-9de7-002564c97630") public void setPageSize(final int width, final int height) { this.pageWidth = width; this.pageHeight = height; } /** * Shows the starting page of the wizard. */ @objid("d65e0a16-910f-11e0-9de7-002564c97630") private void showStartingPage() { this.currentPage = this.wizard.getStartingPage(); if (this.currentPage == null) { // something must have happened getting the page return; } // ensure the page control has been created if (this.currentPage.getControl() == null) { this.currentPage.createControl(this.pageContainer); // the page is responsible for ensuring the created control is // accessible via getControl. Assert.isNotNull(this.currentPage.getControl()); // we do not need to update the size since the call // to initialize bounds has not been made yet. } // make the new page visible this.currentPage.setVisible(true); // update the dialog controls update(); } /** * A long running operation triggered through the wizard was stopped either * by user input or by normal end. Hides the progress monitor and restores * the enable state wizard's buttons and controls. * @see #aboutToStart * @param savedState the saved UI state as returned by <code>aboutToStart</code> */ @objid("d65e3125-910f-11e0-9de7-002564c97630") private void stopped(final Object savedState) { if (getShell() != null && !getShell().isDisposed()) { if (this.wizard.needsProgressMonitor()) { this.progressMonitorPart.setVisible(false); this.progressMonitorPart.removeFromCancelComponent(this.cancelButton); } @SuppressWarnings("unchecked") Map<String, Object> state = (Map<String, Object>) savedState; restoreUIState(state); setDisplayCursor(null); if (this.useCustomProgressMonitorPart) { this.cancelButton.addSelectionListener(this.cancelListener); this.cancelButton.setCursor(null); this.arrowCursor.dispose(); this.arrowCursor = null; } this.waitCursor.dispose(); this.waitCursor = null; Control focusControl = (Control) state.get(FOCUS_CONTROL); if (focusControl != null && !focusControl.isDisposed()) { focusControl.setFocus(); } } } /** * Updates this dialog's controls to reflect the current page. */ @objid("d65e5835-910f-11e0-9de7-002564c97630") protected void update() { // Update the window title updateWindowTitle(); // Update the title bar updateTitleBar(); // Update the buttons updateButtons(); // Fires the page change event firePageChanged(new PageChangedEvent(this, getCurrentPage())); } @objid("d65e7f45-910f-11e0-9de7-002564c97630") @Override public void updateButtons() { boolean canFlipToNextPage = false; boolean canFinish = this.wizard.canFinish(); if (this.backButton != null) { this.backButton.setEnabled(this.currentPage.getPreviousPage() != null); } if (this.nextButton != null) { canFlipToNextPage = this.currentPage.canFlipToNextPage(); this.nextButton.setEnabled(canFlipToNextPage); } this.finishButton.setEnabled(canFinish); // finish is default unless it is disabled and next is enabled if (canFlipToNextPage && !canFinish) { getShell().setDefaultButton(this.nextButton); } else { getShell().setDefaultButton(this.finishButton); } } /** * Update the message line with the page's description. * <p> * A description is shown only if there is no message or error message. * </p> */ @objid("d65ea655-910f-11e0-9de7-002564c97630") private void updateDescriptionMessage() { this.pageDescription = this.currentPage.getDescription(); setMessage(this.pageDescription); } @objid("d65ecd65-910f-11e0-9de7-002564c97630") @Override public void updateMessage() { if (this.currentPage == null) { return; } String pageMessage = this.currentPage.getMessage(); if (pageMessage != null && this.currentPage instanceof IMessageProvider) { this.pageMessageType = ((IMessageProvider) this.currentPage).getMessageType(); } else { this.pageMessageType = IMessageProvider.NONE; } if (pageMessage == null) { setMessage(this.pageDescription); } else { setMessage(pageMessage, this.pageMessageType); } setErrorMessage(this.currentPage.getErrorMessage()); } /** * Changes the shell size to the given size, ensuring that it is no larger * than the display bounds. * @param width the shell width * @param height the shell height */ @objid("d65ef475-910f-11e0-9de7-002564c97630") private void setShellSize(final int width, final int height) { Rectangle size = getShell().getBounds(); size.height = height; size.width = width; getShell().setBounds(getConstrainedShellBounds(size)); } @objid("d65f90b5-910f-11e0-9de7-002564c97630") @Override public void updateSize() { updateSize(this.currentPage); } @objid("d66005e6-910f-11e0-9de7-002564c97630") @Override public void updateTitleBar() { String s = null; if (this.currentPage != null) { s = this.currentPage.getTitle(); } if (s == null) { s = ""; //$NON-NLS-1$ } setTitle(s); if (this.currentPage != null) { //setTitleLeftImage(this.currentPage.getImage()); updateDescriptionMessage(); } updateMessage(); } @objid("d6602cf5-910f-11e0-9de7-002564c97630") @Override public void updateWindowTitle() { if (getShell() == null) { // Not created yet return; } String title = this.wizard.getWindowTitle(); if (title == null) { title = ""; //$NON-NLS-1$ } getShell().setText(title); } @objid("d6605405-910f-11e0-9de7-002564c97630") @Override public Object getSelectedPage() { return getCurrentPage(); } @objid("d66201b5-910f-11e0-9de7-002564c97630") @Override public void init() { ImageDescriptor imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin("org.modelio.ui", "icons/headerleft.png"); Image image = imageDescriptor.createImage(); setTitleLeftImage(image); } /** * Creates a new wizard dialog for the given wizard. * @param parentShell the parent shell * @param newWizard the wizard this dialog is working on */ @objid("bc1825af-120f-11e2-b5c6-002564c97630") public ModelioWizardDialog(final Shell parentShell, final IWizard newWizard) { super(parentShell); setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL | SWT.RESIZE | getDefaultOrientation()); setWizard(newWizard); // since VAJava can't initialize an instance var with an anonymous // class outside a constructor we do it here: this.cancelListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { cancelPressed(); } }; } /** * Calculates the difference in size between the given page and the page * container. A larger page results in a positive delta. * @param page the page * @return the size difference encoded as a * <code>new Point(deltaWidth,deltaHeight)</code> */ @objid("bc1a870a-120f-11e2-b5c6-002564c97630") private Point calculatePageSizeDelta(final IWizardPage page) { Control pageControl = page.getControl(); if (pageControl == null) { // control not created yet return new Point(0, 0); } Point contentSize = pageControl.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); Rectangle rect = this.pageContainerLayout.getClientArea(this.pageContainer); Point containerSize = new Point(rect.width, rect.height); return new Point(Math.max(0, contentSize.x - containerSize.x), Math.max(0, contentSize.y - containerSize.y)); } @objid("bc1a8711-120f-11e2-b5c6-002564c97630") @Override protected void configureShell(final Shell newShell) { super.configureShell(newShell); // Register help listener on the shell newShell.addHelpListener(new HelpListener() { @Override public void helpRequested(HelpEvent event) { // call perform help on the current page if (ModelioWizardDialog.this.currentPage != null) { ModelioWizardDialog.this.currentPage.performHelp(); } } }); } /** * Creates the buttons for this dialog's button bar. * <p> * The <code>WizardDialog</code> implementation of this framework method * prevents the parent composite's columns from being made equal width in * order to remove the margin between the Back and Next buttons. * </p> * @param parent the parent composite to contain the buttons */ @objid("bc1a8716-120f-11e2-b5c6-002564c97630") @Override protected void createButtonsForButtonBar(final Composite parent) { ((GridLayout) parent.getLayout()).makeColumnsEqualWidth = false; if (this.wizard.isHelpAvailable()) { this.helpButton = createButton(parent, IDialogConstants.HELP_ID, IDialogConstants.HELP_LABEL, false); } if (this.wizard.needsPreviousAndNextButtons()) { createPreviousAndNextButtons(parent); } this.finishButton = createButton(parent, IDialogConstants.FINISH_ID, IDialogConstants.FINISH_LABEL, true); this.cancelButton = createCancelButton(parent); if (parent.getDisplay().getDismissalAlignment() == SWT.RIGHT) { // Make the default button the right-most button. // See also special code in org.eclipse.jface.dialogs.Dialog#initializeBounds() this.finishButton.moveBelow(null); } } @objid("bc1a871c-120f-11e2-b5c6-002564c97630") @Override protected void setButtonLayoutData(final Button button) { GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); // On large fonts this can make this dialog huge widthHint = Math.min(widthHint, button.getDisplay().getBounds().width / 5); Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); data.widthHint = Math.max(widthHint, minSize.x); button.setLayoutData(data); } /** * Creates the Cancel button for this wizard dialog. Creates a standard (<code>SWT.PUSH</code>) * button and registers for its selection events. Note that the number of * columns in the button bar composite is incremented. The Cancel button is * created specially to give it a removeable listener. * @param parent the parent button bar * @return the new Cancel button */ @objid("bc1a8721-120f-11e2-b5c6-002564c97630") private Button createCancelButton(final Composite parent) { // increment the number of columns in the button bar ((GridLayout) parent.getLayout()).numColumns++; Button button = new Button(parent, SWT.PUSH); button.setText(IDialogConstants.CANCEL_LABEL); setButtonLayoutData(button); button.setFont(parent.getFont()); button.setData(Integer.valueOf(IDialogConstants.CANCEL_ID)); button.addSelectionListener(this.cancelListener); return button; } /** * Return the cancel button if the id is a the cancel id. * @param id the button id * @return the button corresponding to the button id */ @objid("bc1a8728-120f-11e2-b5c6-002564c97630") @Override protected Button getButton(final int id) { if (id == IDialogConstants.CANCEL_ID) { return this.cancelButton; } return super.getButton(id); } /** * The <code>WizardDialog</code> implementation of this * <code>Window</code> method calls call <code>IWizard.addPages</code> * to allow the current wizard to add extra pages, then * <code>super.createContents</code> to create the controls. It then calls * <code>IWizard.createPageControls</code> to allow the wizard to * pre-create their page controls prior to opening, so that the wizard opens * to the correct size. And finally it shows the first page. */ @objid("bc1a8730-120f-11e2-b5c6-002564c97630") @Override protected Control createContents(final Composite parent) { // Allow the wizard to add pages to itself // Need to call this now so page count is correct // for determining if next/previous buttons are needed this.wizard.addPages(); Control contents = super.createContents(parent); // Allow the wizard pages to precreate their page controls createPageControls(); // Show the first page showStartingPage(); return contents; } @objid("bc1ce86f-120f-11e2-b5c6-002564c97630") @Override protected Control createDialogArea(final Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); // Build the Page container this.pageContainer = createPageContainer(composite); GridData gd = new GridData(GridData.FILL_BOTH); gd.widthHint = this.pageWidth; gd.heightHint = this.pageHeight; this.pageContainer.setLayoutData(gd); this.pageContainer.setFont(parent.getFont()); // Insert a progress monitor this.progressMonitorPart = createProgressMonitorPart(composite, new GridLayout()); GridData gridData = new GridData(GridData.FILL_HORIZONTAL); this.progressMonitorPart.setLayoutData(gridData); this.progressMonitorPart.setVisible(false); // Build the separator line Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR); separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); applyDialogFont(this.progressMonitorPart); return composite; } /** * Hook method for subclasses to create a custom progress monitor part. * <p> * The default implementation creates a progress monitor with a stop button will be created. * </p> * @param composite the parent composite * @param pmlayout the layout * @return ProgressMonitorPart the progress monitor part */ @objid("bc1ce876-120f-11e2-b5c6-002564c97630") protected ProgressMonitorPart createProgressMonitorPart(final Composite composite, final GridLayout pmlayout) { this.useCustomProgressMonitorPart = false; return new ProgressMonitorPart(composite, pmlayout, true); } /** * Creates the container that holds all pages. * @param parent * @return Composite */ @objid("bc1ce87f-120f-11e2-b5c6-002564c97630") private Composite createPageContainer(final Composite parent) { Composite result = new Composite(parent, SWT.NULL); result.setLayout(this.pageContainerLayout); return result; } /** * Creates the Previous and Next buttons for this wizard dialog. Creates * standard (<code>SWT.PUSH</code>) buttons and registers for their * selection events. Note that the number of columns in the button bar * composite is incremented. These buttons are created specially to prevent * any space between them. * @param parent the parent button bar * @return a composite containing the new buttons */ @objid("bc1ce886-120f-11e2-b5c6-002564c97630") private Composite createPreviousAndNextButtons(final Composite parent) { // increment the number of columns in the button bar ((GridLayout) parent.getLayout()).numColumns++; Composite composite = new Composite(parent, SWT.NONE); // create a layout with spacing and margins appropriate for the font // size. GridLayout layout = new GridLayout(); layout.numColumns = 0; // will be incremented by createButton layout.marginWidth = 0; layout.marginHeight = 0; layout.horizontalSpacing = 0; layout.verticalSpacing = 0; composite.setLayout(layout); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_CENTER); composite.setLayoutData(data); composite.setFont(parent.getFont()); this.backButton = createButton(composite, IDialogConstants.BACK_ID, IDialogConstants.BACK_LABEL, false); this.nextButton = createButton(composite, IDialogConstants.NEXT_ID, IDialogConstants.NEXT_LABEL, false); return composite; } /** * Creates and return a new wizard closing dialog without opening it. * @return MessageDalog */ @objid("bc1ce88d-120f-11e2-b5c6-002564c97630") private MessageDialog createWizardClosingDialog() { MessageDialog result = new MessageDialog(getShell(), JFaceResources.getString("WizardClosingDialog.title"), //$NON-NLS-1$ null, JFaceResources.getString("WizardClosingDialog.message"), //$NON-NLS-1$ MessageDialog.QUESTION, new String[] { IDialogConstants.OK_LABEL }, 0) { @Override protected int getShellStyle() { return super.getShellStyle() | SWT.SHEET; } }; return result; } @objid("bc1ce892-120f-11e2-b5c6-002564c97630") @Override public IWizardPage getCurrentPage() { return this.currentPage; } /** * Returns the progress monitor for this wizard dialog (if it has one). * @return the progress monitor, or <code>null</code> if this wizard * dialog does not have one */ @objid("bc1f49ca-120f-11e2-b5c6-002564c97630") protected IProgressMonitor getProgressMonitor() { return this.progressMonitorPart; } /** * Returns the wizard this dialog is currently displaying. * @return the current wizard */ @objid("bc1f49cf-120f-11e2-b5c6-002564c97630") protected IWizard getWizard() { return this.wizard; } /** * Notifies page changing listeners and returns result of page changing * processing to the sender. * @param eventType * @return <code>true</code> if page changing listener completes * successfully, <code>false</code> otherwise */ @objid("bc1f49d4-120f-11e2-b5c6-002564c97630") private boolean doPageChanging(final IWizardPage targetPage) { PageChangingEvent e = new PageChangingEvent(this, getCurrentPage(), targetPage); firePageChanging(e); // Prevent navigation if necessary return e.doit; } /** * Restores the enabled/disabled state of the given control. * @see #saveEnableStateAndSet * @param w the control * @param h the map (key type: <code>String</code>, element type: * <code>Boolean</code>) * @param key the key */ @objid("bc1f49db-120f-11e2-b5c6-002564c97630") private void restoreEnableState(final Control w, final Map<String, Object> h, final String key) { if (w != null) { Boolean b = (Boolean) h.get(key); if (b != null) { w.setEnabled(b.booleanValue()); } } } /** * This implementation of IRunnableContext#run(boolean, boolean, * IRunnableWithProgress) blocks until the runnable has been run, regardless * of the value of <code>fork</code>. It is recommended that * <code>fork</code> is set to true in most cases. If <code>fork</code> * is set to <code>false</code>, the runnable will run in the UI thread * and it is the runnable's responsibility to call * <code>Display.readAndDispatch()</code> to ensure UI responsiveness. * * UI state is saved prior to executing the long-running operation and is * restored after the long-running operation completes executing. Any * attempt to change the UI state of the wizard in the long-running * operation will be nullified when original UI state is restored. */ @objid("bc1f49e4-120f-11e2-b5c6-002564c97630") @Override public void run(final boolean fork, final boolean cancelable, final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException { // The operation can only be canceled if it is executed in a separate // thread. // Otherwise the UI is blocked anyway. Object state = null; if (this.activeRunningOperations == 0) { state = aboutToStart(fork && cancelable); } this.activeRunningOperations++; try { if (!fork) { this.lockedUI = true; } ModalContext.run(runnable, fork, getProgressMonitor(), getShell().getDisplay()); this.lockedUI = false; } finally { // explicitly invoke done() on our progress monitor so that its // label does not spill over to the next invocation, see bug 271530 if (getProgressMonitor() != null) { getProgressMonitor().done(); } // Stop if this is the last one if (state != null) { this.timeWhenLastJobFinished = System.currentTimeMillis(); stopped(state); } this.activeRunningOperations--; } } /** * Saves the enabled/disabled state of the given control in the given map, * which must be modifiable. * @see #restoreEnableState(Control, Map, String) * @param w the control, or <code>null</code> if none * @param h the map (key type: <code>String</code>, element type: * <code>Boolean</code>) * @param key the key * @param enabled <code>true</code> to enable the control, and * <code>false</code> to disable it */ @objid("bc21ab2c-120f-11e2-b5c6-002564c97630") private void saveEnableStateAndSet(final Control w, final Map<String, Object> h, final String key, final boolean enabled) { if (w != null) { h.put(key, w.getEnabled() ? Boolean.TRUE : Boolean.FALSE); w.setEnabled(enabled); } } /** * Sets the given cursor for all shells currently active for this window's * display. * @param c the cursor */ @objid("bc21ab3b-120f-11e2-b5c6-002564c97630") private void setDisplayCursor(final Cursor c) { Shell[] shells = getShell().getDisplay().getShells(); for (int i = 0; i < shells.length; i++) { shells[i].setCursor(c); } } /** * Sets the minimum page size used for the pages. * @see #setMinimumPageSize(int,int) * @param size the page size encoded as <code>new Point(width,height)</code> */ @objid("bc21ab40-120f-11e2-b5c6-002564c97630") public void setMinimumPageSize(final Point size) { setMinimumPageSize(size.x, size.y); } /** * Sets the size of all pages. The given size takes precedence over computed * sizes. * @see #setPageSize(int,int) * @param size the page size encoded as <code>new Point(width,height)</code> */ @objid("bc21ab45-120f-11e2-b5c6-002564c97630") public void setPageSize(final Point size) { setPageSize(size.x, size.y); } /** * Sets the wizard this dialog is currently displaying. * @param newWizard the wizard */ @objid("bc21ab4a-120f-11e2-b5c6-002564c97630") protected void setWizard(final IWizard newWizard) { this.wizard = newWizard; this.wizard.setContainer(this); if (!this.createdWizards.contains(this.wizard)) { this.createdWizards.add(this.wizard); // New wizard so just add it to the end of our nested list this.nestedWizards.add(this.wizard); if (this.pageContainer != null) { // Dialog is already open // Allow the wizard pages to precreate their page controls // This allows the wizard to open to the correct size createPageControls(); // Ensure the dialog is large enough for the wizard updateSizeForWizard(this.wizard); this.pageContainer.layout(true); } } else { // We have already seen this wizard, if it is the previous wizard // on the nested list then we assume we have gone back and remove // the last wizard from the list int size = this.nestedWizards.size(); if (size >= 2 && this.nestedWizards.get(size - 2) == this.wizard) { this.nestedWizards.remove(size - 1); } else { // Assume we are going forward to revisit a wizard this.nestedWizards.add(this.wizard); } } } @objid("bc21ab4f-120f-11e2-b5c6-002564c97630") @Override public void showPage(final IWizardPage page) { if (page == null || page == this.currentPage) { return; } if (!this.isMovingToPreviousPage) { // remember my previous page. page.setPreviousPage(this.currentPage); } else { this.isMovingToPreviousPage = false; } // If page changing evaluation unsuccessful, do not change the page if (!doPageChanging(page)) return; // Update for the new page in a busy cursor if possible if (getContents() == null) { updateForPage(page); } else { final IWizardPage finalPage = page; BusyIndicator.showWhile(getContents().getDisplay(), new Runnable() { @Override public void run() { updateForPage(finalPage); } }); } } /** * Update the receiver for the new page. * @param page */ @objid("bc21ab54-120f-11e2-b5c6-002564c97630") void updateForPage(final IWizardPage page) { // ensure this page belongs to the current wizard if (this.wizard != page.getWizard()) { setWizard(page.getWizard()); } // ensure that page control has been created // (this allows lazy page control creation) if (page.getControl() == null) { page.createControl(this.pageContainer); // the page is responsible for ensuring the created control is // accessible via getControl. Assert.isNotNull(page.getControl(), JFaceResources.format(JFaceResources.getString("WizardDialog.missingSetControl"), //$NON-NLS-1$ new Object[] { page.getName() })); // ensure the dialog is large enough for this page updateSize(page); } // make the new page visible IWizardPage oldPage = this.currentPage; this.currentPage = page; this.currentPage.setVisible(true); if (oldPage != null) { oldPage.setVisible(false); } // update the dialog controls update(); } /** * Computes the correct dialog size for the current page and resizes its shell if necessary. * Also causes the container to refresh its layout. * @param page the wizard page to use to resize the dialog * @since 2.0 */ @objid("bc240c8a-120f-11e2-b5c6-002564c97630") protected void updateSize(final IWizardPage page) { if (page == null || page.getControl() == null) { return; } updateSizeForPage(page); this.pageContainerLayout.layoutPage(page.getControl()); } /** * Computes the correct dialog size for the given page and resizes its shell if necessary. * @param page the wizard page */ @objid("bc240c8f-120f-11e2-b5c6-002564c97630") private void updateSizeForPage(final IWizardPage page) { // ensure the page container is large enough Point delta = calculatePageSizeDelta(page); if (delta.x > 0 || delta.y > 0) { // increase the size of the shell Shell shell = getShell(); Point shellSize = shell.getSize(); setShellSize(shellSize.x + delta.x, shellSize.y + delta.y); constrainShellSize(); } } /** * Computes the correct dialog size for the given wizard and resizes its shell if necessary. * @param sizingWizard the wizard */ @objid("bc240c94-120f-11e2-b5c6-002564c97630") private void updateSizeForWizard(final IWizard sizingWizard) { Point delta = new Point(0, 0); IWizardPage[] pages = sizingWizard.getPages(); for (int i = 0; i < pages.length; i++) { // ensure the page container is large enough Point pageDelta = calculatePageSizeDelta(pages[i]); delta.x = Math.max(delta.x, pageDelta.x); delta.y = Math.max(delta.y, pageDelta.y); } if (delta.x > 0 || delta.y > 0) { // increase the size of the shell Shell shell = getShell(); Point shellSize = shell.getSize(); setShellSize(shellSize.x + delta.x, shellSize.y + delta.y); } } @objid("bc240c9a-120f-11e2-b5c6-002564c97630") @Override public void addPageChangedListener(final IPageChangedListener listener) { this.pageChangedListeners.add(listener); } @objid("bc240c9f-120f-11e2-b5c6-002564c97630") @Override public void removePageChangedListener(final IPageChangedListener listener) { this.pageChangedListeners.remove(listener); } /** * Notifies any selection changed listeners that the selected page has * changed. Only listeners registered at the time this method is called are * notified. * @see IPageChangedListener#pageChanged * * @since 3.1 * @param event a selection changed event */ @objid("bc266dec-120f-11e2-b5c6-002564c97630") protected void firePageChanged(final PageChangedEvent event) { Object[] listeners = this.pageChangedListeners.getListeners(); for (int i = 0; i < listeners.length; ++i) { final IPageChangedListener l = (IPageChangedListener) listeners[i]; SafeRunnable.run(new SafeRunnable() { @Override public void run() { l.pageChanged(event); } }); } } /** * Adds a listener for page changes to the list of page changing listeners * registered for this dialog. Has no effect if an identical listener is * already registered. * @param listener a page changing listener * @since 3.3 */ @objid("bc266df1-120f-11e2-b5c6-002564c97630") public void addPageChangingListener(final IPageChangingListener listener) { this.pageChangingListeners.add(listener); } /** * Removes the provided page changing listener from the list of page * changing listeners registered for the dialog. * @param listener a page changing listener * @since 3.3 */ @objid("bc266df6-120f-11e2-b5c6-002564c97630") public void removePageChangingListener(final IPageChangingListener listener) { this.pageChangingListeners.remove(listener); } /** * Notifies any page changing listeners that the currently selected dialog * page is changing. Only listeners registered at the time this method is * called are notified. * @see IPageChangingListener#handlePageChanging(PageChangingEvent) * @since 3.3 * @param event a selection changing event */ @objid("bc266dfb-120f-11e2-b5c6-002564c97630") protected void firePageChanging(final PageChangingEvent event) { Object[] listeners = this.pageChangingListeners.getListeners(); for (int i = 0; i < listeners.length; ++i) { final IPageChangingListener l = (IPageChangingListener) listeners[i]; SafeRunnable.run(new SafeRunnable() { @Override public void run() { l.handlePageChanging(event); } }); } } @objid("bc266e00-120f-11e2-b5c6-002564c97630") @Override public void addButtonsInButtonBar(final Composite parent) { super.addDefaultButtons(parent); } @objid("bc266e05-120f-11e2-b5c6-002564c97630") @Override public Control createContentArea(final Composite parent) { return parent; } /** * A layout for a container which includes several pages, like a notebook, * wizard, or preference dialog. The size computed by this layout is the * maximum width and height of all pages currently inserted into the * container. */ @objid("d6561ad7-910f-11e0-9de7-002564c97630") protected static class PageContainerFillLayout extends Layout { /** * The margin width; <code>5</code> pixels by default. */ @objid("d65641e5-910f-11e0-9de7-002564c97630") public int marginWidth = 5; /** * The margin height; <code>5</code> pixels by default. */ @objid("d65641e7-910f-11e0-9de7-002564c97630") public int marginHeight = 5; /** * The minimum width; <code>0</code> pixels by default. */ @objid("d65641e9-910f-11e0-9de7-002564c97630") public int minimumWidth = 0; /** * The minimum height; <code>0</code> pixels by default. */ @objid("d65668f5-910f-11e0-9de7-002564c97630") public int minimumHeight = 0; /** * Creates new layout object. * @param mw the margin width * @param mh the margin height * @param minW the minimum width * @param minH the minimum height */ @objid("d65668f7-910f-11e0-9de7-002564c97630") public PageContainerFillLayout(final int mw, final int mh, final int minW, final int minH) { this.marginWidth = mw; this.marginHeight = mh; this.minimumWidth = minW; this.minimumHeight = minH; } @objid("bc266e0c-120f-11e2-b5c6-002564c97630") @Override public Point computeSize(final Composite composite, final int wHint, final int hHint, final boolean force) { if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) { return new Point(wHint, hHint); } Point result = null; Control[] children = composite.getChildren(); if (children.length > 0) { result = new Point(0, 0); for (int i = 0; i < children.length; i++) { Point cp = children[i].computeSize(wHint, hHint, force); result.x = Math.max(result.x, cp.x); result.y = Math.max(result.y, cp.y); } result.x = result.x + 2 * this.marginWidth; result.y = result.y + 2 * this.marginHeight; } else { Rectangle rect = composite.getClientArea(); result = new Point(rect.width, rect.height); } result.x = Math.max(result.x, this.minimumWidth); result.y = Math.max(result.y, this.minimumHeight); if (wHint != SWT.DEFAULT) { result.x = wHint; } if (hHint != SWT.DEFAULT) { result.y = hHint; } return result; } /** * Returns the client area for the given composite according to this * layout. * @param c the composite * @return the client area rectangle */ @objid("bc266e19-120f-11e2-b5c6-002564c97630") public Rectangle getClientArea(final Composite c) { Rectangle rect = c.getClientArea(); rect.x = rect.x + this.marginWidth; rect.y = rect.y + this.marginHeight; rect.width = rect.width - 2 * this.marginWidth; rect.height = rect.height - 2 * this.marginHeight; return rect; } @objid("bc28cf4d-120f-11e2-b5c6-002564c97630") @Override public void layout(final Composite composite, final boolean force) { Rectangle rect = getClientArea(composite); Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) { children[i].setBounds(rect); } } /** * Lays outs the page according to this layout. * @param w the control */ @objid("bc28cf54-120f-11e2-b5c6-002564c97630") public void layoutPage(final Control w) { w.setBounds(getClientArea(w.getParent())); } /** * Sets the location of the page so that its origin is in the upper left * corner. * @param w the control */ @objid("bc28cf59-120f-11e2-b5c6-002564c97630") public void setPageLocation(final Control w) { w.setLocation(this.marginWidth, this.marginHeight); } } @objid("7afdb355-975f-11e0-bb39-002564c97630") class MWDProgressMonitorPart extends ProgressMonitorPart { @objid("7afe0176-975f-11e0-bb39-002564c97630") private String currentTask = null; @objid("7afe2887-975f-11e0-bb39-002564c97630") @Override public void clearBlocked() { super.clearBlocked(); if (!ModelioWizardDialog.this.lockedUI) { getBlockedHandler().clearBlocked(); } } @objid("7afe288b-975f-11e0-bb39-002564c97630") @Override public void beginTask(final String name, final int totalWork) { super.beginTask(name, totalWork); this.currentTask = name; } @objid("7afe76a9-975f-11e0-bb39-002564c97630") @Override public void setTaskName(final String name) { super.setTaskName(name); this.currentTask = name; } @objid("7afe76ae-975f-11e0-bb39-002564c97630") @Override public void subTask(final String name) { super.subTask(name); // If we haven't got anything yet use this value for more // context if (this.currentTask == null) { this.currentTask = name; } } @objid("bc28cf5f-120f-11e2-b5c6-002564c97630") public MWDProgressMonitorPart(final Composite parent, final Layout layout, final boolean createStopButton) { super(parent, layout, createStopButton); } @objid("bc28cf67-120f-11e2-b5c6-002564c97630") @Override public void setBlocked(final IStatus reason) { super.setBlocked(reason); if (!ModelioWizardDialog.this.lockedUI) { getBlockedHandler().showBlocked(getShell(), this, reason, this.currentTask); } } } }