/*******************************************************************************
* Copyright (c) 2007, 2008 Dakshinamurthy Karra, 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:
* Dakshinamurthy Karra (Jalian Systems)
*******************************************************************************/
package org.eclipse.ui.examples.templateeditor.editors;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
/**
*
A ContentAssistantProcessor that stores a list of other processors and their names. When this processor
* is attached to a ContentAssistant, the user is allowed to cycle through the different categories for
* selecting a suggestion.
*
*
Typical Usage:
*
* CategorizedContentAssistProcessor categorizedProcessor = new CategorizedContentAssistProcessor(assistant);
* categorizedProcessor.addContentAssistantProcessor(processor, "XML Completion");
* categorizedProcessor.addContentAssistantProcessor(processor2, "Java Completion");
* assistant.setContentAssistProcessor(categorizedProcessor, IDocument.DEFAULT_CONTENT_TYPE);
*
*
* Note: If the auto activation characters of two processors overlap, the first processor is activated.
*/
public class CategorizedContentAssistProcessor implements IContentAssistProcessor, ICompletionListener {
private static final int COMPLETION = 1;
private static final int CONTEXT = 2;
private final ContentAssistant fContentAssistant;
private final List fProcessors;
private final List fCategoryNames;
private char[] fCompletionAutoActivationCharacters;
private char[] fContextAutoActivationCharacters;
private IContentAssistProcessor fCurrentProcessor;
private int fCurrentOffset = -1;
private boolean fEventAutoactivated;
/**
* Create a new {@link CategorizedContentAssistProcessor} for this content assistant.
*
* @param contentAssistant
*/
public CategorizedContentAssistProcessor(ContentAssistant contentAssistant) {
fContentAssistant = contentAssistant;
fContentAssistant.setEmptyMessage("No suggestions available"); //$NON-NLS-1$
fContentAssistant.addCompletionListener(this);
fProcessors = new ArrayList();
fCategoryNames = new ArrayList();
}
/**
* Add a {@link IContentAssistProcessor} to this processor.
*
* @param processor the processor to be included
* @param categoryName the name of the category
*/
public void addContentAssistantProcessor(IContentAssistProcessor processor, String categoryName) {
fProcessors.add(processor);
fCategoryNames.add(categoryName);
if (fCurrentProcessor == null)
fCurrentProcessor = processor;
addChars(processor.getCompletionProposalAutoActivationCharacters(), COMPLETION);
addChars(processor.getContextInformationAutoActivationCharacters(), CONTEXT);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContentAssistProcessor#
* computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
*/
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
if (fEventAutoactivated) {
fCurrentProcessor = findProcessor(getActivationChar(viewer, offset), COMPLETION);
fEventAutoactivated = false;
}
if (fCurrentOffset != offset)
fCurrentOffset = offset;
else if (fCurrentOffset == offset)
fCurrentProcessor = getNextProcessor();
fContentAssistant.setStatusMessage("Next: " + fCategoryNames.get(fProcessors.indexOf(getNextProcessor()))); //$NON-NLS-1$
return fCurrentProcessor.computeCompletionProposals(viewer, offset);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContentAssistProcessor#
* computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
*/
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
if (fEventAutoactivated) {
fCurrentProcessor = findProcessor(getActivationChar(viewer, offset), CONTEXT);
fEventAutoactivated = false;
}
return fCurrentProcessor.computeContextInformation(viewer, offset);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContentAssistProcessor#
* getCompletionProposalAutoActivationCharacters()
*/
public char[] getCompletionProposalAutoActivationCharacters() {
return fCompletionAutoActivationCharacters;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContentAssistProcessor#
* getContextInformationAutoActivationCharacters()
*/
public char[] getContextInformationAutoActivationCharacters() {
return fContextAutoActivationCharacters;
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.jface.text.contentassist.IContentAssistProcessor#
* getContextInformationValidator()
*/
public IContextInformationValidator getContextInformationValidator() {
return fCurrentProcessor.getContextInformationValidator();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage
* ()
*/
public String getErrorMessage() {
return fCurrentProcessor.getErrorMessage();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionEnded
* (org.eclipse.jface.text.contentassist.ContentAssistEvent)
*/
public void assistSessionEnded(ContentAssistEvent event) {
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionStarted
* (org.eclipse.jface.text.contentassist.ContentAssistEvent)
*/
public void assistSessionStarted(ContentAssistEvent event) {
Assert.isTrue(fProcessors.size() > 0);
fEventAutoactivated = event.isAutoActivated;
if (fProcessors.size() == 1) {
fContentAssistant.setShowEmptyList(false);
fContentAssistant.setRepeatedInvocationMode(false);
fContentAssistant.setStatusLineVisible(false);
} else {
fContentAssistant.setShowEmptyList(true);
fContentAssistant.setRepeatedInvocationMode(true);
fContentAssistant.setStatusLineVisible(true);
}
fCurrentProcessor = (IContentAssistProcessor) fProcessors.get(0);
fCurrentOffset = -1;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.text.contentassist.ICompletionListener#selectionChanged
* (org.eclipse.jface.text.contentassist.ICompletionProposal, boolean)
*/
public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
}
private void addChars(char[] cs, int type) {
if (cs == null)
return;
char[] current;
if (type == COMPLETION)
current = fCompletionAutoActivationCharacters;
else
current = fContextAutoActivationCharacters;
char[] nchars = new char[(current != null ? current.length : 0) + cs.length];
if (current != null)
System.arraycopy(current, 0, nchars, 0, current.length);
System.arraycopy(cs, 0, nchars, current != null ? current.length : 0, cs.length);
if (type == COMPLETION)
fCompletionAutoActivationCharacters = nchars;
else
fContextAutoActivationCharacters = nchars;
}
private IContentAssistProcessor getNextProcessor() {
int index = fProcessors.indexOf(fCurrentProcessor);
if (index == fProcessors.size() - 1)
index = 0;
else
index++;
IContentAssistProcessor processor = (IContentAssistProcessor) fProcessors.get(index);
return processor;
}
private IContentAssistProcessor findProcessor(char activationChar, int type) {
if (activationChar == 0)
return fCurrentProcessor;
for (Iterator iterator = fProcessors.iterator(); iterator.hasNext();) {
IContentAssistProcessor processor = (IContentAssistProcessor) iterator.next();
char[] cs;
if (type == COMPLETION)
cs = processor.getCompletionProposalAutoActivationCharacters();
else
cs = processor.getContextInformationAutoActivationCharacters();
if (cs != null) {
for (int i = 0; i < cs.length; i++) {
if (cs[i] == activationChar)
return processor;
}
}
}
return fCurrentProcessor;
}
private char getActivationChar(ITextViewer viewer, int offset) {
try {
return viewer.getTextWidget().getText(offset - 1, offset).charAt(0);
} catch (Throwable t) {
return 0;
}
}
}