/*******************************************************************************
* Copyright (c) 2012 VMware, Inc.
* 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.quickfix.jdt.computers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMemberValuePair;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.internal.core.SourceRefElement;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.ui.text.correction.AssistContext;
import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.source.SourceViewer;
import org.springframework.ide.eclipse.beans.core.BeansCorePlugin;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.beans.core.model.IBeansProject;
import org.springframework.ide.eclipse.beans.ui.model.BeansModelImages;
/**
* @author Terry Denney
* @author Martin Lippert
* @author Kaitlin Duck Sherwood
*/
public class ConfigurationLocationProposalComputer extends AnnotationProposalComputer {
// TODO: restructure to not find ASTNode in computer but in proposal
final String ILLEGAL_STRING = ":!\t)";
class ProposalAssemblyInformation {
String prefix;
String postfix;
String filter;
ProposalAssemblyInformation(String aPrefix, String aPostfix, String aFilter) {
this.prefix = aPrefix;
this.postfix = aPostfix;
this.filter = aFilter;
}
public String getPrefix() {
return prefix;
}
public String getPostfix() {
return postfix;
}
public String getFilter() {
return filter;
}
}
private List<String> getPathPrefixes(IJavaProject project) {
ArrayList<String> pathPrefixes = new ArrayList<String>();
try {
for (IClasspathEntry entry : project.getRawClasspath()) {
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
// Spring uses "/", not the system default separator
pathPrefixes.add(entry.getPath().removeFirstSegments(1).toOSString() + "/");
}
}
}
catch (JavaModelException e) {
// ignore
}
return pathPrefixes;
}
@Override
protected List<ICompletionProposal> computeCompletionProposals(SourceType type, String value, IAnnotation a,
JavaContentAssistInvocationContext javaContext) throws JavaModelException {
// }
// @Override
// protected List<ICompletionProposal>
// computeCompletionProposals(SourceType type, LocationInformation
// locationInfo,
// Annotation annotation, JavaContentAssistInvocationContext
// javaContext) throws JavaModelException {
// // TODO Auto-generated method stub
// return super.computeCompletionProposals(type, locationInfo,
// annotation, javaContext);
// }
// @Override
// protected List<ICompletionProposal>
// computeCompletionProposals(SourceType type, IAnnotation annotation,
// JavaContentAssistInvocationContext javaContext) throws
// JavaModelException {
// IMemberValuePair[] memberValuePairs =
// annotation.getMemberValuePairs();
// for (IMemberValuePair memberValuePair : memberValuePairs) {
// if ("locations".equals(memberValuePair.getMemberName()) ||
// "value".equals(memberValuePair.getMemberName())) {
ITextViewer viewer = javaContext.getViewer();
if (viewer instanceof SourceViewer) {
ICompilationUnit cu = javaContext.getCompilationUnit();
SourceViewer sourceViewer = (SourceViewer) javaContext.getViewer();
int invocationOffset = javaContext.getInvocationOffset();
AssistContext assistContext = new AssistContext(cu, sourceViewer, invocationOffset, 0);
ASTNode node = ((SourceRefElement) a).findNode(assistContext.getASTRoot());
if (node == null) {
node = assistContext.getCoveredNode();
}
if (!(a instanceof Annotation)) {
return Collections.emptyList();
}
Annotation annotation = (Annotation) a;
LocationInformation locationInfo = null;
if (node instanceof NormalAnnotation) {
NormalAnnotation normalAnnotation = (NormalAnnotation) node;
@SuppressWarnings("unchecked")
List<MemberValuePair> pairs = normalAnnotation.values();
for (MemberValuePair pair : pairs) {
Expression expression = pair.getValue();
if (expression instanceof StringLiteral) {
locationInfo = getLocationInformation((StringLiteral) expression, javaContext);
}
}
}
else if (node instanceof SingleMemberAnnotation) {
SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) node;
Expression expression = singleMemberAnnotation.getValue();
locationInfo = getLocationInformation((StringLiteral) expression, javaContext);
}
if (locationInfo == null) {
return Collections.emptyList();
}
Name typeName = annotation.getTypeName();
return getBeanProposals(javaContext, type.getCompilationUnit(), javaContext.getInvocationOffset(),
typeName.getFullyQualifiedName(), typeName.getStartPosition(), typeName.getLength());
}
// }
// }
return Collections.emptyList();
}
@Override
public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context,
IProgressMonitor monitor) {
if (context instanceof JavaContentAssistInvocationContext) {
JavaContentAssistInvocationContext javaContext = (JavaContentAssistInvocationContext) context;
ICompilationUnit cu = javaContext.getCompilationUnit();
try {
int invocationOffset = context.getInvocationOffset();
IJavaElement element = cu.getElementAt(invocationOffset);
if (element instanceof IType) {
IType type = (IType) element;
// NOTE: getAnnotations does not get any {} associated with
// the annotations
IAnnotation[] annotations = type.getAnnotations();
for (IAnnotation annotation : annotations) {
if ("ContextConfiguration".equals(annotation.getElementName())) {
IMemberValuePair[] memberValuePairs = annotation.getMemberValuePairs();
for (IMemberValuePair memberValuePair : memberValuePairs) {
if ("locations".equals(memberValuePair.getMemberName())
|| "value".equals(memberValuePair.getMemberName())) {
return getBeanProposals(context, cu, invocationOffset,
getAnnotationText(annotation, context.getViewer(), invocationOffset),
annotation.getNameRange().getOffset(), annotation.getNameRange()
.getLength());
}
}
}
}
}
}
catch (JavaModelException e) {
// ignore
}
}
return new ArrayList<ICompletionProposal>();
}
private List<ICompletionProposal> getBeanProposals(ContentAssistInvocationContext context, ICompilationUnit cu,
int invocationOffset, String annotationText, int annotationOffset, int annotationLength) {
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
// String annotationText = getAnnotationText(annotation,
// context.getViewer(), invocationOffset);
String prefix = "";
String postfix = "";
String filter = "";
// try {
ProposalAssemblyInformation assemblyInfo = createProposalAssemblyInformation(annotationText, invocationOffset
- annotationOffset - annotationLength);
// ProposalAssemblyInformation assemblyInfo =
// createProposalAssemblyInformation(annotationText,
// invocationOffset - annotation.getNameRange().getOffset() -
// annotation.getNameRange().getLength());
prefix = assemblyInfo.getPrefix();
postfix = assemblyInfo.getPostfix();
filter = assemblyInfo.getFilter();
// }
// catch (JavaModelException e) {
// prefix = "";
// postfix = "";
// }
IBeansProject beansProject = BeansCorePlugin.getModel().getProject(cu.getJavaProject().getProject());
List<String> classpathPrefixes = getPathPrefixes(cu.getJavaProject());
if (beansProject != null) {
Set<IBeansConfig> configs = beansProject.getConfigs();
// Imagine classpath "src/" and two config files
// "src/one/two/three.xml" and
// "config/x/y/z.xml" (<- i.e. not on classpath)
// If the user type "src", "one", or "three", they should get
// "classpath:one/two/three.xml" back.
// Similarly if they preface either of those three with
// "classpath:", they should get "classpath:one/two/three.xml".
// If the user types "config" or "z", they should get
// "file:config/x/y/z.xml" back.
// If they preface any of the above with "file:", they should get
// "file:src/one/two/three.xml" or
// "file:config/x/y/z.xml" back.
String resourceTypePrefix = "";
// Don't just search for a colon: we only handle
// "file:" and "classpath:".
if (filter.startsWith("file:")) {
resourceTypePrefix = "file:";
filter = filter.replaceFirst(resourceTypePrefix, "");
}
else if (filter.startsWith("classpath:")) {
resourceTypePrefix = "classpath:";
filter = filter.replaceFirst(resourceTypePrefix, "");
}
for (IBeansConfig config : configs) {
// Note that the displayText gets checked after
// the proposals are returned: see
// AbstractJavaCompletionProposal.getPrefix()
String displayText = "";
String replacementText = "";
String fullConfigFilePathname = config.getElementName();
String strippedConfigPath = fullConfigFilePathname;
String basename = config.getElementResource().getName();
boolean isOnClasspath = false;
boolean matchesFilter = false;
for (String classpathPrefix : classpathPrefixes) {
if (fullConfigFilePathname.startsWith(classpathPrefix)) {
isOnClasspath = true;
strippedConfigPath = fullConfigFilePathname.substring(classpathPrefix.length());
if (resourceTypePrefix.equals("classpath:")) {
replacementText = strippedConfigPath;
}
else {
replacementText = "classpath:" + strippedConfigPath;
}
break;
}
}
// if this config file isn't where it is supposed to be --
// e.g. on the classpath when file: is specified -- then it is
// not a legitimate option, skip this if statement's body
if (!(isOnClasspath && resourceTypePrefix.equals("file:"))
&& !(!isOnClasspath && resourceTypePrefix.equals("classpath:"))) {
if (!isOnClasspath) {
if (resourceTypePrefix.equals("file:")) {
replacementText = fullConfigFilePathname;
}
else {
replacementText = "file:" + fullConfigFilePathname;
}
}
if (fullConfigFilePathname.length() > 0) {
// user starts typing the start of the path *without*
// the classpath (e.g. "one" as described above)
if (isOnClasspath && strippedConfigPath.startsWith(filter)) {
displayText = strippedConfigPath;
matchesFilter = true;
}
// user starts typing the start of the full path (e.g.
// "src" or "config" as described above)
else if (fullConfigFilePathname.startsWith(filter)) {
displayText = fullConfigFilePathname;
matchesFilter = true;
}
// user starts typing the filename (e.g. foo.xml)
else if (basename.startsWith(filter)) {
displayText = basename;
matchesFilter = true;
}
}
replacementText = prefix + replacementText + postfix;
if (matchesFilter) {
proposals.add(new JavaCompletionProposal(replacementText, invocationOffset - filter.length(),
filter.length(), BeansModelImages.getImage(config), displayText, 0));
}
}
}
}
return proposals;
}
private static final int LINE_LOCATIONS_POSITION = 1;
private static final int LINE_LEADING_BRACE_PATTERN_POSITION = LINE_LOCATIONS_POSITION + 1;
private static final int LINE_WHITESPACE1_PATTERN_POSITION = LINE_LEADING_BRACE_PATTERN_POSITION + 1;
private static final int LINE_CONFIG_FILEPATHS_PATTERN_POSITION = LINE_WHITESPACE1_PATTERN_POSITION + 1;
private static final int LINE_CONFIG_LAST_FILEPATH_WITH_DELIMITING_SPACE_PATTERN_POSITION = LINE_CONFIG_FILEPATHS_PATTERN_POSITION + 1;
private static final int LINE_CONFIG_LAST_FILEPATH_PATTERN_POSITION = LINE_CONFIG_LAST_FILEPATH_WITH_DELIMITING_SPACE_PATTERN_POSITION + 1;
private static final int LINE_CONFIG_FILEPATH_NO_SPACES_PATTERN_POSITION = LINE_CONFIG_LAST_FILEPATH_PATTERN_POSITION + 1;
private static final int LINE_CONFIG_FILEPATH_SPACES_PATTERN_POSITION = LINE_CONFIG_FILEPATH_NO_SPACES_PATTERN_POSITION + 1;
private static final int LINE_COMMA_POSITION = LINE_CONFIG_FILEPATH_SPACES_PATTERN_POSITION + 1;
private static final int LINE_WHITESPACE2_PATTERN_POSITION = LINE_COMMA_POSITION + 1;
private static final int LINE_CLOSING_BRACE_PATTERN_POSITION = LINE_WHITESPACE2_PATTERN_POSITION + 1;
private static final int LINE_WHITESPACE3_PATTERN_POSITION = LINE_CLOSING_BRACE_PATTERN_POSITION + 1;
private static final int LINE_CLOSING_PAREN_PATTERN_POSITION = LINE_WHITESPACE3_PATTERN_POSITION + 1;
// This is only public to allow testing
public static Pattern getLineCompiledPattern() {
String locations = "(locations|value)\\s*=\\s*";
String optionalLeadingBrace = "(\\{?)";
// if you want a space in the file name, it must be quoted
String oneFileNameAllowingSpaces = "([\"'][^\"']*[\"'])";
// must allow possible missing close quote so you can autocomplete
// the file, but a file must have at least an opening quote
String oneFileNameDisallowingSpaces = "([\'\"][^\\s\"'\\)\\}]*[\"']?)";
String oneFileName = "(" + oneFileNameAllowingSpaces + "|" + oneFileNameDisallowingSpaces + ")";
String configurationFiles = "((" + oneFileName + "\\s*(,?)\\s*)*)";
String optionalClosingBrace = "(\\}?)";
String optionalClosingParen = "(\\)?)";
String whitespace = "(\\s*)";
String validCompletion = locations + optionalLeadingBrace + // group 1
whitespace + // group 2
configurationFiles + // group 3
whitespace + // group 4
optionalClosingBrace + // group 5
whitespace + // group 6
optionalClosingParen; // group 7
return Pattern.compile(validCompletion);
}
private int invocationOffsetIsInWhichGroupNumber(Matcher matcher, int invocationIndex) {
int groupIndex;
for (groupIndex = 1; groupIndex <= matcher.groupCount(); groupIndex++) {
if (invocationIndex < matcher.start(groupIndex)) {
return CONFIG_AT_END; // we ran off the end
}
try {
if (invocationIndex >= matcher.start(groupIndex) && invocationIndex <= matcher.end(groupIndex)) {
return groupIndex;
}
}
catch (IllegalStateException e) {
// ignore
}
}
return CONFIG_AT_END;
}
private boolean hasSomethingInField(Matcher matcher, int patternPosition) {
return matcher.start(patternPosition) != matcher.end(patternPosition);
}
private ProposalAssemblyInformation createProposalAssemblyInformation(String annotationText, int invocationIndex) {
String prefix = "";
String postfix = "";
String filter = "";
Matcher matcher = getLineCompiledPattern().matcher(annotationText);
if (matcher.find()) {
boolean hasOpeningBrace = hasSomethingInField(matcher, LINE_LEADING_BRACE_PATTERN_POSITION);
boolean hasOtherConfigFiles = hasSomethingInField(matcher, LINE_CONFIG_FILEPATHS_PATTERN_POSITION);
boolean hasComma = hasSomethingInField(matcher, LINE_COMMA_POSITION);
boolean hasClosingBrace = hasSomethingInField(matcher, LINE_CLOSING_BRACE_PATTERN_POSITION);
int groupIndex = invocationOffsetIsInWhichGroupNumber(matcher, invocationIndex);
if (groupIndex < 0) {
if (invocationIndex >= annotationText.length()) {
String comma = "";
if (hasOtherConfigFiles && !hasComma) {
comma = ",";
}
prefix = comma + "\"";
// String closeParen = "";
// if there is a close brace, end with a )
if (hasClosingBrace) {
postfix = "";
filter = ILLEGAL_STRING;
}
else {
filter = "";
postfix = "\"";
}
return new ProposalAssemblyInformation(prefix, postfix, filter);
}
else {
// This can happen if the string is just not legal,
// or if the invocation is before the = sign.
prefix = "";
postfix = "";
filter = ILLEGAL_STRING;
return new ProposalAssemblyInformation(prefix, postfix, filter);
}
}
filter = ""; // overridden as needed
switch (groupIndex) {
case LINE_LEADING_BRACE_PATTERN_POSITION:
String closingBrace = "";
if (!hasOpeningBrace) {
prefix = "{\"";
// if we open a brace, close it as well
closingBrace = "}";
}
else {
prefix = "\"";
}
if (hasOtherConfigFiles) {
postfix = "\", " + closingBrace;
}
else {
postfix = "\"" + closingBrace;
}
break;
case LINE_WHITESPACE1_PATTERN_POSITION:
prefix = "\"";
if (hasOtherConfigFiles) {
postfix = "\", ";
}
else {
postfix = "\"";
}
break;
case LINE_CONFIG_FILEPATHS_PATTERN_POSITION:
String fileString = substringOfGroup(annotationText, matcher, LINE_CONFIG_FILEPATHS_PATTERN_POSITION);
if (fileString.length() == 0) {
prefix = "";
postfix = "";
}
else {
int newInvocationIndex = invocationIndex - matcher.end(groupIndex - 1);
ProposalAssemblyInformation configAssemblyInfo = proposalAssemblyInfoFromConfigFiles(fileString,
newInvocationIndex, hasClosingBrace);
return configAssemblyInfo;
}
break;
case LINE_WHITESPACE2_PATTERN_POSITION:
// Whitespace usually ends up getting eaten by the config
// line, so this will almost never get hit
// Adding a prefix comma is the responsibility of the
// CONFIG_WHITESPACE2_PATTERN_POSITION handler
prefix = "\"";
postfix = "\"";
break;
case LINE_CLOSING_BRACE_PATTERN_POSITION:
case LINE_WHITESPACE3_PATTERN_POSITION:
prefix = "\"";
if (!hasClosingBrace) {
postfix = "\"}";
}
// disallow matching; proposals are invalid here
filter = ILLEGAL_STRING;
break;
case LINE_CLOSING_PAREN_PATTERN_POSITION: // too late
prefix = "";
postfix = "";
// disallow matching; proposals are invalid here
filter = ILLEGAL_STRING;
break;
}
ProposalAssemblyInformation assemblyInfo = new ProposalAssemblyInformation(prefix, postfix, filter);
return assemblyInfo;
}
return new ProposalAssemblyInformation("", "", "");
}
private String substringOfGroup(String annotationText, Matcher matcher, int groupIndex) {
int startLocation = matcher.start(groupIndex);
int endLocation = matcher.end(groupIndex);
return annotationText.substring(startLocation, endLocation);
}
private ProposalAssemblyInformation proposalAssemblyInfoFromConfigFiles(String fileString, int invocationIndex,
boolean hasClosingBrace) {
String postfix = "";
String prefix = "";
String filter = "";
java.util.regex.Pattern filePattern = ConfigurationLocationProposalComputer.getConfigFileCompiledPattern();
Matcher fileMatcher = filePattern.matcher(fileString);
int fileGroupIndex = 1;
while (fileMatcher.find()) {
if (invocationIndex >= fileMatcher.start() && invocationIndex <= fileMatcher.end()) {
int fileSubgroupIndex = invocationOffsetIsInWhichGroupNumber(fileMatcher, invocationIndex);
// boolean hasOpeningQuote = hasSomethingInField(fileMatcher,
// CONFIG_OPENING_QUOTE_PATTERN_POSITION);
boolean hasClosingQuote = hasSomethingInField(fileMatcher, CONFIG_CLOSING_QUOTE_PATTERN_POSITION);
boolean hasComma = hasSomethingInField(fileMatcher, CONFIG_COMMA_PATTERN_POSITION);
boolean hasFilePattern = hasSomethingInField(fileMatcher, CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION)
|| hasSomethingInField(fileMatcher, CONFIG_CLOSING_QUOTE_PATTERN_POSITION);
String comma = "";
if (fileGroupIndex > 1 && !hasComma) {
comma = ", ";
}
switch (fileSubgroupIndex) {
// off the end
case CONFIG_AT_END:
prefix = comma + "\"";
postfix = "\" ,";
if (fileGroupIndex == fileMatcher.groupCount()) {
return new ProposalAssemblyInformation(prefix, postfix, filter);
}
break;
case CONFIG_WHITESPACE3_PATTERN_POSITION:
postfix = "\"";
prefix = "\"";
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_WHITESPACE1_PATTERN_POSITION:
prefix = "\"";
postfix = comma + "\"";
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_WHITESPACE2_PATTERN_POSITION:
boolean areThereMoreFiles = hasFilePattern;
if (areThereMoreFiles) {
prefix = ", \"";
}
else {
prefix = "\"";
}
postfix = "\"" + comma;
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_COMMA_PATTERN_POSITION:
prefix = "\"";
postfix = "\"";
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_OPENING_QUOTE_PATTERN_POSITION:
prefix = "";
// If there is no trailing brace, the annotation text only
// goes up to the invocation point. This means we can't
// know if there is a close quote or not if there is no
// closing brace.
if (!hasClosingQuote && hasClosingBrace) {
postfix = "\"";
}
else {
postfix = "";
}
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION:
prefix = "";
if (hasClosingQuote) {
postfix = "";
}
else {
postfix = "\"";
}
filter = fileMatcher.group(CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION);
return new ProposalAssemblyInformation(prefix, postfix, filter);
case CONFIG_CLOSING_QUOTE_PATTERN_POSITION:
prefix = ", \"";
postfix = "\"";
filter = "";
return new ProposalAssemblyInformation(prefix, postfix, filter);
}
}
fileGroupIndex++;
}
return new ProposalAssemblyInformation("", "", "");
}
private static final int CONFIG_AT_END = -1;
private static final int CONFIG_WHITESPACE1_PATTERN_POSITION = 1;
private static final int CONFIG_OPENING_QUOTE_PATTERN_POSITION = CONFIG_WHITESPACE1_PATTERN_POSITION + 1;
private static final int CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION = CONFIG_OPENING_QUOTE_PATTERN_POSITION + 1;
private static final int CONFIG_TYPE_PREFIXES = CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION + 1;
private static final int CONFIG_CLOSING_QUOTE_PATTERN_POSITION = CONFIG_TYPE_PREFIXES + 1;
private static final int CONFIG_WHITESPACE2_PATTERN_POSITION = CONFIG_CLOSING_QUOTE_PATTERN_POSITION + 1;
private static final int CONFIG_COMMA_PATTERN_POSITION = CONFIG_WHITESPACE2_PATTERN_POSITION + 1;
private static final int CONFIG_WHITESPACE3_PATTERN_POSITION = CONFIG_COMMA_PATTERN_POSITION + 1;
// public only for testing purposes
public static java.util.regex.Pattern getConfigFileCompiledPattern() {
String whitespace = "(\\s*)"; // group
// CONFIG_WHITESPACE1_PATTERN_POSITION
// and group
// CONFIG_WHITESPACE2_PATTERN_POSITION
// group CONFIG_OPENING_QUOTE_PATTERN_POSITION
String openingQuotePatternString = "(\"?)";
// group CONFIG_TYPE_PREFIXES
String allowedResourceTypePrefixes = "(file:|classpath:)?";
// CONFIG_UNQUOTED_FILENAME_PATTERN_POSITION and CONFIG_TYPE_PREFIXES
String unquotedFileNamePatternString = "(" + allowedResourceTypePrefixes + "[\\w\\.\\-\\/]*)";
// group CONFIG_CLOSING_QUOTE_PATTERN_POSITION
String closingQuotePatternString = "(\"?)";
// group CONFIG_COMMA_PATTERN_POSITION
String commaPatternString = "(,?)";
String filePatternString = whitespace + openingQuotePatternString + unquotedFileNamePatternString
+ closingQuotePatternString + whitespace + commaPatternString + whitespace;
java.util.regex.Pattern filePattern = java.util.regex.Pattern.compile(filePatternString);
return filePattern;
}
private String getAnnotationText(IAnnotation annotation, ITextViewer viewer, int invocationOffset) {
ISourceRange nameRange;
ISourceRange sourceRange;
try {
nameRange = annotation.getNameRange();
sourceRange = annotation.getSourceRange();
}
catch (JavaModelException e) {
return "";
}
int endPoint = sourceRange.getOffset() + sourceRange.getLength();
// Want to get AT LEAST to the invocation point
if (invocationOffset > endPoint) {
endPoint = invocationOffset;
}
String text;
try {
text = viewer.getDocument().get((nameRange.getOffset() + nameRange.getLength()),
endPoint - (nameRange.getOffset() + nameRange.getLength()));
}
catch (BadLocationException e) {
return "";
}
return text;
}
}