org.eclipse.wst.jsdt.internal.ui.refactoring.PullUpMethodPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wst.jsdt.internal.ui.refactoring.PullUpMethodPage.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2009 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.wst.jsdt.internal.ui.refactoring;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.ISourceReference;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.ITypeHierarchy;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.HierarchyProcessor;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.PullUpRefactoring;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.wst.jsdt.internal.corext.util.Messages;
import org.eclipse.wst.jsdt.internal.corext.util.Strings;
import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaSourceViewer;
import org.eclipse.wst.jsdt.internal.ui.util.ExceptionHandler;
import org.eclipse.wst.jsdt.internal.ui.util.SWTUtil;
import org.eclipse.wst.jsdt.ui.JavaScriptElementComparator;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabelProvider;
import org.eclipse.wst.jsdt.ui.PreferenceConstants;
import org.eclipse.wst.jsdt.ui.text.JavaScriptSourceViewerConfiguration;

/**
 * Wizard page for pull up refactoring wizards which allows to specify the
 * methods to be deleted in subtypes after pull up.
 * 
 * 
 */
public class PullUpMethodPage extends UserInputWizardPage {

    private static class PullUpFilter extends ViewerFilter {

        private static boolean anySubtypeCanBeShown(final IType type, final Map typeToMemberArray,
                final ITypeHierarchy hierarchy) {
            final IType[] subTypes = hierarchy.getSubclasses(type);
            for (int i = 0; i < subTypes.length; i++) {
                if (canBeShown(subTypes[i], typeToMemberArray, hierarchy))
                    return true;
            }
            return false;
        }

        private static boolean canBeShown(final IType type, final Map typeToMemberArray,
                final ITypeHierarchy hierarchy) {
            if (typeToMemberArray.containsKey(type))
                return true;
            return anySubtypeCanBeShown(type, typeToMemberArray, hierarchy);
        }

        private static Set computeShowableSubtypesOfMainType(final ITypeHierarchy hierarchy,
                final Map typeToMemberArray) {
            final Set result = new HashSet();
            final IType[] subtypes = hierarchy.getAllSubtypes(hierarchy.getType());
            for (int i = 0; i < subtypes.length; i++) {
                final IType subtype = subtypes[i];
                if (canBeShown(subtype, typeToMemberArray, hierarchy))
                    result.add(subtype);
            }
            return result;
        }

        private static Set computeTypesToShow(final ITypeHierarchy hierarchy, final Map typeToMemberArray) {
            final Set typesToShow = new HashSet();
            typesToShow.add(hierarchy.getType());
            typesToShow.addAll(computeShowableSubtypesOfMainType(hierarchy, typeToMemberArray));
            return typesToShow;
        }

        private final Set fTypesToShow;

        public PullUpFilter(final ITypeHierarchy hierarchy, final IMember[] members) {
            // IType -> IMember[]
            final Map map = PullUpMethodPage.createTypeToMemberArrayMapping(members);
            fTypesToShow = computeTypesToShow(hierarchy, map);
        }

