/** * Copyright (c) 2008-2012 University of Illinois at Urbana-Champaign. * 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 */ package edu.illinois.compositerefactorings.steps; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil; import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.ui.actions.SelectionConverter; import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.ltk.core.refactoring.CheckConditionsOperation; import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.internal.ui.refactoring.RefactoringStatusDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.handlers.HandlerUtil; import edu.illinois.compositerefactorings.messages.CompositeRefactoringsMessages; import edu.illinois.compositerefactorings.refactorings.createnewtoplevelsuperclass.CreateNewTopLevelSuperClassDescriptor; import edu.illinois.compositerefactorings.refactorings.createnewtoplevelsuperclass.CreateNewTopLevelSuperClassRefactoring; @SuppressWarnings("restriction") public class CreateNewSuperclassCommandHandler extends AbstractHandler { @SuppressWarnings("serial") public static class InvalidSelectionException extends Exception { public InvalidSelectionException(String message) { super(message); } } // private static Set<String> fullyQualifiedName(List<IType> types) { // Set<String> fullyQualifiedNames= new HashSet<String>(); // for (IType type : types) { // fullyQualifiedNames.add(type.getFullyQualifiedName()); // } // return fullyQualifiedNames; // } @Override public Object execute(ExecutionEvent event) throws ExecutionException { // See http://wiki.bioclipse.net/index.php?title=How_to_add_menus_and_actions&oldid=4857 Shell shell= HandlerUtil.getActiveShell(event); IEditorPart editorPart= HandlerUtil.getActiveEditor(event); ISelection selection= HandlerUtil.getCurrentSelection(event); try { List<IType> selectedTypes= getSelectedTypes(editorPart, selection); CreateNewTopLevelSuperClassRefactoring refactoring= createRefactoring(selectedTypes); IProgressMonitor monitor= new NullProgressMonitor(); RefactoringStatus status= checkRefactoring(selectedTypes, refactoring, monitor); if (status.isOK() || choseToProceed(shell, status)) { performRefactoring(refactoring, monitor); openNewSuperClass(selectedTypes); } } catch (JavaModelException e) { throw new ExecutionException("Unexpected selection", e); } catch (CoreException e) { throw new ExecutionException("Refactoring object creation failed.", e); } catch (InvalidSelectionException e) { MessageDialog.openError(shell, "Unavailable Refactoring", e.getMessage()); } return null; } private static void openNewSuperClass(List<IType> selectedTypes) throws JavaModelException, PartInitException { JavaUI.openInEditor(findNewType(selectedTypes.get(0))); } private static void performRefactoring(CreateNewTopLevelSuperClassRefactoring refactoring, IProgressMonitor monitor) throws CoreException { PerformRefactoringOperation operation= new PerformRefactoringOperation(refactoring, CheckConditionsOperation.INITIAL_CONDITONS); operation.run(monitor); } private static RefactoringStatus checkRefactoring(List<IType> selectedTypes, CreateNewTopLevelSuperClassRefactoring refactoring, IProgressMonitor monitor) throws CoreException { RefactoringStatus status= new RefactoringStatus(); status.merge(refactoring.checkInitialConditions(monitor)); status.merge(refactoring.checkFinalConditions(monitor)); // I (Mohsen) disabled the following check because it is too expensive. // status.merge(areSelectedTypesCompatible(refactoring, selectedTypes, monitor)); return status; } private static CreateNewTopLevelSuperClassRefactoring createRefactoring(List<IType> selectedTypes) throws CoreException { CreateNewTopLevelSuperClassDescriptor descriptor= createRefactoringDescriptor(selectedTypes); CreateNewTopLevelSuperClassRefactoring refactoring= (CreateNewTopLevelSuperClassRefactoring)descriptor.createRefactoringContext(new RefactoringStatus()).getRefactoring(); return refactoring; } private static List<IType> getSelectedTypes(IEditorPart editorPart, ISelection selection) throws InvalidSelectionException, JavaModelException { List<IType> selectedTypes; if (selection instanceof ITextSelection) { selectedTypes= getSelectedTypes(editorPart, (ITextSelection)selection); } else if (selection instanceof IStructuredSelection) { selectedTypes= getSelectedTypes((IStructuredSelection)selection); } else { throw new InvalidSelectionException("Unexpected kind of selection"); } return selectedTypes; } // private static RefactoringStatus areSelectedTypesCompatible(CreateNewTopLevelSuperClassRefactoring refactoring, List<IType> selectedTypes, IProgressMonitor monitor) { // RefactoringStatus status= new RefactoringStatus(); // List<IType> possibleTypes= Arrays.asList(refactoring.getCandidateTypes(monitor)); // if (!fullyQualifiedName(possibleTypes).containsAll(fullyQualifiedName(selectedTypes))) { // status.merge(RefactoringStatus.createErrorStatus("The selected types belong to different class hierarchies.")); // } // return status; // } private boolean choseToProceed(Shell shell, RefactoringStatus status) { return new RefactoringStatusDialog(status, shell, "Refactoring Problems", false).open() == Window.OK; } // See http://publib.boulder.ibm.com/infocenter/iadthelp/v6r0/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_open_editor.htm private static IType findNewType(IType firstSelectedType) { return firstSelectedType.getPackageFragment().getCompilationUnit("Super" + firstSelectedType.getElementName() + JavaModelUtil.DEFAULT_CU_SUFFIX).findPrimaryType(); } public static List<IType> getSelectedTypes(IEditorPart editorPart, ITextSelection selection) throws InvalidSelectionException, JavaModelException { CompilationUnitEditor editor; if (editorPart instanceof CompilationUnitEditor) { editor= (CompilationUnitEditor)editorPart; } else { throw new InvalidSelectionException("The active editor is not for editing Java compilation units."); } IType selectedType= SelectionConverter.getTypeAtOffset(editor); if (selectedType != null) { return Arrays.asList(selectedType); } else { throw new InvalidSelectionException("No Java types were selected."); } } private static List<IType> getSelectedTypes(IStructuredSelection selection) throws JavaModelException, InvalidSelectionException { List<IType> selectedTypes= new ArrayList<IType>(); for (Object selectionElement : selection.toList()) { selectedTypes.add(extractTypeFromSelection(selectionElement)); } return selectedTypes; } // See org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester.getSingleSelectedType(IStructuredSelection) private static IType extractTypeFromSelection(Object selectionElement) throws JavaModelException, InvalidSelectionException { if (selectionElement instanceof IType) return (IType)selectionElement; if (selectionElement instanceof ICompilationUnit) { final ICompilationUnit unit= (ICompilationUnit)selectionElement; if (unit.exists()) { return JavaElementUtil.getMainType(unit); } } throw new InvalidSelectionException(selectionElement + " is not a Java type."); } private static String typeNames(List<IType> types) { StringBuilder sb= new StringBuilder(); for (Iterator<IType> iterator= types.iterator(); iterator.hasNext();) { IType type= (IType)iterator.next(); sb.append(type.getElementName()); if (iterator.hasNext()) { sb.append(","); } } return sb.toString(); } public static CreateNewTopLevelSuperClassDescriptor createRefactoringDescriptor(List<IType> types) { IJavaProject javaProject= types.get(0).getJavaProject(); String description= MessageFormat.format(CompositeRefactoringsMessages.CreateNewTopLevelSuperClass_description, typeNames(types)); Map<String, String> arguments= new HashMap<String, String>(); arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(javaProject.getElementName(), types.get(0))); org.eclipse.jdt.internal.core.refactoring.descriptors.JavaRefactoringDescriptorUtil.setJavaElementArray(arguments, CreateNewTopLevelSuperClassDescriptor.ATTRIBUTE_TYPES, JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT, javaProject.getElementName(), types.toArray(new IType[] {}), 1); arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, "Super" + types.get(0).getElementName()); CreateNewTopLevelSuperClassDescriptor descriptor= new CreateNewTopLevelSuperClassDescriptor(javaProject.getElementName(), description, null, arguments, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE); return descriptor; } }