diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal')
8 files changed, 492 insertions, 133 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlContentProposalProvider.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlContentProposalProvider.java index bc3a95cdd4..6845c3a351 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlContentProposalProvider.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlContentProposalProvider.java @@ -66,6 +66,7 @@ import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; import org.eclipse.jpt.jpa.core.context.NamedQuery; import org.eclipse.jpt.jpa.core.jpql.JpaJpqlQueryHelper; +import org.eclipse.jpt.jpa.core.jpql.JpaJpqlQueryHelper.EscapeType; import org.eclipse.jpt.jpa.ui.internal.JptUiMessages; import org.eclipse.osgi.util.NLS; import org.eclipse.persistence.jpa.jpql.JPQLQueryProblem; @@ -347,19 +348,18 @@ public final class JpaJpqlContentProposalProvider extends JpqlCompletionProposal Image image, int cursorOffset) { - return new JpqlCompletionProposal( + return new JpqlDefaultCompletionProposal( contentAssistProposals, proposal, displayString, additionalInfo, image, namedQuery, - actualQuery, jpqlQuery, - offset, + tokenStart, + tokenEnd, position, - cursorOffset, - false + cursorOffset ); } @@ -472,6 +472,9 @@ public final class JpaJpqlContentProposalProvider extends JpqlCompletionProposal // Install a custom context menu to the widget TextTransferHandler.installContextMenu(styledText, sourceViewer.getUndoManager()); + + // Make sure the document is up to date in case the text holder is already hooked to the model + sourceViewer.getDocument().set(textHolder.getValue()); } /** @@ -583,8 +586,8 @@ public final class JpaJpqlContentProposalProvider extends JpqlCompletionProposal for (JPQLQueryProblem problem : sortProblems(queryHelper.validate())) { - // Create the range - int[] positions = queryHelper.buildPositions(problem, parsedJpqlQuery, jpqlQuery); + // Create the text range + int[] positions = queryHelper.buildPositions(problem, parsedJpqlQuery, jpqlQuery, jpqlQuery, 0, EscapeType.NONE); // Add the problem to the tool tip Annotation annotation = new Annotation(ERROR_TYPE, true, buildMessage(problem)); @@ -608,9 +611,16 @@ public final class JpaJpqlContentProposalProvider extends JpqlCompletionProposal public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { JpaJpqlContentProposalProvider.this.position = offset; - String jpqlQuery = viewer.getDocument().get(); - List<ICompletionProposal> proposals = buildProposals(query(), jpqlQuery, 0, position); + + List<ICompletionProposal> proposals = buildProposals( + query(), + jpqlQuery, + 0, + jpqlQuery.length(), + position + ); + return proposals.toArray(new ICompletionProposal[proposals.size()]); } diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java index 9aed1daa34..50f095a33d 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java @@ -13,6 +13,7 @@ ******************************************************************************/ package org.eclipse.jpt.jpa.ui.internal.jpql; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.resources.IFile; @@ -27,6 +28,7 @@ import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.IExtendedModifier; +import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; @@ -55,7 +57,7 @@ import org.eclipse.swt.graphics.Image; * This computer adds content assist support when it is invoked inside the query element of {@link * javax.persistence.NamedQuery @NamedQuery}. * - * @version 3.2 + * @version 3.3 * @since 3.0 * @author Pascal Filion */ @@ -80,22 +82,30 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP Image image, int cursorOffset) { - return new JpqlCompletionProposal( + return new JpqlJavaCompletionProposal( contentAssistProposals, proposal, displayString, additionalInfo, image, namedQuery, - actualQuery, jpqlQuery, - offset + 1, // +1 is to skip the opening " + tokenStart + 1, // +1 is to skip the opening " + tokenEnd - 1, // -1 is to skip the closing " position, - cursorOffset, - true + cursorOffset ); } + @SuppressWarnings("unchecked") + private List<Expression> children(InfixExpression expression) { + List<Expression> children = new ArrayList<Expression>(); + children.add(expression.getLeftOperand()); + children.add(expression.getRightOperand()); + children.addAll(expression.extendedOperands()); + return children; + } + /** * {@inheritDoc} */ @@ -129,10 +139,11 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP // - It is inside the string representation of a unicode character, \\u0|0E9 where | is the // cursor, then -1 is returned; // - The string is not valid (it has some invalid characters) - int tokenStart = completionContext.getTokenStart(); - if (tokenStart == -1) return Collections.emptyList(); + int tokenStart[] = { completionContext.getTokenStart() }; + int tokenEnd[] = { completionContext.getTokenEnd() }; + if (tokenStart[0] == -1) return Collections.emptyList(); - int[] position = { completionContext.getOffset() - tokenStart - 1 }; + int[] position = { completionContext.getOffset() - tokenStart[0] - 1 }; if (position[0] < 0) return Collections.emptyList(); ICompilationUnit compilationUnit = context.getCompilationUnit(); @@ -149,15 +160,15 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP checkCanceled(monitor); // Retrieve the JPA's model object - NamedQuery namedQuery = namedQuery(jpaFile, tokenStart); + NamedQuery namedQuery = namedQuery(jpaFile, tokenStart[0]); if (namedQuery == null) return Collections.emptyList(); // Retrieve the actual value of the element "query" since the content assist can be // invoked before the model received the new content - String jpqlQuery = jpqlQuery(astRoot, tokenStart, completionContext.getTokenEnd(), position); + String jpqlQuery = retrieveQuery(astRoot, tokenStart, tokenEnd, position); // Now create the proposals - return buildProposals(namedQuery, jpqlQuery, tokenStart, position[0]); + return buildProposals(namedQuery, jpqlQuery, tokenStart[0], tokenEnd[0], position[0]); } /** @@ -178,10 +189,11 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP for (Query query : typeMapping.getQueries()){ if (query.getType().equals(NamedQuery.class)){ - JavaNamedQuery namedQuery = (JavaNamedQuery)query; - TextRange textRange = namedQuery.getQueryAnnotation().getQueryTextRange(); - if ((textRange != null) && textRange.includes(tokenStart)) { - return namedQuery; + JavaNamedQuery namedQuery = (JavaNamedQuery) query; + for (TextRange textRange : namedQuery.getQueryAnnotation().getQueryTextRanges()) { + if ((textRange != null) && textRange.includes(tokenStart)) { + return namedQuery; + } } } } @@ -206,20 +218,6 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP startPosition + node.getLength() >= tokenEnd; } - private String jpqlQuery(CompilationUnit astRoot, int tokenStart, int tokenEnd, int[] position) { - - String jpqlQuery = retrieveQuery(astRoot, tokenStart, tokenEnd); - - if (jpqlQuery == null) { - jpqlQuery = StringTools.EMPTY_STRING; - } - else if (StringTools.isQuoted(jpqlQuery)) { - jpqlQuery = jpqlQuery.substring(1, jpqlQuery.length() - 1); - } - - return jpqlQuery; - } - /** * {@inheritDoc} */ @@ -254,12 +252,12 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP * @return The actual value retrieved from the query element */ @SuppressWarnings("unchecked") - private String retrieveQuery(CompilationUnit astRoot, int tokenStart, int tokenEnd) { + private String retrieveQuery(CompilationUnit astRoot, int[] tokenStart, int[] tokenEnd, int[] position) { // Dig into the TypeDeclarations for (AbstractTypeDeclaration type : (List<AbstractTypeDeclaration>) astRoot.types()) { - if (isInsideNode(type, tokenStart, tokenEnd)) { + if (isInsideNode(type, tokenStart[0], tokenEnd[0])) { // Dig inside its modifiers and annotations for (IExtendedModifier modifier : (List<IExtendedModifier>) type.modifiers()) { @@ -271,7 +269,7 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP Annotation annotation = (Annotation) modifier; // Dig inside the annotation - if (isInsideNode(annotation, tokenStart, tokenEnd)) { + if (isInsideNode(annotation, tokenStart[0], tokenEnd[0])) { // @NamedQueries({...}) if (annotation.isSingleMemberAnnotation()) { @@ -282,22 +280,22 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP ArrayInitializer array = (ArrayInitializer) value; for (Expression expression : (List<Expression>) array.expressions()) { - if (isInsideNode(expression, tokenStart, tokenEnd)) { - return retrieveQuery((NormalAnnotation) expression, tokenStart, tokenEnd); + if (isInsideNode(expression, tokenStart[0], tokenEnd[0])) { + return retrieveQuery((NormalAnnotation) expression, tokenStart, tokenEnd, position); } } } else { NormalAnnotation childAnnotation = (NormalAnnotation) value; - if (isInsideNode(childAnnotation, tokenStart, tokenEnd)) { - return retrieveQuery(childAnnotation, tokenStart, tokenEnd); + if (isInsideNode(childAnnotation, tokenStart[0], tokenEnd[0])) { + return retrieveQuery(childAnnotation, tokenStart, tokenEnd, position); } } } // @NamedQuery() else if (annotation.isNormalAnnotation()) { - return retrieveQuery((NormalAnnotation) annotation, tokenStart, tokenEnd); + return retrieveQuery((NormalAnnotation) annotation, tokenStart, tokenEnd, position); } } } @@ -308,17 +306,62 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP } @SuppressWarnings("unchecked") - private String retrieveQuery(NormalAnnotation annotation, int tokenStart, int tokenEnd) { + private String retrieveQuery(NormalAnnotation annotation, int[] tokenStart, int[] tokenEnd, int[] position) { for (MemberValuePair pair : (List<MemberValuePair>) annotation.values()) { org.eclipse.jdt.core.dom.Expression expression = pair.getValue(); - if (isInsideNode(expression, tokenStart, tokenEnd)) { - StringLiteral literal = (StringLiteral) pair.getValue(); - return literal.getEscapedValue(); + if (isInsideNode(expression, tokenStart[0], tokenEnd[0])) { + Expression child = pair.getValue(); + + // Single string + if (child.getNodeType() == ASTNode.STRING_LITERAL) { + StringLiteral literal = (StringLiteral) pair.getValue(); + return unquotedString(literal.getEscapedValue()); + } + + // Build the JPQL query from the concatenated strings + if (child.getNodeType() == ASTNode.INFIX_EXPRESSION) { + + StringBuilder sb = new StringBuilder(); + boolean adjustPosition = true; + + for (Expression childNode : children((InfixExpression) child)) { + + StringLiteral literal = (StringLiteral) childNode; + sb.append(unquotedString(literal.getEscapedValue())); + + if (adjustPosition && !isInsideNode(literal, tokenEnd[0], tokenEnd[0])) { + position[0] += (literal.getLength() - 2); + } + else { + adjustPosition = false; + } + } + + // Now adjust the start and end offsets so it includes the entire InfixExpression + // because content assist will only replace one string literal and right now we + // only support replacing the entire string + tokenStart[0] = child.getStartPosition(); + tokenEnd[0] = child.getStartPosition() + child.getLength(); + + return sb.toString(); + } } } - return null; + return StringTools.EMPTY_STRING; + } + + private String unquotedString(String value) { + + if (value == null) { + value = StringTools.EMPTY_STRING; + } + else if (StringTools.isQuoted(value)) { + value = value.substring(1, value.length() - 1); + } + + return value; } }
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java index 92b4bb3fe9..e3299b054a 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java @@ -36,9 +36,9 @@ import org.eclipse.jpt.jpa.core.context.orm.EntityMappings; import org.eclipse.jpt.jpa.core.context.orm.OrmEntity; import org.eclipse.jpt.jpa.core.context.orm.OrmNamedQuery; import org.eclipse.jpt.jpa.core.context.orm.OrmQueryContainer; +import org.eclipse.jpt.jpa.core.jpql.XmlEscapeCharacterConverter; import org.eclipse.jpt.jpa.ui.internal.JptUiMessages; import org.eclipse.jpt.jpa.ui.internal.plugin.JptJpaUiPlugin; -import org.eclipse.persistence.jpa.jpql.ExpressionTools; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.sse.ui.contentassist.CompletionProposalInvocationContext; import org.eclipse.wst.sse.ui.contentassist.ICompletionProposalComputer; @@ -47,13 +47,15 @@ import org.eclipse.wst.sse.ui.contentassist.ICompletionProposalComputer; * This computer adds content assist support when it is invoked inside the <query> element * defined in a mapping file (ORM Configuration). * - * @version 3.2 + * @version 3.3 * @since 3.0 * @author Pascal Filion */ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionProposalComputer<ICompletionProposal> implements ICompletionProposalComputer { + private boolean cDATASection; + /** * Creates a new <code>JpaJpqlSseCompletionProposalComputer</code>. */ @@ -71,19 +73,21 @@ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionPr Image image, int cursorOffset) { - return new JpqlCompletionProposal( + return new JpqlSseCompletionProposal( contentAssistProposals, proposal, displayString, additionalInfo, image, namedQuery, - actualQuery, jpqlQuery, - offset, + actualQuery, + tokenStart, + tokenEnd, position, + actualPosition, cursorOffset, - false + cDATASection ); } @@ -117,12 +121,17 @@ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionPr OrmNamedQuery namedQuery = namedQuery(jpaFile, offset, position); if (namedQuery == null) return Collections.emptyList(); - // Keep track of the beginning of the text since the entire string is always replaced + // Retrieve the entire JPQL query from the document + Object[] info = jpqlQuery(namedQuery, context.getDocument()); + String jpqlQuery = (String) info[0]; + this.cDATASection = (Boolean) info[1]; + + // Keep track of the beginning and ending offsets since the entire string is always replaced int tokenStart = offset - position[0]; + int tokenEnd = tokenStart + jpqlQuery.length(); // Now create the proposals - String jpqlQuery = jpqlQuery(namedQuery, context.getDocument()); - return buildProposals(namedQuery, jpqlQuery, tokenStart, position[0]); + return buildProposals(namedQuery, jpqlQuery, tokenStart, tokenEnd, position[0]); } catch (Exception ex) { JptJpaUiPlugin.instance().logError(ex, JptUiMessages.JpaJpqlSseCompletionProposalComputer_Error); @@ -175,24 +184,34 @@ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionPr private OrmNamedQuery findNamedQuery(OrmQueryContainer container, int offset, int[] position) { for (OrmNamedQuery namedQuery : container.getNamedQueries()) { - TextRange textRange = namedQuery.getQueryTextRange(); - if (textRange.touches(offset)) { - position[0] = offset - textRange.getOffset(); - return namedQuery; + for (TextRange textRange : namedQuery.getQueryTextRanges()) { + + if (textRange.touches(offset)) { + position[0] = offset - textRange.getOffset(); + return namedQuery; + } } } return null; } - private String jpqlQuery(OrmNamedQuery namedQuery, IDocument document) { + private Object[] jpqlQuery(OrmNamedQuery namedQuery, IDocument document) { + try { - TextRange range = namedQuery.getQueryTextRange(); - return document.get(range.getOffset(), range.getLength()); + TextRange range = namedQuery.getQueryTextRanges().get(0); + + return new Object[] { + document.get(range.getOffset(), range.getLength()), + namedQuery.getXmlQuery().isQueryInsideCDATASection() + }; } catch (BadLocationException e) { - return StringTools.EMPTY_STRING; + return new Object[] { + StringTools.EMPTY_STRING, + Boolean.FALSE + }; } } @@ -201,7 +220,15 @@ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionPr */ @Override String modifyJpqlQuery(String jpqlQuery, int[] position) { - return ExpressionTools.unescape(jpqlQuery, position); + + // The JPQL query is not encapsulated by a CDATA section, + // converts any escape characters like < into '<' + if (!cDATASection) { + // TODO: UPDATE TO USE ECLIPSELINK HERMES 2.5 M2 ONCE IT IS AVAILABLE + jpqlQuery = XmlEscapeCharacterConverter.unescape(jpqlQuery, position); + } + + return jpqlQuery; } private OrmNamedQuery namedQuery(JpaFile jpaFile, int offset, int[] position) { diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java index aefd14b501..cf9b6f53f1 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java @@ -26,29 +26,28 @@ import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; /** - * The concrete implementation of a {@link org.eclipse.jface.text.contentassist.ICompletionProposal - * ICompletionProposal} that adds relevance and toggling the completion insertion property behavior. + * The abstract implementation of {@link org.eclipse.jface.text.contentassist.ICompletionProposal + * ICompletionProposal} which adds relevance and toggling the completion insertion property behavior. * - * @version 3.0 + * @version 3.3 * @since 3.0 * @author Pascal Filion */ -final class JpqlCompletionProposal implements ICompletionProposal { +abstract class JpqlCompletionProposal implements ICompletionProposal { - private String actualQuery; private String additionalInfo; - private ContentAssistProposals proposals; private int cursorOffset; private String displayString; - private boolean escapeCharacters; private Image image; - private String jpqlQuery; + String jpqlQuery; private NamedQuery namedQuery; - private int offset; - private int position; - private String proposal; - private ResultQuery result; - private boolean toggleCompletion; + int position; + String proposal; + ContentAssistProposals proposals; + ResultQuery result; + boolean toggleCompletion; + private int tokenEnd; + private int tokenStart; JpqlCompletionProposal(ContentAssistProposals proposals, String proposal, @@ -56,27 +55,25 @@ final class JpqlCompletionProposal implements ICompletionProposal { String additionalInfo, Image image, NamedQuery namedQuery, - String actualQuery, String jpqlQuery, - int offset, + int tokenStart, + int tokenEnd, int position, - int cursorOffset, - boolean escapeCharacters) { + int cursorOffset) { super(); this.image = image; - this.offset = offset; + this.tokenStart = tokenStart; + this.tokenEnd = tokenEnd; this.position = position; this.proposal = proposal; this.jpqlQuery = jpqlQuery; this.proposals = proposals; this.namedQuery = namedQuery; - this.actualQuery = actualQuery; this.cursorOffset = cursorOffset; this.displayString = displayString; this.additionalInfo = additionalInfo; - this.escapeCharacters = escapeCharacters; } /** @@ -84,35 +81,19 @@ final class JpqlCompletionProposal implements ICompletionProposal { */ public void apply(IDocument document) { try { - ResultQuery result = buildResult(); - document.replace(offset, actualQuery.length(), result.getQuery()); + document.replace(tokenStart, tokenEnd - tokenStart, getResult().getQuery()); } catch (BadLocationException e) { // Ignore } } - private ResultQuery buildResult() { - if (result == null) { - if (escapeCharacters) { - result = proposals.buildEscapedQuery( - jpqlQuery, - proposal, - position, - isCompletionInserts() ^ toggleCompletion - ); - } - else { - result = proposals.buildQuery( - jpqlQuery, - proposal, - position, - isCompletionInserts() ^ toggleCompletion - ); - } - } - return result; - } + /** + * Creates + * + * @return + */ + abstract ResultQuery buildResult(); /** * {@inheritDoc} @@ -143,14 +124,25 @@ final class JpqlCompletionProposal implements ICompletionProposal { } /** + * Returns + * + * @return + */ + final ResultQuery getResult() { + if (result == null) { + result = buildResult(); + } + return result; + } + + /** * {@inheritDoc} */ public Point getSelection(IDocument document) { - ResultQuery result = buildResult(); - return new Point(offset + result.getPosition() + cursorOffset, 0); + return new Point(tokenStart + getResult().getPosition() + cursorOffset, 0); } - private boolean isCompletionInserts() { + final boolean isCompletionInserts() { IJavaProject javaProject = namedQuery.getJpaProject().getJavaProject(); String value = PreferenceConstants.getPreference(PreferenceConstants.CODEASSIST_INSERT_COMPLETION, javaProject); return Boolean.valueOf(value); diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java index 7517ff0c22..530173c2f9 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java @@ -47,6 +47,11 @@ import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.*; abstract class JpqlCompletionProposalComputer<T> { /** + * The position of the cursor within the actual JPQL query (not modified). + */ + int actualPosition; + + /** * The current value of the query element. */ String actualQuery; @@ -73,17 +78,12 @@ abstract class JpqlCompletionProposalComputer<T> { NamedQuery namedQuery; /** - * The start position of the query within the document. - */ - int offset; - - /** * The word before the position of the cursor. */ private String partialWord; /** - * The position of the cursor within {@link #actualQuery}. + * The position of the cursor within the adjusted JPQL query. */ int position; @@ -94,6 +94,16 @@ abstract class JpqlCompletionProposalComputer<T> { JpaJpqlQueryHelper queryHelper; /** + * The end position of the query within the document. + */ + int tokenEnd; + + /** + * The start position of the query within the document. + */ + int tokenStart; + + /** * Creates a new <code>JpqlCompletionProposalComputer</code>. */ public JpqlCompletionProposalComputer() { @@ -219,6 +229,10 @@ abstract class JpqlCompletionProposalComputer<T> { ); } + private ImageDescriptor buildImageDescriptor(String key) { + return JptJpaUiPlugin.instance().buildImageDescriptor(key); + } + private T buildMappingProposal(IMapping mapping) { String proposal = mapping.getName(); return buildProposal(proposal, proposal, mappingImage(mapping)); @@ -252,19 +266,25 @@ abstract class JpqlCompletionProposalComputer<T> { * the specified position. * * @param namedQuery The model object used to access the application metadata information - * @param actualQuery The model object may sometimes be out of sync with the actual content, the - * actual query is required for proper content assist + * @param actualQuery The string representation of the JPQL query that is coming from the + * document itself (Java source or XML) * @param offset The beginning of the string within the document * @param position The position of the cursor within the query, which starts at the beginning of * that query and not the document * @return The list of completion proposals */ - final List<T> buildProposals(NamedQuery namedQuery, String actualQuery, int offset, int position) { + final List<T> buildProposals(NamedQuery namedQuery, + String actualQuery, + int tokenStart, + int tokenEnd, + int position) { try { - this.offset = offset; - this.actualQuery = actualQuery; - this.namedQuery = namedQuery; + this.tokenStart = tokenStart; + this.tokenEnd = tokenEnd; + this.actualQuery = actualQuery; + this.actualPosition = position; + this.namedQuery = namedQuery; // It's possible the string has literal representation of the escape characters, if required, // convert them into actual escape characters and adjust the position accordingly @@ -309,7 +329,8 @@ abstract class JpqlCompletionProposalComputer<T> { */ final void clearInformation() { namedQuery = null; - offset = -1; + tokenStart = -1; + tokenEnd = -1; position = -1; actualQuery = null; namedQuery = null; @@ -341,10 +362,6 @@ abstract class JpqlCompletionProposalComputer<T> { return image; } - private ImageDescriptor buildImageDescriptor(String key) { - return JptJpaUiPlugin.instance().buildImageDescriptor(key); - } - private synchronized ImageRegistry getImageRegistry() { if (imageRegistry == null) { imageRegistry = new ImageRegistry(Display.getCurrent()); diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlDefaultCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlDefaultCompletionProposal.java new file mode 100644 index 0000000000..8e3ee82187 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlDefaultCompletionProposal.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation + * + ******************************************************************************/ +package org.eclipse.jpt.jpa.ui.internal.jpql; + +import org.eclipse.jpt.jpa.core.context.NamedQuery; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; +import org.eclipse.persistence.jpa.jpql.ResultQuery; +import org.eclipse.swt.graphics.Image; + +/** + * @version 3.3 + * @since 3.3 + * @author Pascal Filion + */ +final class JpqlDefaultCompletionProposal extends JpqlCompletionProposal { + + JpqlDefaultCompletionProposal(ContentAssistProposals proposals, + String proposal, + String displayString, + String additionalInfo, + Image image, + NamedQuery namedQuery, + String jpqlQuery, + int tokenStart, + int tokenEnd, + int position, + int cursorOffset) { + + super(proposals, + proposal, + displayString, + additionalInfo, + image, + namedQuery, + jpqlQuery, + tokenStart, + tokenEnd, + position, + cursorOffset); + } + + /** + * {@inheritDoc} + */ + @Override + ResultQuery buildResult() { + return proposals.buildQuery( + jpqlQuery, + proposal, + position, + isCompletionInserts() ^ toggleCompletion + ); + } +}
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlJavaCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlJavaCompletionProposal.java new file mode 100644 index 0000000000..a787b7a0a8 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlJavaCompletionProposal.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation + * + ******************************************************************************/ +package org.eclipse.jpt.jpa.ui.internal.jpql; + +import org.eclipse.jpt.jpa.core.context.NamedQuery; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; +import org.eclipse.persistence.jpa.jpql.ResultQuery; +import org.eclipse.swt.graphics.Image; + +/** + * @version 3.3 + * @since 3.3 + * @author Pascal Filion + */ +final class JpqlJavaCompletionProposal extends JpqlCompletionProposal { + + JpqlJavaCompletionProposal(ContentAssistProposals proposals, + String proposal, + String displayString, + String additionalInfo, + Image image, + NamedQuery namedQuery, + String jpqlQuery, + int tokenStart, + int tokenEnd, + int position, + int cursorOffset) { + + super(proposals, + proposal, + displayString, + additionalInfo, + image, + namedQuery, + jpqlQuery, + tokenStart, + tokenEnd, + position, + cursorOffset); + } + + /** + * {@inheritDoc} + */ + @Override + ResultQuery buildResult() { + return proposals.buildEscapedQuery( + jpqlQuery, + proposal, + position, + isCompletionInserts() ^ toggleCompletion + ); + } +}
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java new file mode 100644 index 0000000000..992af926d7 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation + * + ******************************************************************************/ +package org.eclipse.jpt.jpa.ui.internal.jpql; + +import java.lang.reflect.Method; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.jpa.core.context.NamedQuery; +import org.eclipse.jpt.jpa.core.jpql.XmlEscapeCharacterConverter; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; +import org.eclipse.persistence.jpa.jpql.DefaultContentAssistProposals; +import org.eclipse.persistence.jpa.jpql.ExpressionTools; +import org.eclipse.persistence.jpa.jpql.ResultQuery; +import org.eclipse.persistence.jpa.jpql.WordParser; +import org.eclipse.swt.graphics.Image; + +/** + * @version 3.3 + * @since 3.3 + * @author Pascal Filion + */ +final class JpqlSseCompletionProposal extends JpqlCompletionProposal { + + private boolean cDATASection; + private int actualPosition; + private String actualJpqlQuery; + + JpqlSseCompletionProposal(ContentAssistProposals proposals, + String proposal, + String displayString, + String additionalInfo, + Image image, + NamedQuery namedQuery, + String jpqlQuery, + String actualJpqlQuery, + int tokenStart, + int tokenEnd, + int position, + int actualPosition, + int cursorOffset, + boolean cDATASection) { + + super(proposals, + proposal, + displayString, + additionalInfo, + image, + namedQuery, + jpqlQuery, + tokenStart, + tokenEnd, + position, + cursorOffset); + + this.actualPosition = actualPosition; + this.actualJpqlQuery = actualJpqlQuery; + this.cDATASection = cDATASection; + } + + /** + * {@inheritDoc} + */ + @Override + ResultQuery buildResult() { + + // No need to convert the JPQL query into an escaped version (like converting > into >) + if (cDATASection) { + return proposals.buildQuery( + jpqlQuery, + proposal, + position, + isCompletionInserts() ^ toggleCompletion + ); + } + + // TODO: UPDATE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE + return /*proposals.*/buildXmlQuery( + actualJpqlQuery, + proposal, + actualPosition, + isCompletionInserts() ^ toggleCompletion + ); + } + + /** + * TODO: TO DELETE ONCE USING THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE + */ + @SuppressWarnings("nls") + private ResultQuery buildXmlQuery(String jpqlQuery, String proposal, int position, boolean insert) { + + // Nothing to replace + if (ExpressionTools.stringIsEmpty(proposal)) { + return proposals.buildQuery(jpqlQuery, StringTools.EMPTY_STRING, position, false); + } + + int[] positions = { position }; + + // First convert the escape characters into their unicode characters + String query = XmlEscapeCharacterConverter.unescape(jpqlQuery, positions); + + // Calculate the start and end positions + WordParser wordParser = new WordParser(query); + wordParser.setPosition(positions[0]); + + // int[] proposalPositions = buildPositions(wordParser, proposal, insert); + int[] proposalPositions; + try { + Method buildPositionsMethod = DefaultContentAssistProposals.class.getDeclaredMethod("buildPositions", WordParser.class, String.class, boolean.class); + buildPositionsMethod.setAccessible(true); + proposalPositions = (int[]) buildPositionsMethod.invoke(proposals, wordParser, proposal, insert); + } + catch (Exception e) { + // This is temporary + proposalPositions = new int[2]; + } + + // Escape the proposal + proposal = XmlEscapeCharacterConverter.escape(proposal, new int[1]); + + // Adjust the positions so it's in the original JPQL query, which may contain escaped characters + XmlEscapeCharacterConverter.reposition(jpqlQuery, proposalPositions); + + // Create the new JPQL query + StringBuilder sb = new StringBuilder(jpqlQuery); + sb.replace(proposalPositions[0], proposalPositions[1], proposal); + + // And simply create a new ResultQuery object + return proposals.buildQuery(sb.toString(), StringTools.EMPTY_STRING, proposalPositions[0] + proposal.length(), false); + } +}
\ No newline at end of file |