/*=============================================================================# # Copyright (c) 2008-2016 Stephan Wahlbrink (WalWare.de) 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: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.ecommons.ltk.ui.sourceediting.assist; import java.util.Objects; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3; import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.StyledString; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import de.walware.ecommons.ltk.IElementName; import de.walware.ecommons.ltk.core.model.IModelElement; import de.walware.ecommons.ltk.ui.IElementLabelProvider; /** * Proposal completing a given {@link IElementName} of a element. */ public abstract class ElementNameCompletionProposal<E extends IModelElement> extends CompletionProposalWithOverwrite implements ICompletionProposalExtension3, ICompletionProposalExtension6 { private final IElementName replacementName; private final E element; private final int relevance; private final IElementLabelProvider labelProvider; /** The cursor position after this proposal has been applied. */ private int cursorPosition= -1; public ElementNameCompletionProposal(final AssistInvocationContext context, final IElementName replacementName, final int replacementOffset, final E element, final int relevance, final IElementLabelProvider labelProvider) { super(context, replacementOffset); this.replacementName= replacementName; this.element= element; this.labelProvider= labelProvider; this.relevance= relevance; } public final E getElement() { return this.element; } protected IElementLabelProvider getLabelProvider() { return this.labelProvider; } /** * {@inheritDoc} */ @Override public Image getImage() { return this.labelProvider.getImage(getElement()); } /** * {@inheritDoc} */ @Override public String getDisplayString() { return this.labelProvider.getText(getElement()); } /** * {@inheritDoc} */ @Override public StyledString getStyledDisplayString() { return this.labelProvider.getStyledText(getElement()); } /** * {@inheritDoc} */ @Override public String getAdditionalProposalInfo() { return null; } /** * {@inheritDoc} */ @Override public int getRelevance() { return this.relevance; } public IElementName getReplacementName() { return this.replacementName; } @Override public String getSortingString() { return getReplacementName().getSegmentName(); } /** * {@inheritDoc} */ @Override public boolean validate(final IDocument document, final int offset, final DocumentEvent event) { try { final String content= document.get(getReplacementOffset(), offset - getReplacementOffset()); if (this.getReplacementName().getSegmentName().regionMatches(true, 0, content, 0, content.length())) { return true; } } catch (final BadLocationException e) { // ignore concurrently modified document } return false; } /** * {@inheritDoc} */ @Override public boolean isAutoInsertable() { return false; } @Override protected void doApply(final char trigger, final int stateMask, final int caretOffset, final int replacementOffset, final int replacementLength) throws BadLocationException { final AssistInvocationContext context= getInvocationContext(); final SourceViewer viewer= context.getSourceViewer(); final IDocument document= viewer.getDocument(); final StringBuilder replacement= new StringBuilder(this.getReplacementName().getDisplayName()); document.replace(replacementOffset, replacementLength, replacement.toString()); setCursorPosition(replacementOffset + replacement.length()); } protected void setCursorPosition(final int offset) { this.cursorPosition= offset; } /** * {@inheritDoc} * * This implementation returns <code>null</code> */ @Override public IContextInformation getContextInformation() { return null; } /** * {@inheritDoc} */ @Override public Point getSelection(final IDocument document) { if (this.cursorPosition >= 0) { return new Point(this.cursorPosition, 0); } return null; } @Override public int getPrefixCompletionStart(final IDocument document, final int offset) { return getReplacementOffset(); } @Override public CharSequence getPrefixCompletionText(final IDocument document, final int offset) { return null; } @Override public IInformationControlCreator getInformationControlCreator() { return null; } @Override public int hashCode() { return getClass().hashCode() * Objects.hashCode(getReplacementName()); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (getClass() == obj.getClass()) { final ElementNameCompletionProposal<?> other= (ElementNameCompletionProposal<?>) obj; return (Objects.equals(getReplacementName(), other.getReplacementName()) && Objects.equals(getElement(), other.getElement()) ); } return false; } }