/*******************************************************************************
* Copyright (c) 2005, 2017 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
*
*******************************************************************************/
package org.eclipse.dltk.ui.text.completion;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.dltk.internal.corext.util.Messages;
import org.eclipse.dltk.ui.DLTKUIPlugin;
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.osgi.framework.Bundle;
/**
* Describes a category extension to the "javaCompletionProposalComputer"
* extension point.
*/
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;
private boolean fIsSeparateCommand = true;
private boolean fIsEnabled = true;
private boolean fIsIncluded = true;
private final CompletionProposalComputerRegistry fRegistry;
private int fSortOrder = 0x10000;
private String fLastError = null;
private String fToolkitID = null;
CompletionProposalCategory(IConfigurationElement element,
CompletionProposalComputerRegistry registry) {
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;
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;
fToolkitID = element
.getAttribute(CompletionProposalComputerDescriptor.TOOLKITID);
}
CompletionProposalCategory(String id, String name,
CompletionProposalComputerRegistry registry, String toolkitID) {
fRegistry = registry;
fId = id;
fName = name;
fElement = null;
fImage = null;
fToolkitID = toolkitID;
}
private Bundle getBundle() {
String namespace = fElement.getDeclaringExtension().getContributor()
.getName();
Bundle bundle = Platform.getBundle(namespace);
return bundle;
}
/**
* Checks an element that must be defined according to the extension point
* schema. Throws an <code>InvalidRegistryObjectException</code> if
* <code>obj</code> is <code>null</code>.
*/
private void checkNotNull(Object obj, String attribute)
throws InvalidRegistryObjectException {
if (obj == null) {
Object[] args = { getId(), fElement.getContributor().getName(),
attribute };
String message = Messages.format(
ScriptTextMessages.CompletionProposalComputerDescriptor_illegal_attribute_message,
args);
IStatus status = new Status(IStatus.WARNING, DLTKUIPlugin.PLUGIN_ID,
IStatus.OK, message, null);
DLTKUIPlugin.log(status);
throw new InvalidRegistryObjectException();
}
}
/**
* 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;
}
/**
* 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 IScriptCompletionProposalComputer}, 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,
IProgressMonitor monitor) {
fLastError = null;
List<ICompletionProposal> result = new ArrayList<>();
List<CompletionProposalComputerDescriptor> descriptors = new ArrayList<>(
fRegistry.getProposalComputerDescriptors(partition));
for (Iterator<CompletionProposalComputerDescriptor> it = descriptors
.iterator(); it.hasNext();) {
CompletionProposalComputerDescriptor desc = it.next();
if (context instanceof ScriptContentAssistInvocationContext) {
ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context;
if (!scriptContext.getLanguageNatureID()
.equals(desc.getLanguageToolkitID())) {
continue;
}
}
if (desc.getCategory() == this)
result.addAll(
desc.computeCompletionProposals(context, monitor));
if (fLastError == 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 IScriptCompletionProposalComputer}, 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,
IProgressMonitor monitor) {
fLastError = null;
List<IContextInformation> result = new ArrayList<>();
List<CompletionProposalComputerDescriptor> descriptors = new ArrayList<>(
fRegistry.getProposalComputerDescriptors(partition));
for (Iterator<CompletionProposalComputerDescriptor> it = descriptors
.iterator(); it.hasNext();) {
CompletionProposalComputerDescriptor desc = it.next();
if (context instanceof ScriptContentAssistInvocationContext) {
ScriptContentAssistInvocationContext scriptContext = (ScriptContentAssistInvocationContext) context;
if (!scriptContext.getLanguageNatureID()
.equals(desc.getLanguageToolkitID())) {
continue;
}
}
if (desc.getCategory() == this)
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<>(
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<>(
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();
}
}
public String getToolkitID() {
return fToolkitID;
}
}