org.eclipse.photran.internal.ui.actions.RefactoringAction.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.photran.internal.ui.actions.RefactoringAction.java

Source

/*******************************************************************************
 * Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    UIUC - Initial API and implementation
 *******************************************************************************/
package org.eclipse.photran.internal.ui.actions;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.photran.internal.core.refactoring.IRefactoring;
import org.eclipse.photran.internal.core.refactoring.UserInputBoolean;
import org.eclipse.photran.internal.core.refactoring.UserInputString;
import org.eclipse.photran.internal.ui.UIUtil;
import org.eclipse.photran.internal.ui.menus.RefactorMenu;
import org.eclipse.photran.internal.ui.refactoring.CustomUserInputPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;

/**
 * A default action for refactorings, which provides a refactoring wizard and optionally generates
 * a simple user input page for that wizard based on {@link UserInputString} and
 * {@link UserInputBoolean} method annotations..
 *
 * @author Jeff Overbey
 *
 * @see RefactorMenu
 * @see UserInputString
 * @see UserInputBoolean
 */
public class RefactoringAction<T extends Refactoring> implements IWorkbenchWindowActionDelegate,
        //IEditorActionDelegate,
        IRunnableWithProgress {
    private IWorkbenchWindow activeWindow = null;
    private Shell activeShell = null;

    protected IRefactoring refactoring;
    protected CustomUserInputPage<T> customUserInputPage = null;

    public RefactoringAction(IRefactoring refactoring) {
        this(refactoring, null);
    }

    public RefactoringAction(IRefactoring refactoring, CustomUserInputPage<T> customUserInputPage) {
        this.refactoring = refactoring;
        this.customUserInputPage = customUserInputPage;
    }

    public void init(IWorkbenchWindow window) {
        activeWindow = window;
        if (activeWindow != null)
            activeShell = activeWindow.getShell();
    }

    public void dispose() {
        ;
    }

    public void selectionChanged(IAction action, ISelection selection) {
        ;
    }

    public void run() {
        run((IAction) null);
    }

    public void run(IAction action) {
        if (!(refactoring instanceof Refactoring)) {
            UIUtil.displayErrorDialog("ERROR: " + refactoring.getClass().getName() + //$NON-NLS-1$
                    " is not a subclass of org.eclipse.ltk.core.refactoring.Refactoring." + //$NON-NLS-1$
                    " A custom Action must be provided."); //$NON-NLS-1$
            return;
        }

        IProgressService context = PlatformUI.getWorkbench().getProgressService();
        ISchedulingRule lockEntireWorkspace = ResourcesPlugin.getWorkspace().getRoot();
        try {
            context.runInUI(context, this, lockEntireWorkspace);
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            MessageDialog.openError(activeShell, Messages.RefactoringAction_UnhandledExceptionTitle,
                    e.getMessage());
        } catch (InterruptedException e) {
            // Do nothing
        }
    }

    public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
        if (filesSavedAsNecessary()) {
            String name = refactoring.getName();
            DefaultRefactoringWizard wizard = new DefaultRefactoringWizard();
            RefactoringWizardOpenOperation wiz = new RefactoringWizardOpenOperation(wizard);
            if (activeShell == null)
                activeShell = UIUtil.determineActiveShell();
            wiz.run(activeShell, name);
        }
    }

    private boolean filesSavedAsNecessary() {
        return UIUtil.askUserToSaveModifiedFiles();
    }

    public class DefaultRefactoringWizard extends RefactoringWizard {
        @SuppressWarnings("unchecked")
        public DefaultRefactoringWizard() {
            // CHECK_INITIAL_CONDITIONS_ON_OPEN causes the initial conditions to be checked
            // twice, which may lead to duplicate or missing error messages
            // (missing if, say, an INCLUDE could not be found, but the AST was already
            // loaded into the workspace on the second invocation)
            super((Refactoring) refactoring, DIALOG_BASED_USER_INTERFACE /*| CHECK_INITIAL_CONDITIONS_ON_OPEN*/);
            setNeedsProgressMonitor(true);
            setChangeCreationCancelable(false);
            setWindowTitle(getRefactoring().getName());

            if (customUserInputPage != null)
                customUserInputPage.setRefactoring((T) getRefactoring());
        }

        @Override
        protected final void addUserInputPages() {
            setDefaultPageTitle(refactoring.getName());
            if (customUserInputPage != null)
                addPage(customUserInputPage);
            else if (hasAnnotatedMethods())
                addPage(new SimpleUserInputWizardPage(refactoring.getName()));
            else
                addPage(new NoUserInputWizardPage(refactoring.getName()));
        }

        private boolean hasAnnotatedMethods() {
            for (Method method : refactoring.getClass().getMethods()) {
                if (method.getAnnotation(UserInputString.class) != null
                        || method.getAnnotation(UserInputBoolean.class) != null) {
                    return true;
                }
            }

            return false;
        }
    }

    private final class NoUserInputWizardPage extends UserInputWizardPage {
        private NoUserInputWizardPage(String name) {
            super(name);
        }

        public void createControl(Composite parent) {
            Composite top = new Composite(parent, SWT.NONE);
            initializeDialogUnits(top);
            setControl(top);

            top.setLayout(new GridLayout(1, false));

            Label lbl = new Label(top, SWT.NONE);
            lbl.setText(
                    Messages.bind(Messages.RefactoringAction_ClickOKToRunTheRefactoring, refactoring.getName()));
        }
    }

    private final class SimpleUserInputWizardPage extends UserInputWizardPage {
        private Control firstField = null;

        private SimpleUserInputWizardPage(String name) {
            super(name);
        }

        public void createControl(Composite parent) {
            Composite top = new Composite(parent, SWT.NONE);
            initializeDialogUnits(top);
            setControl(top);

            top.setLayout(new GridLayout(2, false));

            addContolsFromAnnotatedFields(top);
        }

        private void addContolsFromAnnotatedFields(Composite group) {
            for (Method method : refactoring.getClass().getMethods()) {
                UserInputString stringAnnotation = method.getAnnotation(UserInputString.class);
                if (stringAnnotation != null) {
                    checkMethodSignature(method, String.class);
                    String defaultValue = getDefaultValue(refactoring, stringAnnotation.defaultValueMethod());
                    addTextField(group, stringAnnotation.label(), defaultValue, method);
                }

                UserInputBoolean annotation = method.getAnnotation(UserInputBoolean.class);
                if (annotation != null) {
                    checkMethodSignature(method, Boolean.TYPE);
                    addCheckBoxField(group, annotation.label(), annotation.defaultValue(), method);
                }
            }
        }

        private void checkMethodSignature(Method method, Class<?> parameterType) {
            if (!method.getReturnType().equals(Void.TYPE) || method.getParameterTypes().length != 1
                    || !method.getParameterTypes()[0].equals(parameterType)) {
                throw new IllegalArgumentException(
                        "The method " + method.getName() + " may not have the @UserInput " + //$NON-NLS-1$ //$NON-NLS-2$
                                "annotation unless it has the following signature:\n" + //$NON-NLS-1$
                                "    void " + method.getName() + "(" + parameterType.getSimpleName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            }
        }

        private String getDefaultValue(IRefactoring refactoring, String defaultValueMethod) {
            try {
                if (defaultValueMethod != null && !defaultValueMethod.equals("")) //$NON-NLS-1$
                {
                    Method getter = refactoring.getClass().getMethod(defaultValueMethod);
                    String result = getter.invoke(refactoring).toString();
                    return result == null ? "" : result; //$NON-NLS-1$
                } else
                    return ""; //$NON-NLS-1$
            } catch (Throwable e) {
                e.printStackTrace();
                return ""; //$NON-NLS-1$
            }
        }

        private void addTextField(Composite group, String label, String defaultValue, final Method method) {
            Label lbl = new Label(group, SWT.NONE);
            lbl.setText(label);

            final Text newNameField = new Text(group, SWT.BORDER);
            newNameField.setText(defaultValue);
            setString(method, defaultValue);
            newNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            newNameField.selectAll();
            newNameField.addModifyListener(new ModifyListener() {
                public void modifyText(ModifyEvent e) {
                    setString(method, newNameField.getText());
                }
            });

            if (firstField == null)
                firstField = newNameField;
        }

        private void setString(Method method, String value) {
            try {
                method.invoke(refactoring, value);
            } catch (Exception x) {
                throw new Error(x);
            }
        }

        private void addCheckBoxField(Composite group, String label, boolean defaultValue, final Method method) {
            new Label(group, SWT.NONE).setText(""); //$NON-NLS-1$

            final Button button = new Button(group, SWT.CHECK);
            button.setText(label);
            button.setSelection(defaultValue);
            setBoolean(method, defaultValue);
            button.addSelectionListener(new SelectionListener() {
                public void widgetDefaultSelected(SelectionEvent e) {
                    widgetSelected(e);
                }

                public void widgetSelected(SelectionEvent e) {
                    setBoolean(method, button.getSelection());
                }
            });

            if (firstField == null)
                firstField = button;
        }

        private void setBoolean(Method method, boolean isChecked) {
            try {
                method.invoke(refactoring, isChecked);
            } catch (Exception x) {
                throw new Error(x);
            }
        }
    }
}