blob: 7e410d49a6f31c959150d5228257effffb58e5cb [file] [log] [blame]
/*******************************************************************************
* 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;
}
}