package org.eclipse.emf.mwe2.language.ui.quickfix; import java.util.List; import org.apache.log4j.Logger; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.mwe2.language.mwe2.Assignment; import org.eclipse.emf.mwe2.language.mwe2.Component; import org.eclipse.emf.mwe2.language.mwe2.DeclaredProperty; import org.eclipse.emf.mwe2.language.mwe2.impl.JvmTypeUriFactory; import org.eclipse.emf.mwe2.language.validation.Mwe2JavaValidator; import org.eclipse.emf.mwe2.runtime.IFactory; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.ui.IJavaElementSearchConstants; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor; import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.dialogs.SelectionDialog; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.common.types.JvmFormalParameter; import org.eclipse.xtext.common.types.JvmIdentifiableElement; import org.eclipse.xtext.common.types.JvmOperation; import org.eclipse.xtext.common.types.JvmType; import org.eclipse.xtext.ui.editor.model.edit.IModificationContext; import org.eclipse.xtext.ui.editor.model.edit.ISemanticModification; import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider; import org.eclipse.xtext.ui.editor.quickfix.Fix; import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor; import org.eclipse.xtext.validation.Issue; import com.google.inject.Inject; public class Mwe2QuickfixProvider extends DefaultQuickfixProvider { private static final Logger logger = Logger.getLogger(Mwe2QuickfixProvider.class); @Inject(optional=true) private IWorkbench workbench; @Inject private IWorkspace workspace; @Fix(Mwe2JavaValidator.ABSTRACT_OR_INTERFACE) public void assignValidType(final Issue issue, IssueResolutionAcceptor acceptor) { acceptor.accept(issue, "Define type explicitly", "Choose a compatible type for the component.", null, new ISemanticModification() { public void apply(EObject element, IModificationContext context) { Component component = (Component) element; if (component != null) { IJavaProject project = findEnclosingProject(element.eResource()); Assignment assignment = EcoreUtil2.getContainerOfType(component, Assignment.class); JvmIdentifiableElement feature = assignment.getFeature(); JvmType actualType = component.getActualType(); if (feature instanceof JvmOperation) { List<JvmFormalParameter> parameters = ((JvmOperation) feature).getParameters(); JvmFormalParameter parameter = parameters.get(0); actualType = parameter.getParameterType().getType(); } else if (feature instanceof DeclaredProperty) { actualType = ((DeclaredProperty) feature).getType(); } String type = chooseType(project, actualType); if (type != null) { JvmType jvmType = findJvmType(component, type); component.setType(jvmType); } } } }); } public static JvmType findJvmType(EObject context, String type) { URI fqnURI = JvmTypeUriFactory.getURIForFqn(type); JvmType jvmType = JvmTypeUriFactory.findJvmType(fqnURI, context); return jvmType; } public static class ComponentTypeSelectionExtension extends TypeSelectionExtension { private final String superType; public ComponentTypeSelectionExtension(String superType) { this.superType = superType; } @Override public ITypeInfoFilterExtension getFilterExtension() { return new ITypeInfoFilterExtension() { public boolean select(ITypeInfoRequestor typeInfoRequestor) { return !Flags.isAbstract(typeInfoRequestor.getModifiers()); } }; } @Override public ISelectionStatusValidator getSelectionValidator() { return new ISelectionStatusValidator() { public IStatus validate(Object[] selection) { if(selection.length == 1) { try { IType type = (IType) selection[0]; ITypeHierarchy hierarchy = type.newSupertypeHierarchy(new NullProgressMonitor()); IType curr = type; while (curr != null) { if (superType.equals(curr.getFullyQualifiedName())) { return Status.OK_STATUS; } curr = hierarchy.getSuperclass(curr); } IType[] interfaces = hierarchy.getAllSuperInterfaces(type); for(IType intf: interfaces) { if (IFactory.class.getName().equals(intf.getFullyQualifiedName())) { // TODO check right factory type return Status.OK_STATUS; } if (superType.equals(intf.getFullyQualifiedName())) { return Status.OK_STATUS; } } } catch (JavaModelException e) { logger.error(e.getMessage(), e); return Status.CANCEL_STATUS; } } return new Status(IStatus.ERROR, "org.eclipse.emf.mwe2.language.ui", "The component type must be a subtype of " + superType.replace('$', '.')); } }; } } public IJavaProject findEnclosingProject(Resource resource) { URI resourceURI = resource.getURI(); IFile file = workspace.getRoot().getFile(new Path(resourceURI.toPlatformString(true))); if (file == null) return null; IProject project = file.getProject(); if (project == null) return null; IJavaProject result = JavaCore.create(project); return result; } public String chooseType(IJavaProject project, JvmType actualType) { if (project == null) return null; IWorkbenchWindow activeWindow = workbench.getActiveWorkbenchWindow(); Shell shell = activeWindow.getShell(); try { SelectionDialog dialog = JavaUI.createTypeDialog(shell, activeWindow, SearchEngine.createJavaSearchScope(new IJavaElement[]{ project }), IJavaElementSearchConstants.CONSIDER_CLASSES, false, "", new ComponentTypeSelectionExtension(actualType.getIdentifier())); dialog.setTitle("Select component type"); dialog.setMessage("Select component type"); dialog.create(); if(dialog.open() == IDialogConstants.OK_ID) { Object[] results = dialog.getResult(); if(results != null && results.length > 0) { IType result = (IType) results[0]; return result.getFullyQualifiedName(); } } return null; } catch(JavaModelException e) { logger.error(e.getMessage(), e); return null; } } }