/******************************************************************************* * Copyright (c) 2007 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 *******************************************************************************/ package org.eclipse.wst.sse.ui.internal.correction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredPartitioning; import org.eclipse.wst.sse.ui.internal.ExtendedConfigurationBuilder; import org.eclipse.wst.sse.ui.internal.Logger; /** * A quick assist processor that will allow for more than one quick assist * processor. It includes quick assist processors contributed via the * quickAssistProcessor extended configuration extension point. It also * includes quick assist processors contributed via validators. */ public class CompoundQuickAssistProcessor implements IQuickAssistProcessor { private final String QUICK_ASSIST_PROCESSOR_EXTENDED_ID = IQuickAssistProcessor.class.getName(); private Map fProcessors; private IQuickAssistProcessor fQuickFixProcessor; /** * list of partition types where extended processors have been installed */ private List fInstalledExtendedContentTypes; private Set getQuickAssistProcessors(String partitionType) { if (fInstalledExtendedContentTypes == null || !fInstalledExtendedContentTypes.contains(partitionType)) { // get extended quick assist processors that have not already // been set List processors = ExtendedConfigurationBuilder.getInstance().getConfigurations(QUICK_ASSIST_PROCESSOR_EXTENDED_ID, partitionType); if (processors != null && !processors.isEmpty()) { Iterator iter = processors.iterator(); while (iter.hasNext()) { IQuickAssistProcessor processor = (IQuickAssistProcessor) iter.next(); setQuickAssistProcessor(partitionType, processor); } } // add partition type to list of extended partition types // installed (regardless of whether or not any extended content // assist processors were installed because dont want to look it // up every time) if (fInstalledExtendedContentTypes == null) fInstalledExtendedContentTypes = new ArrayList(); fInstalledExtendedContentTypes.add(partitionType); } Set processors = null; if (fProcessors != null) processors = (Set) fProcessors.get(partitionType); return processors; } /** * Gets all the quick assist processors relevant to the partion which is * calcuated from the given document and offset. * * @param invocationContext * @return Set of quick assist processors or null if none exist */ private Set getQuickAssistProcessors(IQuickAssistInvocationContext invocationContext) { Set processsors = null; ISourceViewer sourceViewer = invocationContext.getSourceViewer(); if (sourceViewer != null) { IDocument document = sourceViewer.getDocument(); try { String partitionType; if (document != null) partitionType = TextUtilities.getContentType(document, IStructuredPartitioning.DEFAULT_STRUCTURED_PARTITIONING, invocationContext.getOffset(), true); else partitionType = IDocument.DEFAULT_CONTENT_TYPE; processsors = getQuickAssistProcessors(partitionType); } catch (BadLocationException x) { Logger.log(Logger.WARNING_DEBUG, x.getMessage(), x); } } return processsors; } /** * Gets the quick assist processor for validator contributed quick fixes * * @return IQuickAssistProcessor */ private IQuickAssistProcessor getQuickFixProcessor() { if (fQuickFixProcessor == null) fQuickFixProcessor = new SourceValidationQuickAssistProcessor(); return fQuickFixProcessor; } /** * Associates a quick assist processor to a partition type and adds it to * the list of processors in this compound processor. * * @param partitionType * @param processor */ private void setQuickAssistProcessor(String partitionType, IQuickAssistProcessor processor) { if (fProcessors == null) fProcessors = new HashMap(); Set processors = (Set) fProcessors.get(partitionType); if (processor == null && processors != null) { // removing quick assist processor for this partition type processors.clear(); // check if it's the only fProcessors.remove(partitionType); } else { if (processors == null) { processors = new LinkedHashSet(); } processors.add(processor); fProcessors.put(partitionType, processors); } } public boolean canAssist(IQuickAssistInvocationContext invocationContext) { Set processors = getQuickAssistProcessors(invocationContext); if (processors != null) { // iterate through list of processors until one processor says // canAssist for (Iterator it = processors.iterator(); it.hasNext();) { IQuickAssistProcessor p = (IQuickAssistProcessor) it.next(); if (p.canAssist(invocationContext)) return true; } } return false; } public boolean canFix(Annotation annotation) { // only quick fix processor contributes fixes so just check it IQuickAssistProcessor processor = getQuickFixProcessor(); return processor.canFix(annotation); } public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) { List proposalsList = new ArrayList(); // first get list of fixes IQuickAssistProcessor processor = getQuickFixProcessor(); ICompletionProposal[] proposals = processor.computeQuickAssistProposals(invocationContext); if (proposals != null && proposals.length > 0) { proposalsList.addAll(Arrays.asList(proposals)); } // no fixes, so try adding assists if (proposalsList.isEmpty()) { Set processors = getQuickAssistProcessors(invocationContext); if (processors != null) { // iterate through list of processors until one processor says // canAssist for (Iterator it = processors.iterator(); it.hasNext();) { IQuickAssistProcessor assistProcessor = (IQuickAssistProcessor) it.next(); ICompletionProposal[] assistProposals = assistProcessor.computeQuickAssistProposals(invocationContext); if (assistProposals != null && assistProposals.length > 0) { proposalsList.addAll(Arrays.asList(assistProposals)); } } } } /* * Java editor currently returns a no modification completion proposal * but it seems better to just return null so user does not get * annoying proposal popup */ if (proposalsList.isEmpty()) { // proposalsList.add(new NoModificationCompletionProposal()); return null; } return (ICompletionProposal[]) proposalsList.toArray(new ICompletionProposal[proposalsList.size()]); } public String getErrorMessage() { // never have error messages return null; } }