| /******************************************************************************* |
| * Copyright (c) 2005, 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 |
| * Paul Fullbright <paul.fullbright@oracle.com> - content assist category enablement - http://bugs.eclipse.org/345213 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.text.java; |
| |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.osgi.framework.Bundle; |
| |
| import org.eclipse.core.expressions.EvaluationContext; |
| import org.eclipse.core.expressions.EvaluationResult; |
| import org.eclipse.core.expressions.Expression; |
| import org.eclipse.core.expressions.ExpressionConverter; |
| import org.eclipse.core.expressions.ExpressionTagNames; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.jface.action.LegacyActionTools; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| |
| import org.eclipse.jdt.core.IJavaProject; |
| |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; |
| import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| |
| |
| /** |
| * Describes a category extension to the "javaCompletionProposalComputer" extension point. |
| * |
| * @since 3.2 |
| */ |
| public final class CompletionProposalCategory { |
| /** The extension schema name of the icon attribute. */ |
| private static final String ICON= "icon"; //$NON-NLS-1$ |
| |
| private final String fId; |
| private final String fName; |
| private final IConfigurationElement fElement; |
| /** The image descriptor for this category, or <code>null</code> if none specified. */ |
| private final ImageDescriptor fImage; |
| |
| /** The enablement expression for this category, or <code>null</code> if none specified. */ |
| private final Expression fEnablementExpression; |
| |
| private boolean fIsSeparateCommand= true; |
| private boolean fIsEnabled= true; |
| private boolean fIsIncluded= true; |
| private final CompletionProposalComputerRegistry fRegistry; |
| |
| private int fSortOrder= 0xffff - 1; |
| private String fLastError= null; |
| |
| CompletionProposalCategory(IConfigurationElement element, CompletionProposalComputerRegistry registry) throws CoreException { |
| fElement= element; |
| fRegistry= registry; |
| IExtension parent= (IExtension) element.getParent(); |
| fId= parent.getUniqueIdentifier(); |
| checkNotNull(fId, "id"); //$NON-NLS-1$ |
| String name= parent.getLabel(); |
| if (name == null) |
| fName= fId; |
| else |
| fName= name; |
| |
| IConfigurationElement[] children= fElement.getChildren(ExpressionTagNames.ENABLEMENT); |
| if (children.length == 1) { |
| ExpressionConverter parser= ExpressionConverter.getDefault(); |
| fEnablementExpression = parser.perform(children[0]); |
| } |
| else { |
| fEnablementExpression = null; |
| } |
| |
| String icon= element.getAttribute(ICON); |
| ImageDescriptor img= null; |
| if (icon != null) { |
| Bundle bundle= getBundle(); |
| if (bundle != null) { |
| Path path= new Path(icon); |
| URL url= FileLocator.find(bundle, path, null); |
| img= ImageDescriptor.createFromURL(url); |
| } |
| } |
| fImage= img; |
| |
| } |
| |
| CompletionProposalCategory(String id, String name, CompletionProposalComputerRegistry registry) { |
| fRegistry= registry; |
| fId= id; |
| fName= name; |
| fElement= null; |
| fEnablementExpression = null; |
| fImage= null; |
| } |
| |
| private Bundle getBundle() { |
| String namespace= fElement.getDeclaringExtension().getContributor().getName(); |
| Bundle bundle= Platform.getBundle(namespace); |
| return bundle; |
| } |
| |
| /** |
| * Checks that the given attribute value is not <code>null</code>. |
| * |
| * @param value the element to be checked |
| * @param attribute the attribute |
| * @throws CoreException if <code>value</code> is <code>null</code> |
| */ |
| private void checkNotNull(Object value, String attribute) throws CoreException { |
| if (value == null) { |
| Object[] args= { getId(), fElement.getContributor().getName(), attribute }; |
| String message= Messages.format(JavaTextMessages.CompletionProposalComputerDescriptor_illegal_attribute_message, args); |
| IStatus status= new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, message, null); |
| throw new CoreException(status); |
| } |
| } |
| |
| /** |
| * Returns the identifier of the described extension. |
| * |
| * @return Returns the id |
| */ |
| public String getId() { |
| return fId; |
| } |
| |
| /** |
| * Returns the name of the described extension. |
| * |
| * @return Returns the name |
| */ |
| public String getName() { |
| return fName; |
| } |
| |
| /** |
| * Returns the name of the described extension |
| * without mnemonic hint in order to be displayed |
| * in a message. |
| * |
| * @return Returns the name |
| */ |
| public String getDisplayName() { |
| return LegacyActionTools.removeMnemonics(fName); |
| } |
| |
| /** |
| * Returns the image descriptor of the described category. |
| * |
| * @return the image descriptor of the described category |
| */ |
| public ImageDescriptor getImageDescriptor() { |
| return fImage; |
| } |
| |
| /** |
| * Sets the separate command state of the category. |
| * |
| * @param enabled the new enabled state. |
| */ |
| public void setSeparateCommand(boolean enabled) { |
| fIsSeparateCommand= enabled; |
| } |
| |
| /** |
| * Returns the enablement state of the category. |
| * |
| * @return the enablement state of the category |
| */ |
| public boolean isSeparateCommand() { |
| return fIsSeparateCommand; |
| } |
| |
| /** |
| * @param included the included |
| */ |
| public void setIncluded(boolean included) { |
| fIsIncluded= included; |
| } |
| |
| /** |
| * @return included |
| */ |
| public boolean isIncluded() { |
| return fIsIncluded; |
| } |
| |
| public boolean isEnabled() { |
| return fIsEnabled; |
| } |
| |
| public void setEnabled(boolean isEnabled) { |
| fIsEnabled= isEnabled; |
| } |
| |
| /** |
| * Returns <code>true</code> if the category contains any computers, <code>false</code> |
| * otherwise. |
| * |
| * @return <code>true</code> if the category contains any computers, <code>false</code> |
| * otherwise |
| */ |
| public boolean hasComputers() { |
| List<CompletionProposalComputerDescriptor> descriptors= fRegistry.getProposalComputerDescriptors(); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns <code>true</code> if the category contains any computers in the given partition, <code>false</code> |
| * otherwise. |
| * |
| * @param partition the partition |
| * @return <code>true</code> if the category contains any computers, <code>false</code> |
| * otherwise |
| */ |
| public boolean hasComputers(String partition) { |
| List<CompletionProposalComputerDescriptor> descriptors= fRegistry.getProposalComputerDescriptors(partition); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @return sortOrder |
| */ |
| public int getSortOrder() { |
| return fSortOrder; |
| } |
| |
| /** |
| * @param sortOrder the sortOrder |
| */ |
| public void setSortOrder(int sortOrder) { |
| fSortOrder= sortOrder; |
| } |
| |
| /** |
| * Determines if the project matches any enablement expression defined on the extension. |
| * |
| * @param javaProject the Java project against which to test the enablement expression, can be |
| * <code>null</code> |
| * @return <code>true</code> if any enablement expression matches the given project or if the |
| * project is <code>null</code> or no enablement expression is specified, |
| * <code>false</code> otherwise |
| * @since 3.8 |
| */ |
| public boolean matches(IJavaProject javaProject) { |
| if (fEnablementExpression == null) { |
| return true; |
| } |
| |
| if (javaProject == null) { |
| return false; |
| } |
| |
| try { |
| EvaluationContext evalContext= new EvaluationContext(null, javaProject); |
| evalContext.addVariable("project", javaProject); //$NON-NLS-1$ |
| return fEnablementExpression.evaluate(evalContext) == EvaluationResult.TRUE; |
| } catch (CoreException e) { |
| JavaPlugin.log(e); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Safely computes completion proposals of all computers of this category through their |
| * extension. If an extension is disabled, throws an exception or otherwise does not adhere to |
| * the contract described in {@link IJavaCompletionProposalComputer}, it is disabled. |
| * |
| * @param context the invocation context passed on to the extension |
| * @param partition the partition type where to invocation occurred |
| * @param monitor the progress monitor passed on to the extension |
| * @return the list of computed completion proposals (element type: |
| * {@link org.eclipse.jface.text.contentassist.ICompletionProposal}) |
| */ |
| public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context, String partition, SubProgressMonitor monitor) { |
| fLastError= null; |
| List<ICompletionProposal> result= new ArrayList<ICompletionProposal>(); |
| List<CompletionProposalComputerDescriptor> descriptors= new ArrayList<CompletionProposalComputerDescriptor>(fRegistry.getProposalComputerDescriptors(partition)); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this) |
| result.addAll(desc.computeCompletionProposals(context, monitor)); |
| if (fLastError == null && desc.getErrorMessage() != null) |
| fLastError= desc.getErrorMessage(); |
| } |
| return result; |
| } |
| |
| /** |
| * Safely computes context information objects of all computers of this category through their |
| * extension. If an extension is disabled, throws an exception or otherwise does not adhere to |
| * the contract described in {@link IJavaCompletionProposalComputer}, it is disabled. |
| * |
| * @param context the invocation context passed on to the extension |
| * @param partition the partition type where to invocation occurred |
| * @param monitor the progress monitor passed on to the extension |
| * @return the list of computed context information objects (element type: |
| * {@link org.eclipse.jface.text.contentassist.IContextInformation}) |
| */ |
| public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context, String partition, SubProgressMonitor monitor) { |
| fLastError= null; |
| List<IContextInformation> result= new ArrayList<IContextInformation>(); |
| List<CompletionProposalComputerDescriptor> descriptors= new ArrayList<CompletionProposalComputerDescriptor>(fRegistry.getProposalComputerDescriptors(partition)); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this && (isIncluded() || isSeparateCommand())) |
| result.addAll(desc.computeContextInformation(context, monitor)); |
| if (fLastError == null) |
| fLastError= desc.getErrorMessage(); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the error message from the computers in this category. |
| * |
| * @return the error message from the computers in this category |
| */ |
| public String getErrorMessage() { |
| return fLastError; |
| } |
| |
| /** |
| * Notifies the computers in this category of a proposal computation session start. |
| */ |
| public void sessionStarted() { |
| List<CompletionProposalComputerDescriptor> descriptors= new ArrayList<CompletionProposalComputerDescriptor>(fRegistry.getProposalComputerDescriptors()); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this) |
| desc.sessionStarted(); |
| if (fLastError == null) |
| fLastError= desc.getErrorMessage(); |
| } |
| } |
| |
| /** |
| * Notifies the computers in this category of a proposal computation session end. |
| */ |
| public void sessionEnded() { |
| List<CompletionProposalComputerDescriptor> descriptors= new ArrayList<CompletionProposalComputerDescriptor>(fRegistry.getProposalComputerDescriptors()); |
| for (Iterator<CompletionProposalComputerDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| CompletionProposalComputerDescriptor desc= it.next(); |
| if (desc.getCategory() == this) |
| desc.sessionEnded(); |
| if (fLastError == null) |
| fLastError= desc.getErrorMessage(); |
| } |
| } |
| |
| } |