        public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
            if (element instanceof IFunction)
                return true;
            return fTypesToShow.contains(element);
        }
    }

    private static class PullUpHierarchyContentProvider implements ITreeContentProvider {

        private IType fDeclaringType;

        private ITypeHierarchy fHierarchy;

        private Map fTypeToMemberArray; // IType -> IMember[]

        public PullUpHierarchyContentProvider(final IType declaringType, final IMember[] members) {
            fDeclaringType = declaringType;
            fTypeToMemberArray = PullUpMethodPage.createTypeToMemberArrayMapping(members);
        }

        public void dispose() {
            fHierarchy = null;
            fTypeToMemberArray.clear();
            fTypeToMemberArray = null;
            fDeclaringType = null;
        }

        public Object[] getChildren(final Object parentElement) {
            if (parentElement instanceof IType)
                return getSubclassesAndMembers((IType) parentElement);
            else
                return new Object[0];
        }

        public Object[] getElements(final Object inputElement) {
            Assert.isTrue(inputElement == null || inputElement instanceof ITypeHierarchy);
            return new IType[] { fHierarchy.getType() };
        }

        private IMember[] getMembers(final IType type) {
            if (fTypeToMemberArray.containsKey(type))
                return (IMember[]) (fTypeToMemberArray.get(type));
            else
                return new IMember[0];
        }

        public Object getParent(final Object element) {
            if (element instanceof IType)
                return fHierarchy.getSuperclass((IType) element);
            if (element instanceof IMember)
                return ((IMember) element).getDeclaringType();
            Assert.isTrue(false, "Should not get here"); //$NON-NLS-1$
            return null;
        }

        private IType[] getSubclasses(final IType type) {
            if (type.equals(fDeclaringType))
                return new IType[0];
            return fHierarchy.getSubclasses(type);
        }

        private Object[] getSubclassesAndMembers(final IType type) {
            final Set set = new HashSet();
            set.addAll(Arrays.asList(getSubclasses(type)));
            set.addAll(Arrays.asList(getMembers(type)));
            return set.toArray();
        }

        public boolean hasChildren(final Object element) {
            if (!(element instanceof IType))
                return false;
            final IType type = (IType) element;
            return (fHierarchy.getAllSubtypes(type).length > 0) || fTypeToMemberArray.containsKey(type);
        }

        public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
            Assert.isTrue(newInput == null || newInput instanceof ITypeHierarchy);
            fHierarchy = (ITypeHierarchy) newInput;
        }
    }

    private static final String PAGE_NAME = "PullUpMethodPage"; //$NON-NLS-1$

    // IType -> IMember[]
    private static Map createTypeToMemberArrayMapping(final IMember[] members) {
        final Map typeToMemberSet = createTypeToMemberSetMapping(members);

        final Map typeToMemberArray = new HashMap();
        for (final Iterator iter = typeToMemberSet.keySet().iterator(); iter.hasNext();) {
            final IType type = (IType) iter.next();
            final Set memberSet = (Set) typeToMemberSet.get(type);
            final IMember[] memberArray = (IMember[]) memberSet.toArray(new IMember[memberSet.size()]);
            typeToMemberArray.put(type, memberArray);
        }
        return typeToMemberArray;
    }

    // IType -> Set of IMember
    private static Map createTypeToMemberSetMapping(final IMember[] members) {
        final Map typeToMemberSet = new HashMap();
        for (int i = 0; i < members.length; i++) {
            final IMember member = members[i];
            final IType type = member.getDeclaringType();
            if (!typeToMemberSet.containsKey(type))
                typeToMemberSet.put(type, new HashSet());
            ((Set) typeToMemberSet.get(type)).add(member);
        }
        return typeToMemberSet;
    }

    private boolean fChangedSettings = true;

    private Label fSelectionLabel;

    private SourceViewer fSourceViewer;

    private ContainerCheckedTreeViewer fTreeViewer;

    private Label fTypeHierarchyLabel;

    public PullUpMethodPage() {
        super(PAGE_NAME);
        setMessage(RefactoringMessages.PullUpInputPage_select_methods);
    }

    private void checkAllParents(final IType parent) {
        final ITypeHierarchy th = getTreeInput();
        final IType root = getTreeInput().getType();
        IType type = parent;
        while (!root.equals(type)) {
            fTreeViewer.setChecked(type, true);
            type = th.getSuperclass(type);
        }
        fTreeViewer.setChecked(root, true);
    }

    public void checkPulledUp() {
        uncheckAll();
        final HierarchyProcessor processor = getPullUpRefactoring().getPullUpProcessor();
        fTreeViewer.setCheckedElements(processor.getMembersToMove());
        final IType parent = processor.getDeclaringType();
        fTreeViewer.setChecked(parent, true);
        checkAllParents(parent);
    }

    private void createButtonComposite(final Composite superComposite) {
        final Composite buttonComposite = new Composite(superComposite, SWT.NONE);
        buttonComposite.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
        final GridLayout layout = new GridLayout(2, false);
        layout.marginWidth = 0;
        buttonComposite.setLayout(layout);

        fSelectionLabel = new Label(buttonComposite, SWT.LEFT | SWT.WRAP | SWT.HORIZONTAL);
        GridData data = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false);
        data.widthHint = convertWidthInCharsToPixels(32);
        fSelectionLabel.setLayoutData(data);

        final Button button = new Button(buttonComposite, SWT.PUSH);
        button.setText(RefactoringMessages.PullUpInputPage2_Select);
        button.setLayoutData(new GridData());
        SWTUtil.setButtonDimensionHint(button);
        button.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(final SelectionEvent e) {
                checkPulledUp();
                updateSelectionLabel();
            }
        });
    }

    public void createControl(final Composite parent) {
        final Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout());

        createTreeAndSourceViewer(composite);
        createButtonComposite(composite);
        setControl(composite);

        Dialog.applyDialogFont(composite);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.PULL_UP_WIZARD_PAGE);
    }

    private void createHierarchyTreeComposite(final Composite parent) {
        final Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        final GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = 1;
        layout.verticalSpacing = 1;
        composite.setLayout(layout);

        createTypeHierarchyLabel(composite);
        createTreeViewer(composite);
    }

    private void createSourceViewer(final Composite c) {
        final IPreferenceStore store = JavaScriptPlugin.getDefault().getCombinedPreferenceStore();
        fSourceViewer = new JavaSourceViewer(c, null, null, false,
                SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION, store);
        fSourceViewer.configure(new JavaScriptSourceViewerConfiguration(
                JavaScriptPlugin.getDefault().getJavaTextTools().getColorManager(), store, null, null));
        fSourceViewer.setEditable(false);
        fSourceViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
        fSourceViewer.getControl().setFont(JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT));
    }

    private void createSourceViewerComposite(final Composite parent) {
        final Composite c = new Composite(parent, SWT.NONE);
        c.setLayoutData(new GridData(GridData.FILL_BOTH));
        final GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = 1;
        layout.verticalSpacing = 1;
        c.setLayout(layout);

        createSourceViewerLabel(c);
        createSourceViewer(c);
    }

    private void createSourceViewerLabel(final Composite c) {
        final Label label = new Label(c, SWT.WRAP);
        final GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        label.setText(RefactoringMessages.PullUpInputPage2_Source);
        label.setLayoutData(gd);
    }

    private void createTreeAndSourceViewer(final Composite superComposite) {
        final SashForm composite = new SashForm(superComposite, SWT.HORIZONTAL);
        initializeDialogUnits(superComposite);
        final GridData gd = new GridData(GridData.FILL_BOTH);
        gd.heightHint = convertHeightInCharsToPixels(20);
        gd.widthHint = convertWidthInCharsToPixels(10);
        composite.setLayoutData(gd);
        final GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = 1;
        layout.verticalSpacing = 1;
        composite.setLayout(layout);

        createHierarchyTreeComposite(composite);
        createSourceViewerComposite(composite);
        composite.setWeights(new int[] { 50, 50 });
    }

    private void createTreeViewer(final Composite composite) {
        final Tree tree = new Tree(composite, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
        tree.setLayoutData(new GridData(GridData.FILL_BOTH));
        fTreeViewer = new ContainerCheckedTreeViewer(tree);
        fTreeViewer.setLabelProvider(new JavaScriptElementLabelProvider(
                JavaScriptElementLabelProvider.SHOW_DEFAULT | JavaScriptElementLabelProvider.SHOW_SMALL_ICONS));
        fTreeViewer.setUseHashlookup(true);
        fTreeViewer.setComparator(new JavaScriptElementComparator());
        fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(final SelectionChangedEvent event) {
                treeViewerSelectionChanged(event);
            }
        });
        fTreeViewer.addCheckStateListener(new ICheckStateListener() {

            public void checkStateChanged(final CheckStateChangedEvent event) {
                updateSelectionLabel();
            }
        });
    }

    private void createTypeHierarchyLabel(final Composite composite) {
        fTypeHierarchyLabel = new Label(composite, SWT.WRAP);
        final GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        fTypeHierarchyLabel.setLayoutData(gd);
    }

    public void fireSettingsChanged() {
        fChangedSettings = true;
    }

    private IFunction[] getCheckedMethods() {
        final Object[] checked = fTreeViewer.getCheckedElements();
        final List members = new ArrayList(checked.length);
        for (int i = 0; i < checked.length; i++) {
            if (checked[i] instanceof IFunction)
                members.add(checked[i]);
        }
        return (IFunction[]) members.toArray(new IFunction[members.size()]);
    }

    private ISourceReference getFirstSelectedSourceReference(final SelectionChangedEvent event) {
        final ISelection s = event.getSelection();
        if (!(s instanceof IStructuredSelection))
            return null;
        final IStructuredSelection ss = (IStructuredSelection) s;
        if (ss.size() != 1)
            return null;
        final Object first = ss.getFirstElement();
        if (!(first instanceof ISourceReference))
            return null;
        return (ISourceReference) first;
    }

    public IWizardPage getNextPage() {
        initializeRefactoring();
        return super.getNextPage();
    }

    private PullUpRefactoring getPullUpRefactoring() {
        return (PullUpRefactoring) getRefactoring();
    }

    private String getSupertypeSignature() {
        return JavaElementUtil.createSignature(getPullUpRefactoring().getPullUpProcessor().getDestinationType());
    }

    private ITypeHierarchy getTreeInput() {
        return (ITypeHierarchy) fTreeViewer.getInput();
    }

    private void initializeRefactoring() {
        getPullUpRefactoring().getPullUpProcessor().setDeletedMethods(getCheckedMethods());
    }

    private void initializeTreeViewer() {
        try {
            getContainer().run(false, false, new IRunnableWithProgress() {

                public void run(final IProgressMonitor pm) {
                    try {
                        initializeTreeViewer(pm);
                    } finally {
                        pm.done();
                    }
                }
            });
        } catch (InvocationTargetException e) {
            ExceptionHandler.handle(e, getShell(), RefactoringMessages.PullUpInputPage_pull_Up,
                    RefactoringMessages.PullUpInputPage_exception);
        } catch (InterruptedException e) {
            Assert.isTrue(false);
        }
    }

    private void initializeTreeViewer(final IProgressMonitor pm) {
        try {
            pm.beginTask(RefactoringCoreMessages.PullUpRefactoring_checking, 2);
            final PullUpRefactoringProcessor processor = getPullUpRefactoring().getPullUpProcessor();
            final IMember[] matchingMethods = processor.getMatchingElements(new SubProgressMonitor(pm, 1), false);
            final ITypeHierarchy hierarchy = processor.getDestinationTypeHierarchy(new SubProgressMonitor(pm, 1));
            removeAllTreeViewFilters();
            fTreeViewer.addFilter(new PullUpFilter(hierarchy, matchingMethods));
            fTreeViewer.setContentProvider(
                    new PullUpHierarchyContentProvider(processor.getDeclaringType(), matchingMethods));
            fTreeViewer.setInput(hierarchy);
            precheckElements(fTreeViewer);
            fTreeViewer.expandAll();
            updateSelectionLabel();
        } catch (JavaScriptModelException e) {
            ExceptionHandler.handle(e, RefactoringMessages.PullUpInputPage_pull_up1,
                    RefactoringMessages.PullUpInputPage_exception);
            fTreeViewer.setInput(null);
        } finally {
            pm.done();
        }
    }

    protected boolean performFinish() {
        initializeRefactoring();
        return super.performFinish();
    }

    private void precheckElements(final ContainerCheckedTreeViewer treeViewer) {
        final IMember[] members = getPullUpRefactoring().getPullUpProcessor().getMembersToMove();
        for (int i = 0; i < members.length; i++) {
            treeViewer.setChecked(members[i], true);
        }
    }

    private void removeAllTreeViewFilters() {
        final ViewerFilter[] filters = fTreeViewer.getFilters();
        for (int i = 0; i < filters.length; i++) {
            fTreeViewer.removeFilter(filters[i]);
        }
    }

    private void setHierarchyLabelText() {
        final String message = Messages.format(RefactoringMessages.PullUpInputPage_subtypes,
                getSupertypeSignature());
        fTypeHierarchyLabel.setText(message);
    }

    private void setSourceViewerContents(String contents) {
        if (contents != null) {
            final IJavaScriptProject project = getPullUpRefactoring().getPullUpProcessor().getDestinationType()
                    .getJavaScriptProject();
            final String[] lines = Strings.convertIntoLines(contents);
            if (lines.length > 0) {
                final int indent = Strings.computeIndentUnits(lines[lines.length - 1], project);
                contents = Strings.changeIndent(contents, indent, project, "", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
            }
        }
        final IDocument document = (contents == null) ? new Document() : new Document(contents);
        JavaScriptPlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(document);
        fSourceViewer.setDocument(document);
    }

    public void setVisible(final boolean visible) {
        if (visible && fChangedSettings) {
            fChangedSettings = false;
            initializeTreeViewer();
            setHierarchyLabelText();
        }
        super.setVisible(visible);
    }

    private void showInSourceViewer(final ISourceReference selected) throws JavaScriptModelException {
        if (selected == null)
            setSourceViewerContents(null);
        else
            setSourceViewerContents(selected.getSource());
    }

    private void treeViewerSelectionChanged(final SelectionChangedEvent event) {
        try {
            showInSourceViewer(getFirstSelectedSourceReference(event));
        } catch (JavaScriptModelException e) {
            ExceptionHandler.handle(e, RefactoringMessages.PullUpInputPage_pull_up1,
                    RefactoringMessages.PullUpInputPage_see_log);
        }
    }

    private void uncheckAll() {
        final IType root = getTreeInput().getType();
        fTreeViewer.setChecked(root, false);
    }

    private void updateSelectionLabel() {
        fSelectionLabel.setText(Messages.format(RefactoringMessages.PullUpInputPage_hierarchyLabal,
                String.valueOf(getCheckedMethods().length)));
    }
}