/******************************************************************************* * 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; } } }