--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 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
+ * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.ui.text.correction;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+
+import org.eclipse.text.edits.TextEdit;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableContext;
+
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.progress.IProgressService;
+
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+
+import org.eclipse.jdt.core.ClasspathContainerInitializer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageDeclaration;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.ImportDeclaration;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.Type;
+
+import org.eclipse.jdt.internal.corext.codemanipulation.AddImportsOperation;
+import org.eclipse.jdt.internal.corext.codemanipulation.AddImportsOperation.IChooseImportQuery;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.IProposableFix;
+import org.eclipse.jdt.internal.corext.fix.UnusedCodeFix;
+import org.eclipse.jdt.internal.corext.refactoring.changes.CreatePackageChange;
+import org.eclipse.jdt.internal.corext.refactoring.changes.MoveCompilationUnitChange;
+import org.eclipse.jdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+import org.eclipse.jdt.internal.corext.util.Messages;
+
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.IVMInstall2;
+import org.eclipse.jdt.launching.IVMInstallType;
+import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
+import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
+
+import org.eclipse.jdt.ui.JavaElementLabels;
+import org.eclipse.jdt.ui.actions.OrganizeImportsAction;
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
+import org.eclipse.jdt.ui.text.java.IInvocationContext;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal;
+import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal;
+import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
+
+import org.eclipse.jdt.internal.ui.JavaPlugin;
+import org.eclipse.jdt.internal.ui.JavaPluginImages;
+import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
+import org.eclipse.jdt.internal.ui.fix.UnusedCodeCleanUp;
+import org.eclipse.jdt.internal.ui.javaeditor.AddImportOnSelectionAction;
+import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
+import org.eclipse.jdt.internal.ui.preferences.BuildPathsPropertyPage;
+import org.eclipse.jdt.internal.ui.text.correction.proposals.CorrectMainTypeNameProposal;
+import org.eclipse.jdt.internal.ui.text.correction.proposals.CorrectPackageDeclarationProposal;
+import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal;
+import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
+import org.eclipse.jdt.internal.ui.util.CoreUtility;
+import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
+import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement;
+import org.eclipse.jdt.internal.ui.wizards.buildpaths.ClasspathFixSelectionDialog;
+
+public class ReorgCorrectionsSubProcessor {
+
+ public static void getWrongTypeNameProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
+ ICompilationUnit cu= context.getCompilationUnit();
+ boolean isLinked= cu.getResource().isLinked();
+
+ IJavaProject javaProject= cu.getJavaProject();
+ String sourceLevel= javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
+ String compliance= javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+
+ CompilationUnit root= context.getASTRoot();
+
+ ASTNode coveredNode= problem.getCoveredNode(root);
+ if (!(coveredNode instanceof SimpleName))
+ return;
+
+ ASTNode parentType= coveredNode.getParent();
+ if (!(parentType instanceof AbstractTypeDeclaration))
+ return;
+
+ String currTypeName= ((SimpleName) coveredNode).getIdentifier();
+ String newTypeName= JavaCore.removeJavaLikeExtension(cu.getElementName());
+
+ boolean hasOtherPublicTypeBefore= false;
+
+ boolean found= false;
+ List<AbstractTypeDeclaration> types= root.types();
+ for (int i= 0; i < types.size(); i++) {
+ AbstractTypeDeclaration curr= types.get(i);
+ if (parentType != curr) {
+ if (newTypeName.equals(curr.getName().getIdentifier())) {
+ return;
+ }
+ if (!found && Modifier.isPublic(curr.getModifiers())) {
+ hasOtherPublicTypeBefore= true;
+ }
+ } else {
+ found= true;
+ }
+ }
+ if (!JavaConventions.validateJavaTypeName(newTypeName, sourceLevel, compliance).matches(IStatus.ERROR)) {
+ proposals.add(new CorrectMainTypeNameProposal(cu, context, currTypeName, newTypeName, 5));
+ }
+
+ if (!hasOtherPublicTypeBefore) {
+ String newCUName= JavaModelUtil.getRenamedCUName(cu, currTypeName);
+ ICompilationUnit newCU= ((IPackageFragment) (cu.getParent())).getCompilationUnit(newCUName);
+ if (!newCU.exists() && !isLinked && !JavaConventions.validateCompilationUnitName(newCUName, sourceLevel, compliance).matches(IStatus.ERROR)) {
+ RenameCompilationUnitChange change= new RenameCompilationUnitChange(cu, newCUName);
+
+ // rename CU
+ String label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_renamecu_description, BasicElementLabels.getResourceName(newCUName));
+ proposals.add(new ChangeCorrectionProposal(label, change, 6, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME)));
+ }
+ }
+ }
+
+ public static void getWrongPackageDeclNameProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
+ ICompilationUnit cu= context.getCompilationUnit();
+ boolean isLinked= cu.getResource().isLinked();
+
+ // correct package declaration
+ int relevance= cu.getPackageDeclarations().length == 0 ? 7 : 5; // bug 38357
+ proposals.add(new CorrectPackageDeclarationProposal(cu, problem, relevance));
+
+ // move to package
+ IPackageDeclaration[] packDecls= cu.getPackageDeclarations();
+ String newPackName= packDecls.length > 0 ? packDecls[0].getElementName() : ""; //$NON-NLS-1$
+
+ IPackageFragmentRoot root= JavaModelUtil.getPackageFragmentRoot(cu);
+ IPackageFragment newPack= root.getPackageFragment(newPackName);
+
+ ICompilationUnit newCU= newPack.getCompilationUnit(cu.getElementName());
+ if (!newCU.exists() && !isLinked) {
+ String label;
+ if (newPack.isDefaultPackage()) {
+ label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_movecu_default_description, BasicElementLabels.getFileName(cu));
+ } else {
+ String packageLabel= JavaElementLabels.getElementLabel(newPack, JavaElementLabels.ALL_DEFAULT);
+ label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_movecu_description, new Object[] { BasicElementLabels.getFileName(cu), packageLabel });
+ }
+ CompositeChange composite= new CompositeChange(label);
+ composite.add(new CreatePackageChange(newPack));
+ composite.add(new MoveCompilationUnitChange(cu, newPack));
+
+ proposals.add(new ChangeCorrectionProposal(label, composite, 6, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_MOVE)));
+ }
+ }
+
+ public static void removeImportStatementProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
+ IProposableFix fix= UnusedCodeFix.createRemoveUnusedImportFix(context.getASTRoot(), problem);
+ if (fix != null) {
+ Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_DELETE_IMPORT);
+ Map<String, String> options= new Hashtable<String, String>();
+ options.put(CleanUpConstants.REMOVE_UNUSED_CODE_IMPORTS, CleanUpOptions.TRUE);
+ FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new UnusedCodeCleanUp(options), 6, image, context);
+ proposals.add(proposal);
+ }
+
+ final ICompilationUnit cu= context.getCompilationUnit();
+ String name= CorrectionMessages.ReorgCorrectionsSubProcessor_organizeimports_description;
+ ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(name, null, 5, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)) {
+ @Override
+ public void apply(IDocument document) {
+ IEditorInput input= new FileEditorInput((IFile) cu.getResource());
+ IWorkbenchPage p= JavaPlugin.getActivePage();
+ if (p == null) {
+ return;
+ }
+ IEditorPart part= p.findEditor(input);
+ if (part instanceof JavaEditor) {
+ OrganizeImportsAction action= new OrganizeImportsAction((JavaEditor) part);
+ action.run(cu);
+ }
+ }
+ };
+ proposals.add(proposal);
+ }
+
+ public static class ClasspathFixCorrectionProposal extends CUCorrectionProposal {
+
+ private final int fOffset;
+ private final int fLength;
+ private final String fMissingType;
+
+ private TextEdit fResultingEdit;
+
+ public ClasspathFixCorrectionProposal(ICompilationUnit cu, int offset, int length, String missingType) {
+ super(CorrectionMessages.ReorgCorrectionsSubProcessor_project_seup_fix_description, cu, -10, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
+ fOffset= offset;
+ fLength= length;
+ fMissingType= missingType;
+ }
+
+ @Override
+ public void apply(IDocument document) {
+ IRunnableContext context= JavaPlugin.getActiveWorkbenchWindow();
+ if (context == null) {
+ context= new BusyIndicatorRunnableContext();
+ }
+ Shell shell= JavaPlugin.getActiveWorkbenchShell();
+ if (ClasspathFixSelectionDialog.openClasspathFixSelectionDialog(shell, getCompilationUnit().getJavaProject(), fMissingType, context)) {
+ if (fMissingType.indexOf('.') == -1) {
+ try {
+ IChooseImportQuery query= AddImportOnSelectionAction.newDialogQuery(shell);
+ AddImportsOperation op= new AddImportsOperation(getCompilationUnit(), fOffset, fLength, query, false, false);
+ IProgressService progressService= PlatformUI.getWorkbench().getProgressService();
+ progressService.runInUI(context, new WorkbenchRunnableAdapter(op, op.getScheduleRule()), op.getScheduleRule());
+ fResultingEdit= op.getResultingEdit();
+ super.apply(document);
+ } catch (InvocationTargetException e) {
+ JavaPlugin.log(e);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void addEdits(IDocument document, TextEdit editRoot) throws CoreException {
+ if (fResultingEdit != null) {
+ editRoot.addChild(fResultingEdit);
+ }
+ }
+
+ @Override
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_project_seup_fix_info, BasicElementLabels.getJavaElementName(fMissingType));
+ }
+ }
+
+ public static void addProjectSetupFixProposal(IInvocationContext context, IProblemLocation problem, String missingType, Collection<ICommandAccess> proposals) {
+ proposals.add(new ClasspathFixCorrectionProposal(context.getCompilationUnit(), problem.getOffset(), problem.getLength(), missingType));
+ }
+
+
+ public static void importNotFoundProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
+ ICompilationUnit cu= context.getCompilationUnit();
+
+ ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot());
+ if (selectedNode == null) {
+ return;
+ }
+ ImportDeclaration importDeclaration= (ImportDeclaration) ASTNodes.getParent(selectedNode, ASTNode.IMPORT_DECLARATION);
+ if (importDeclaration == null) {
+ return;
+ }
+ if (!importDeclaration.isOnDemand()) {
+ Name name= importDeclaration.getName();
+ if (importDeclaration.isStatic() && name.isQualifiedName()) {
+ name= ((QualifiedName) name).getQualifier();
+ }
+ int kind= JavaModelUtil.is50OrHigher(cu.getJavaProject()) ? SimilarElementsRequestor.REF_TYPES : SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
+ UnresolvedElementsSubProcessor.addNewTypeProposals(cu, name, kind, 5, proposals);
+ }
+
+ String name= ASTNodes.asString(importDeclaration.getName());
+ if (importDeclaration.isOnDemand()) {
+ name= JavaModelUtil.concatenateName(name, "*"); //$NON-NLS-1$
+ }
+ addProjectSetupFixProposal(context, problem, name, proposals);
+ }
+
+ private static final class OpenBuildPathCorrectionProposal extends ChangeCorrectionProposal {
+ private final IProject fProject;
+ private final IBinding fReferencedType;
+ private OpenBuildPathCorrectionProposal(IProject project, String label, int relevance, IBinding referencedType) {
+ super(label, null, relevance, null);
+ fProject= project;
+ fReferencedType= referencedType;
+ setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_ACCESSRULES_ATTRIB));
+ }
+ @Override
+ public void apply(IDocument document) {
+ Map<Object, Object> data= null;
+ if (fReferencedType != null) {
+ IJavaElement elem= fReferencedType.getJavaElement();
+ if (elem != null) {
+ IPackageFragmentRoot root= (IPackageFragmentRoot) elem.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+ if (root != null) {
+ try {
+ IClasspathEntry entry= root.getRawClasspathEntry();
+ if (entry != null) {
+ data= new HashMap<Object, Object>(1);
+ data.put(BuildPathsPropertyPage.DATA_REVEAL_ENTRY, entry);
+ if (entry.getEntryKind() != IClasspathEntry.CPE_CONTAINER) {
+ data.put(BuildPathsPropertyPage.DATA_REVEAL_ATTRIBUTE_KEY, CPListElement.ACCESSRULES);
+ }
+ }
+ } catch (JavaModelException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ PreferencesUtil.createPropertyDialogOn(JavaPlugin.getActiveWorkbenchShell(), fProject, BuildPathsPropertyPage.PROP_ID, null, data).open();
+ }
+ /*
+ * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension5#getAdditionalProposalInfo(org.eclipse.core.runtime.IProgressMonitor)
+ * @since 3.5
+ */
+ @Override
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_configure_buildpath_description, BasicElementLabels.getResourceName(fProject));
+ }
+ }
+
+ private static final class ChangeToRequiredCompilerCompliance extends ChangeCorrectionProposal implements IWorkspaceRunnable {
+
+ private final IJavaProject fProject;
+ private final boolean fChangeOnWorkspace;
+ private final String fRequiredVersion;
+
+ private Job fUpdateJob;
+ private boolean fRequiredJREFound;
+
+ public ChangeToRequiredCompilerCompliance(String name, IJavaProject project, boolean changeOnWorkspace, String requiredVersion, int relevance) {
+ super(name, null, relevance, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
+ fProject= project;
+ fChangeOnWorkspace= changeOnWorkspace;
+ fRequiredVersion= requiredVersion;
+ fUpdateJob= null;
+ fRequiredJREFound= false;
+ }
+
+ private boolean isRequiredOrGreaterVMInstall(IVMInstall install) {
+ if (install instanceof IVMInstall2) {
+ String compliance= JavaModelUtil.getCompilerCompliance((IVMInstall2) install, JavaCore.VERSION_1_3);
+ return !JavaModelUtil.isVersionLessThan(compliance, fRequiredVersion);
+ }
+ return false;
+ }
+
+ private String getVMInstallCompliance(IVMInstall install) {
+ if (install instanceof IVMInstall2) {
+ String compliance= JavaModelUtil.getCompilerCompliance((IVMInstall2) install, JavaCore.VERSION_1_3);
+ return compliance;
+ }
+ return JavaCore.VERSION_1_1;
+ }
+
+ private IVMInstall findRequiredOrGreaterVMInstall() {
+ String bestMatchingCompliance= null;
+ IVMInstall bestMatchingVMInstall= null;
+ IVMInstallType[] installTypes= JavaRuntime.getVMInstallTypes();
+ for (int i= 0; i < installTypes.length; i++) {
+ IVMInstall[] installs= installTypes[i].getVMInstalls();
+ for (int k= 0; k < installs.length; k++) {
+ String vmInstallCompliance= getVMInstallCompliance(installs[k]);
+
+ if (fRequiredVersion.equals(vmInstallCompliance)) {
+ return installs[k]; // perfect match
+
+ } else if (JavaModelUtil.isVersionLessThan(vmInstallCompliance, fRequiredVersion)) {
+ continue; // no match
+
+ } else if (bestMatchingVMInstall != null) {
+ if (JavaModelUtil.isVersionLessThan(bestMatchingCompliance, vmInstallCompliance)) {
+ continue; // the other one is the least matching
+ }
+ }
+ bestMatchingCompliance= vmInstallCompliance;
+ bestMatchingVMInstall= installs[k];
+ }
+ }
+ return null;
+ }
+
+ public void run(IProgressMonitor monitor) throws CoreException {
+ boolean needsBuild= updateJRE(monitor);
+ if (needsBuild) {
+ fUpdateJob= CoreUtility.getBuildJob(fChangeOnWorkspace ? null : fProject.getProject());
+ }
+ }
+
+ private boolean updateJRE( IProgressMonitor monitor) throws CoreException, JavaModelException {
+ // Caveat: Returns true iff the classpath has not been changed.
+ // If the classpath is changed, JDT Core triggers a build for free.
+ // If the classpath is not changed, we have to trigger a build because we changed
+ // the compiler compliance in #apply(IDocument).
+ try {
+ if (fChangeOnWorkspace) {
+ IVMInstall vmInstall= findRequiredOrGreaterVMInstall();
+ fRequiredJREFound= vmInstall != null;
+ if (vmInstall != null) {
+ IVMInstall install= JavaRuntime.getVMInstall(fProject); // can be null
+ monitor.beginTask(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_operation, 4);
+ IVMInstall defaultVM= JavaRuntime.getDefaultVMInstall(); // can be null
+ if (defaultVM != null && !defaultVM.equals(install)) {
+ IPath newPath= new Path(JavaRuntime.JRE_CONTAINER);
+ updateClasspath(newPath, new SubProgressMonitor(monitor, 1));
+ } else {
+ monitor.worked(1);
+ }
+ if (defaultVM == null || !isRequiredOrGreaterVMInstall(defaultVM)) {
+ JavaRuntime.setDefaultVMInstall(vmInstall, new SubProgressMonitor(monitor, 3), true);
+ return false;
+ }
+ return true;
+ }
+
+ } else {
+ IExecutionEnvironment bestEE= findBestMatchingEE();
+ fRequiredJREFound= bestEE != null;
+ if (bestEE != null) {
+ IPath newPath= JavaRuntime.newJREContainerPath(bestEE);
+ boolean classpathUpdated= updateClasspath(newPath, monitor);
+ return !classpathUpdated;
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+ return true;
+ }
+
+ private IExecutionEnvironment findBestMatchingEE() {
+ IExecutionEnvironmentsManager eeManager= JavaRuntime.getExecutionEnvironmentsManager();
+ IExecutionEnvironment[] ees= eeManager.getExecutionEnvironments();
+ IExecutionEnvironment bestEE= null;
+ String bestEECompliance= null;
+
+ for (int i= 0; i < ees.length; i++) {
+ IExecutionEnvironment ee= ees[i];
+ String eeCompliance= JavaModelUtil.getExecutionEnvironmentCompliance(ee);
+ String eeId= ee.getId();
+
+ if (fRequiredVersion.equals(eeCompliance)) {
+ if (eeId.startsWith("J") && eeId.endsWith(fRequiredVersion)) { //$NON-NLS-1$
+ bestEE= ee;
+ break; // perfect match
+ }
+
+ } else if (JavaModelUtil.isVersionLessThan(eeCompliance, fRequiredVersion)) {
+ continue; // no match
+
+ } else { // possible match
+ if (bestEE != null) {
+ if (! eeId.startsWith("J")) { //$NON-NLS-1$
+ continue; // avoid taking e.g. OSGi profile if a Java profile is available
+ }
+ if (JavaModelUtil.isVersionLessThan(bestEECompliance, eeCompliance)) {
+ continue; // the other one is the least matching
+ }
+ }
+ }
+ // found a new best
+ bestEE= ee;
+ bestEECompliance= eeCompliance;
+ }
+ return bestEE;
+ }
+
+ private boolean updateClasspath(IPath newPath, IProgressMonitor monitor) throws JavaModelException {
+ boolean updated= false;
+
+ IClasspathEntry[] classpath= fProject.getRawClasspath();
+ IPath jreContainerPath= new Path(JavaRuntime.JRE_CONTAINER);
+ for (int i= 0; i < classpath.length; i++) {
+ IClasspathEntry curr= classpath[i];
+ if (curr.getEntryKind() == IClasspathEntry.CPE_CONTAINER && curr.getPath().matchingFirstSegments(jreContainerPath) > 0) {
+ if (! newPath.equals(curr.getPath())) {
+ updated= true;
+ classpath[i]= JavaCore.newContainerEntry(newPath, curr.getAccessRules(), curr.getExtraAttributes(), curr.isExported());
+ }
+ }
+ }
+ if (updated) {
+ fProject.setRawClasspath(classpath, monitor);
+ }
+ return updated;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
+ */
+ @Override
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ StringBuffer message= new StringBuffer();
+ if (fChangeOnWorkspace) {
+ message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_required_compliance_changeworkspace_description, fRequiredVersion));
+ } else {
+ message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_required_compliance_changeproject_description, fRequiredVersion));
+ }
+
+ try {
+ IVMInstall install= JavaRuntime.getVMInstall(fProject); // can be null
+ if (fChangeOnWorkspace) {
+ IVMInstall vmInstall= findRequiredOrGreaterVMInstall();
+ if (vmInstall != null) {
+ IVMInstall defaultVM= JavaRuntime.getDefaultVMInstall(); // can be null
+ if (defaultVM != null && !defaultVM.equals(install)) {
+ message.append(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeProjectJREToDefault_description);
+ }
+ if (defaultVM == null || !isRequiredOrGreaterVMInstall(defaultVM)) {
+ message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeWorkspaceJRE_description, vmInstall.getName()));
+ }
+ }
+ } else {
+ IExecutionEnvironment bestEE= findBestMatchingEE();
+ if (bestEE != null) {
+ if (install == null || !isEEOnClasspath(bestEE)) {
+ message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeProjectJRE_description, bestEE.getId()));
+ }
+ }
+ }
+ } catch (CoreException e) {
+ // ignore
+ }
+ return message.toString();
+ }
+
+ private boolean isEEOnClasspath(IExecutionEnvironment ee) throws JavaModelException {
+ IPath eePath= JavaRuntime.newJREContainerPath(ee);
+
+ for (IClasspathEntry entry: fProject.getRawClasspath()) {
+ if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && entry.getPath().equals(eePath))
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(IDocument)
+ */
+ @Override
+ public void apply(IDocument document) {
+ if (fChangeOnWorkspace) {
+ Hashtable<String, String> map= JavaCore.getOptions();
+ JavaModelUtil.setComplianceOptions(map, fRequiredVersion);
+ JavaCore.setOptions(map);
+ } else {
+ Map<String, String> map= fProject.getOptions(false);
+ int optionsCount= map.size();
+ JavaModelUtil.setComplianceOptions(map, fRequiredVersion);
+ if (map.size() > optionsCount) {
+ // options have been added -> ensure that all compliance options from preference page set
+ JavaModelUtil.setDefaultClassfileOptions(map, fRequiredVersion);
+ }
+ fProject.setOptions(map);
+ }
+ try {
+ IProgressService progressService= PlatformUI.getWorkbench().getProgressService();
+ progressService.run(true, true, new WorkbenchRunnableAdapter(this));
+ } catch (InvocationTargetException e) {
+ JavaPlugin.log(e);
+ } catch (InterruptedException e) {
+ return;
+ }
+
+ if (fUpdateJob != null) {
+ fUpdateJob.schedule();
+ }
+
+ if (!fRequiredJREFound) {
+ MessageDialog.openInformation(JavaPlugin.getActiveWorkbenchShell(),
+ Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_no_required_jre_title, fRequiredVersion),
+ Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_no_required_jre_message, fRequiredVersion));
+ }
+ }
+ }
+
+ /**
+ * Adds a proposal to increase the compiler compliance level
+ * @param context the context
+ * @param problem the current problem
+ * @param proposals the resulting proposals
+ * @param requiredVersion the minimal required Java compiler version
+ */
+ public static void getNeedHigherComplianceProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals, String requiredVersion) {
+ IJavaProject project= context.getCompilationUnit().getJavaProject();
+
+ String label1= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_change_project_compliance_description, requiredVersion);
+ proposals.add(new ChangeToRequiredCompilerCompliance(label1, project, false, requiredVersion, 5));
+
+ if (project.getOption(JavaCore.COMPILER_COMPLIANCE, false) == null) {
+ String label2= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_change_workspace_compliance_description, requiredVersion);
+ proposals.add(new ChangeToRequiredCompilerCompliance(label2, project, true, requiredVersion, 6));
+ }
+ }
+
+ /**
+ * Adds a proposal that opens the build path dialog
+ * @param context the context
+ * @param problem the current problem
+ * @param proposals the resulting proposals
+ */
+ public static void getIncorrectBuildPathProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
+ IProject project= context.getCompilationUnit().getJavaProject().getProject();
+ String label= CorrectionMessages.ReorgCorrectionsSubProcessor_configure_buildpath_label;
+ OpenBuildPathCorrectionProposal proposal= new OpenBuildPathCorrectionProposal(project, label, 5, null);
+ proposals.add(proposal);
+ }
+
+ public static void getAccessRulesProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
+ IBinding referencedElement= null;
+ ASTNode node= problem.getCoveredNode(context.getASTRoot());
+ if (node instanceof Type) {
+ referencedElement= ((Type) node).resolveBinding();
+ } else if (node instanceof Name) {
+ referencedElement= ((Name) node).resolveBinding();
+ }
+ if (referencedElement != null && canModifyAccessRules(referencedElement)) {
+ IProject project= context.getCompilationUnit().getJavaProject().getProject();
+ String label= CorrectionMessages.ReorgCorrectionsSubProcessor_accessrules_description;
+ OpenBuildPathCorrectionProposal proposal= new OpenBuildPathCorrectionProposal(project, label, 5, referencedElement);
+ proposals.add(proposal);
+ }
+ }
+
+ private static boolean canModifyAccessRules(IBinding binding) {
+ IJavaElement element= binding.getJavaElement();
+ if (element == null)
+ return false;
+
+ IPackageFragmentRoot root= JavaModelUtil.getPackageFragmentRoot(element);
+ if (root == null)
+ return false;
+
+ try {
+ IClasspathEntry classpathEntry= root.getRawClasspathEntry();
+ if (classpathEntry == null)
+ return false;
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
+ return true;
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ ClasspathContainerInitializer classpathContainerInitializer= JavaCore.getClasspathContainerInitializer(classpathEntry.getPath().segment(0));
+ IStatus status= classpathContainerInitializer.getAccessRulesStatus(classpathEntry.getPath(), root.getJavaProject());
+ return status.isOK();
+ }
+ } catch (JavaModelException e) {
+ return false;
+ }
+ return false;
+ }
+
+
+}