| package org.eclipse.cdt.internal.ui.text.contentassist; |
| |
| /* |
| * (c) Copyright QNX Software Systems Ltd. 2002. |
| * All Rights Reserved. |
| */ |
| |
| import org.eclipse.cdt.internal.ui.text.link.LinkedPositionManager; |
| import org.eclipse.cdt.internal.ui.text.link.LinkedPositionUI; |
| import org.eclipse.cdt.internal.ui.text.link.LinkedPositionUI.ExitFlags; |
| import org.eclipse.cdt.ui.text.ICCompletionProposal; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.contentassist.ICompletionProposalExtension; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jface.util.Assert; |
| import org.eclipse.swt.events.VerifyEvent; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| |
| public class CCompletionProposal implements ICCompletionProposal, ICompletionProposalExtension { |
| private String fDisplayString; |
| private String fReplacementString; |
| private String fAdditionalInfoString; |
| private int fReplacementOffset; |
| private int fReplacementLength; |
| private int fCursorPosition; |
| private Image fImage; |
| private IContextInformation fContextInformation; |
| private int fContextInformationPosition; |
| //private IImportDeclaration fImportDeclaration; |
| private char[] fTriggerCharacters; |
| protected ITextViewer fTextViewer; |
| |
| private int fRelevance; |
| |
| /** |
| * Creates a new completion proposal. All fields are initialized based on the provided information. |
| * |
| * @param replacementString the actual string to be inserted into the document |
| * @param replacementOffset the offset of the text to be replaced |
| * @param replacementLength the length of the text to be replaced |
| * @param image the image to display for this proposal |
| * @param displayString the string to be displayed for the proposal |
| * If set to <code>null</code>, the replacement string will be taken as display string. |
| */ |
| public CCompletionProposal(String replacementString, int replacementOffset, int replacementLength, Image image, String displayString, int relevance, ITextViewer viewer) { |
| Assert.isNotNull(replacementString); |
| Assert.isTrue(replacementOffset >= 0); |
| Assert.isTrue(replacementLength >= 0); |
| |
| fReplacementString= replacementString; |
| fReplacementOffset= replacementOffset; |
| fReplacementLength= replacementLength; |
| fImage= image; |
| fDisplayString= displayString != null ? displayString : replacementString; |
| fRelevance= relevance; |
| fTextViewer= viewer; |
| |
| //@@@ Is this the best way to do this, likely it isn't |
| if(replacementString.indexOf("()") == -1) { //Not replacing with a function |
| fCursorPosition = replacementString.length(); |
| } else if(displayString.indexOf("()") == -1) { //Assume that there are arguments between () |
| fCursorPosition = replacementString.length() - 1; |
| } else { |
| fCursorPosition = replacementString.length(); |
| } |
| |
| fAdditionalInfoString = null; |
| fContextInformation= null; |
| fContextInformationPosition= -1; |
| //fIncludeDeclaration= null; |
| fTriggerCharacters= null; |
| } |
| |
| /** |
| * Sets the context information. |
| * @param contentInformation The context information associated with this proposal |
| */ |
| public void setContextInformation(IContextInformation contextInformation) { |
| fContextInformation= contextInformation; |
| fContextInformationPosition= (fContextInformation != null ? fCursorPosition : -1); |
| } |
| |
| /** |
| * Sets the import declaration to import when applied. |
| * @param importDeclaration Optional import declaration to be added. Can be <code>null</code>. The underlying compilation unit |
| * is assumed to be compatible with the document passed in <code>apply</code>. |
| * |
| public void setIncludeDeclaration(IImportDeclaration importDeclaration) { |
| fIncludeDeclaration= importDeclaration; |
| } */ |
| |
| /** |
| * Sets the trigger characters. |
| * @param triggerCharacters The set of characters which can trigger the application of this completion proposal |
| */ |
| public void setTriggerCharacters(char[] triggerCharacters) { |
| fTriggerCharacters= triggerCharacters; |
| } |
| |
| /** |
| * Sets the cursor position relative to the insertion offset. By default this is the length of the completion string |
| * (Cursor positioned after the completion) |
| * @param cursorPosition The cursorPosition to set |
| */ |
| public void setCursorPosition(int cursorPosition) { |
| Assert.isTrue(cursorPosition >= 0); |
| fCursorPosition= cursorPosition; |
| fContextInformationPosition= (fContextInformation != null ? fCursorPosition : -1); |
| } |
| |
| /* protected void addInclude(IRequiredInclude[] inc, CFileElementWorkingCopy tu) { |
| AddIncludeOperation op= new AddIncludeOperation(fEditor, tu, inc, false); |
| try { |
| ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell()); |
| dialog.run(false, true, op); |
| } catch (InvocationTargetException e) { |
| e.printStackTrace(); |
| MessageDialog.openError(getShell(), CEditorMessages.getString("AddIncludeOnSelection.error.message1"), e.getTargetException().getMessage()); //$NON-NLS-1$ |
| } catch (InterruptedException e) { |
| // Do nothing. Operation has been canceled. |
| } |
| } */ |
| |
| protected void applyIncludes(IDocument document) { |
| //AddIncludeOperation(ITextEditor ed, CFileElementWorkingCopy tu, IRequiredInclude[] includes, boolean save) { |
| |
| //if (fIncludeDeclaration == null) { |
| return; |
| //} |
| |
| /* ICompilationUnit cu= (ICompilationUnit) JavaModelUtil.findElementOfKind(fImportDeclaration, IJavaElement.COMPILATION_UNIT); |
| if (cu != null) { |
| try { |
| IType[] types= cu.getTypes(); |
| if (types.length == 0 || types[0].getSourceRange().getOffset() > fReplacementOffset) { |
| // do not add import for code assist on import statements |
| return; |
| } |
| |
| String[] prefOrder= ImportOrganizePreferencePage.getImportOrderPreference(); |
| int threshold= ImportOrganizePreferencePage.getImportNumberThreshold(); |
| ImportsStructure impStructure= new ImportsStructure(cu, prefOrder, threshold, true); |
| |
| impStructure.addImport(fImportDeclaration.getElementName()); |
| // will modify the document as the CU works on the document |
| impStructure.create(false, null); |
| |
| } catch (CoreException e) { |
| JavaPlugin.log(e); |
| } |
| } */ |
| } |
| |
| /* |
| * @see ICompletionProposal#apply |
| */ |
| public void apply(IDocument document) { |
| apply(document, (char) 0, fReplacementOffset + fReplacementLength); |
| } |
| |
| /* |
| * In this case we need to apply the completion proposal intelligently. |
| * This means that if we are applying it to a function, we don't wipe |
| * out the internal arguments, and if the proposal is a function, and it |
| * already is bracketed, then don't put those brackets in. |
| * |
| * @see ICompletionProposalExtension#apply(IDocument, char, int) |
| */ |
| public void apply(IDocument document, char trigger, int offset) { |
| int functionBracketIndex; |
| boolean isBeforeBracket; |
| String replacementStringCopy = fReplacementString; |
| fReplacementLength = offset - fReplacementOffset; |
| //If just providing context information, then don't move the cursor |
| // if(offset != (fReplacementOffset + fReplacementLength)) { |
| // fCursorPosition = offset - fReplacementOffset; |
| // } |
| |
| try { |
| functionBracketIndex = fReplacementString.indexOf("()"); |
| isBeforeBracket = document.getChar(fReplacementOffset + fReplacementLength) == '('; |
| |
| //Strip the brackets off the function if inserting right before brackets |
| if(functionBracketIndex != -1 && isBeforeBracket) { |
| replacementStringCopy = fReplacementString.substring(0, functionBracketIndex); |
| } |
| } catch(Exception ex) { |
| /* Ignore */ |
| } |
| |
| try { |
| String string; |
| if (trigger == (char) 0) { |
| string= fReplacementString; |
| replace(document, fReplacementOffset, fReplacementLength, replacementStringCopy); |
| } else { |
| StringBuffer buffer= new StringBuffer(replacementStringCopy); |
| |
| // fix for PR #5533. Assumes that no eating takes place. |
| if ((fCursorPosition > 0 && fCursorPosition <= buffer.length() && buffer.charAt(fCursorPosition - 1) != trigger)) { |
| buffer.insert(fCursorPosition, trigger); |
| ++fCursorPosition; |
| } |
| |
| string= buffer.toString(); |
| replace(document, fReplacementOffset, fReplacementLength, string); |
| } |
| |
| if (fTextViewer != null && string != null) { |
| int index= string.indexOf("()"); //$NON-NLS-1$ |
| if (index != -1 && index + 1 == fCursorPosition) { |
| //IPreferenceStore preferenceStore= JavaPlugin.getDefault().getPreferenceStore(); |
| //if (preferenceStore.getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACKETS)) { |
| int newOffset= fReplacementOffset + fCursorPosition; |
| |
| LinkedPositionManager manager= new LinkedPositionManager(document); |
| manager.addPosition(newOffset, 0); |
| |
| LinkedPositionUI editor= new LinkedPositionUI(fTextViewer, manager); |
| editor.setExitPolicy(new ExitPolicy(')')); |
| editor.setFinalCaretOffset(newOffset + 1); |
| editor.enter(); |
| //} |
| } |
| } |
| |
| /* |
| * The replacement length is used to calculate the new cursor position, |
| * so after we update the includes adjust the replacement offset. |
| * NOTE: This won't work if the include is added after the offset, |
| * such as might be the case with #include completions. |
| */ |
| int oldLen= document.getLength(); |
| applyIncludes(document); |
| fReplacementOffset += document.getLength() - oldLen; |
| |
| } catch (BadLocationException x) { |
| // ignore |
| } |
| } |
| |
| // #6410 - File unchanged but dirtied by code assist |
| private void replace(IDocument document, int offset, int length, String string) throws BadLocationException { |
| if (!document.get(offset, length).equals(string)) |
| document.replace(offset, length, string); |
| } |
| |
| /* |
| * @see ICompletionProposal#getSelection |
| */ |
| public Point getSelection(IDocument document) { |
| return new Point(fReplacementOffset + fCursorPosition, 0); |
| } |
| |
| /* |
| * @see ICompletionProposal#getContextInformation() |
| */ |
| public IContextInformation getContextInformation() { |
| return fContextInformation; |
| } |
| |
| /* |
| * @see ICompletionProposal#getImage() |
| */ |
| public Image getImage() { |
| return fImage; |
| } |
| |
| /* |
| * @see ICompletionProposal#getDisplayString() |
| */ |
| public String getDisplayString() { |
| return fDisplayString; |
| } |
| |
| /** |
| * Set the additional information which will be shown when this |
| * proposal is selected in the popup list. |
| * @param infoString |
| */ |
| public void setAdditionalProposalInfo(String infoString) { |
| fAdditionalInfoString = infoString; |
| } |
| |
| /* |
| * @see ICompletionProposal#getAdditionalProposalInfo() |
| */ |
| public String getAdditionalProposalInfo() { |
| return fAdditionalInfoString; |
| } |
| |
| /* |
| * @see ICompletionProposalExtension#getTriggerCharacters() |
| */ |
| public char[] getTriggerCharacters() { |
| return fTriggerCharacters; |
| } |
| |
| /* |
| * @see ICompletionProposalExtension#getContextInformationPosition() |
| */ |
| public int getContextInformationPosition() { |
| return fReplacementOffset + fContextInformationPosition; |
| } |
| |
| /* |
| * @see ICompletionProposalExtension#isValidFor(IDocument, int) |
| */ |
| public boolean isValidFor(IDocument document, int offset) { |
| if (offset < fReplacementOffset) |
| return false; |
| |
| int replacementLength= fReplacementString == null ? 0 : fReplacementString.length(); |
| if (offset > fReplacementOffset + replacementLength) |
| return false; |
| |
| try { |
| int length= offset - fReplacementOffset; |
| String start= document.get(fReplacementOffset, length); |
| return fReplacementString.substring(0, length).equalsIgnoreCase(start); |
| } catch (BadLocationException x) { |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Gets the replacement offset. |
| * @return Returns a int |
| */ |
| public int getReplacementOffset() { |
| return fReplacementOffset; |
| } |
| |
| /** |
| * Sets the replacement offset. |
| * @param replacementOffset The replacement offset to set |
| */ |
| public void setReplacementOffset(int replacementOffset) { |
| Assert.isTrue(replacementOffset >= 0); |
| fReplacementOffset= replacementOffset; |
| } |
| |
| /** |
| * Gets the replacement length. |
| * @return Returns a int |
| */ |
| public int getReplacementLength() { |
| return fReplacementLength; |
| } |
| |
| /** |
| * Sets the replacement length. |
| * @param replacementLength The replacementLength to set |
| */ |
| public void setReplacementLength(int replacementLength) { |
| Assert.isTrue(replacementLength >= 0); |
| fReplacementLength= replacementLength; |
| } |
| |
| /** |
| * Gets the replacement string. |
| * @return Returns a String |
| */ |
| public String getReplacementString() { |
| return fReplacementString; |
| } |
| |
| /** |
| * Sets the replacement string. |
| * @param replacementString The replacement string to set |
| */ |
| public void setReplacementString(String replacementString) { |
| fReplacementString= replacementString; |
| } |
| |
| /** |
| * Sets the image. |
| * @param image The image to set |
| */ |
| public void setImage(Image image) { |
| fImage= image; |
| } |
| |
| /** |
| * Gets the proposal's relevance. |
| * @return Returns a int |
| */ |
| public int getRelevance() { |
| return fRelevance; |
| } |
| |
| /** |
| * Sets the proposal's relevance. |
| * @param relevance The relevance to set |
| */ |
| public void setRelevance(int relevance) { |
| fRelevance= relevance; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.lang.Object#hashCode() |
| */ |
| public int hashCode() { |
| return fDisplayString.hashCode() |
| + fReplacementString.hashCode() |
| + ((fAdditionalInfoString == null) ? 0 : fAdditionalInfoString.hashCode()); |
| } |
| /* (non-Javadoc) |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| public boolean equals(Object other) { |
| if(!(other instanceof CCompletionProposal)) |
| return false; |
| if(!(fDisplayString.equals(((CCompletionProposal)other).fDisplayString))) |
| return false; |
| if(!(fReplacementString.equals(((CCompletionProposal)other).fReplacementString))) |
| return false; |
| if((fAdditionalInfoString != null) && (((CCompletionProposal)other).fAdditionalInfoString != null) && (!(fAdditionalInfoString.equals(((CCompletionProposal)other).fAdditionalInfoString)))) |
| return false; |
| |
| return true; |
| } |
| |
| private static class ExitPolicy implements LinkedPositionUI.ExitPolicy { |
| |
| final char fExitCharacter; |
| |
| public ExitPolicy(char exitCharacter) { |
| fExitCharacter= exitCharacter; |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int) |
| */ |
| public ExitFlags doExit(LinkedPositionManager manager, VerifyEvent event, int offset, int length) { |
| |
| if (event.character == fExitCharacter) { |
| if (manager.anyPositionIncludes(offset, length)) |
| return new ExitFlags(LinkedPositionUI.COMMIT| LinkedPositionUI.UPDATE_CARET, false); |
| else |
| return new ExitFlags(LinkedPositionUI.COMMIT, true); |
| } |
| |
| switch (event.character) { |
| case '\b': |
| if (manager.getFirstPosition().length == 0) |
| return new ExitFlags(0, true); |
| else |
| return null; |
| |
| case '\n': |
| case '\r': |
| case ';': |
| return new ExitFlags(LinkedPositionUI.COMMIT, true); |
| |
| default: |
| return null; |
| } |
| } |
| |
| } |
| |
| } |
| |