com.google.dart.tools.search.internal.ui.util.ExtendedDialogWindow.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.search.internal.ui.util.ExtendedDialogWindow.java

Source

/*
 * Copyright (c) 2012, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
 * 
 * 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 com.google.dart.tools.search.internal.ui.util;

import com.google.dart.tools.search.internal.ui.SearchMessages;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.dialogs.ControlEnableState;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.ModalContext;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
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.Shell;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public abstract class ExtendedDialogWindow extends TrayDialog implements IRunnableContext {

    private Control fContents;
    private Button fCancelButton;
    private List<Button> fActionButtons;
    // The number of long running operation executed from the dialog.
    private long fActiveRunningOperations;

    // The progress monitor
    private boolean fUseEmbeddedProgressMonitorPart;
    private ProgressMonitorPart fProgressMonitorPart;
    private MessageDialog fWindowClosingDialog;
    private static final String FOCUS_CONTROL = "focusControl"; //$NON-NLS-1$

    public ExtendedDialogWindow(Shell shell) {
        super(shell);
        fActionButtons = new ArrayList<Button>();
    }

    /**
     * The dialog is going to be closed. Check if there is a running operation. If so, post an alert
     * saying that the wizard can't be closed.
     * 
     * @return If false is returned, the dialog should stay open
     */
    public boolean okToClose() {
        if (fActiveRunningOperations > 0) {
            synchronized (this) {
                fWindowClosingDialog = createClosingDialog();
            }
            fWindowClosingDialog.open();
            synchronized (this) {
                fWindowClosingDialog = null;
            }
            return false;
        }
        return true;
    }

    //---- Hooks to reimplement in subclasses -----------------------------------

    @Override
    public void run(boolean fork, boolean cancelable, 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;
        try {
            fActiveRunningOperations++;
            state = aboutToStart(fork && cancelable);
            if (fUseEmbeddedProgressMonitorPart) {
                ModalContext.run(runnable, fork, fProgressMonitorPart, getShell().getDisplay());
            } else {
                new ProgressMonitorDialog(getShell()).run(fork, cancelable, runnable);
            }
        } finally {
            if (state != null) {
                stopped(state);
            }
            fActiveRunningOperations--;
        }
    }

    /**
     * Set the enable state of the perform action button.
     * 
     * @param state The new state
     */
    public void setPerformActionEnabled(boolean state) {
        for (Iterator<Button> buttons = fActionButtons.iterator(); buttons.hasNext();) {
            Button element = buttons.next();
            element.setEnabled(state);
        }
    }

    /**
     * @param enable Use the embedded progress monitor part
     */
    public void setUseEmbeddedProgressMonitorPart(boolean enable) {
        fUseEmbeddedProgressMonitorPart = enable;
    }

    //---- UI creation ----------------------------------------------------------

    /**
     * About to start a long running operation triggered through the wizard. So show the progress
     * monitor and disable the wizard.
     * 
     * @param enableCancelButton The cancel button enable state
     * @return The saved UI state.
     */
    protected synchronized Object aboutToStart(boolean enableCancelButton) {
        HashMap<Object, Object> savedState = null;
        Shell shell = getShell();
        if (shell != null) {
            Display d = shell.getDisplay();

            // Save focus control
            Control focusControl = d.getFocusControl();
            if (focusControl != null && focusControl.getShell() != shell) {
                focusControl = null;
            }

            // Set the busy cursor to all shells.
            setDisplayCursor(d, d.getSystemCursor(SWT.CURSOR_WAIT));

            // Set the arrow cursor to the cancel component.
            fCancelButton.setCursor(d.getSystemCursor(SWT.CURSOR_ARROW));

            // Deactivate shell
            savedState = saveUIState(enableCancelButton);
            if (focusControl != null) {
                savedState.put(FOCUS_CONTROL, focusControl);
            }

            if (fUseEmbeddedProgressMonitorPart) {
                // Attach the progress monitor part to the cancel button
                fProgressMonitorPart.attachToCancelComponent(fCancelButton);
                fProgressMonitorPart.setVisible(true);
            }
        }

        return savedState;
    }

    @Override
    protected void buttonPressed(int buttonId) {
        switch (buttonId) {
        case IDialogConstants.CANCEL_ID:
            if (fActiveRunningOperations == 0) {
                close();
            }
            break;
        default:
            if (performAction(buttonId)) {
                close();
            }
        }
    }

    protected Button createActionButton(Composite parent, int id, String label, boolean defaultButton) {
        Button actionButton = createButton(parent, id, label, defaultButton);
        fActionButtons.add(actionButton);
        return actionButton;
    }

    /**
     * Add buttons to the dialog's button bar. Subclasses may override.
     * 
     * @param parent the button bar composite
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        fCancelButton = createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }

    /**
     * Creates the layout of the extended dialog window.
     * 
     * @param parent The parent composite
     * @return The created control
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite result = (Composite) super.createDialogArea(parent);

        fContents = createPageArea(result);
        fContents.setLayoutData(new GridData(GridData.FILL_BOTH));

        if (fUseEmbeddedProgressMonitorPart) {
            // Insert a progress monitor
            fProgressMonitorPart = new ProgressMonitorPart(result, new GridLayout(), SWT.DEFAULT);
            fProgressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            fProgressMonitorPart.setVisible(false);
            applyDialogFont(fProgressMonitorPart);
        }

        Label separator = new Label(result, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        return result;
    }

    //---- Setters and Getters --------------------------------------------------

    /**
     * Create the page area.
     * 
     * @param parent The parent composite
     * @return The created control
     */
    protected abstract Control createPageArea(Composite parent);

    //---- Operation stuff ------------------------------------------------------

    /**
     * @return Returns the cancel component that is to be used to cancel a long running operation.
     */
    protected Control getCancelComponent() {
        return fCancelButton;
    }

    @Override
    protected void handleShellCloseEvent() {
        if (okToClose()) {
            super.handleShellCloseEvent();
        }
    }

    @Override
    protected boolean isResizable() {
        return true;
    }

    /**
     * Hook called when the user has pressed the button to perform the dialog's action. If the method
     * returns <code>false</code> the dialog stays open. Otherwise the dialog is going to be closed.
     * 
     * @param buttonId Id of the button activated
     * @return If the method returns <code>false</code> the dialog stays open.
     */
    protected boolean performAction(int buttonId) {
        return true;
    }

    //---- UI state save and restoring ---------------------------------------------

    /**
     * Hook called when the user has pressed the button to cancel the dialog. If the method returns
     * <code>false</code> the dialog stays open. Otherwise the dialog is going to be closed.
     * 
     * @return If the method returns <code>false</code> the dialog stays open.
     */
    protected boolean performCancel() {
        return true;
    }

    /*
     * Restores the enable state of the given control.
     */
    protected void restoreEnableState(Control w, @SuppressWarnings("rawtypes") HashMap h) {
        if (!w.isDisposed()) {
            Boolean b = (Boolean) h.get(w);
            if (b != null) {
                w.setEnabled(b.booleanValue());
            }
        }
    }

    /**
     * A long running operation triggered through the wizard was stopped either by user input or by
     * normal end.
     * 
     * @param savedState The saveState returned by <code>aboutToStart</code>.
     * @see #aboutToStart(boolean)
     */
    protected synchronized void stopped(Object savedState) {
        Assert.isTrue(savedState instanceof HashMap);
        Shell shell = getShell();
        if (shell != null) {
            if (fUseEmbeddedProgressMonitorPart) {
                fProgressMonitorPart.setVisible(false);
                fProgressMonitorPart.removeFromCancelComponent(fCancelButton);
            }

            @SuppressWarnings("rawtypes")
            HashMap state = (HashMap) savedState;
            restoreUIState(state);

            setDisplayCursor(shell.getDisplay(), null);
            fCancelButton.setCursor(null);
            Control focusControl = (Control) state.get(FOCUS_CONTROL);
            if (focusControl != null && !focusControl.isDisposed()) {
                focusControl.setFocus();
            }
        }
    }

    private MessageDialog createClosingDialog() {
        MessageDialog result = new MessageDialog(getShell(), SearchMessages.SearchDialogClosingDialog_title, null,
                SearchMessages.SearchDialogClosingDialog_message, MessageDialog.QUESTION,
                new String[] { IDialogConstants.OK_LABEL }, 0);
        return result;
    }

    private void restoreUIState(@SuppressWarnings("rawtypes") HashMap state) {
        restoreEnableState(fCancelButton, state);
        for (Iterator<Button> actionButtons = fActionButtons.iterator(); actionButtons.hasNext();) {
            Button button = actionButtons.next();
            restoreEnableState(button, state);
        }
        ControlEnableState pageState = (ControlEnableState) state.get("tabForm"); //$NON-NLS-1$
        pageState.restore();
    }

    private void saveEnableStateAndSet(Control w, HashMap<Object, Object> h, boolean enabled) {
        if (!w.isDisposed()) {
            h.put(w, new Boolean(w.isEnabled()));
            w.setEnabled(enabled);
        }
    }

    private HashMap<Object, Object> saveUIState(boolean keepCancelEnabled) {
        HashMap<Object, Object> savedState = new HashMap<Object, Object>(10);
        saveEnableStateAndSet(fCancelButton, savedState, keepCancelEnabled);
        for (Iterator<Button> actionButtons = fActionButtons.iterator(); actionButtons.hasNext();) {
            Button button = actionButtons.next();
            saveEnableStateAndSet(button, savedState, false);
        }
        savedState.put("tabForm", ControlEnableState.disable(fContents)); //$NON-NLS-1$

        return savedState;
    }

    private void setDisplayCursor(Display d, Cursor c) {
        Shell[] shells = d.getShells();
        for (int i = 0; i < shells.length; i++) {
            shells[i].setCursor(c);
        }
    }
}