org.eclipse.jface.text.templates.TemplateProposal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.jface.text Show documentation
Show all versions of org.eclipse.jface.text Show documentation
This is org.eclipse.jface.text jar used by Scout SDK
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2008 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.jface.text.templates;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.link.ILinkedModeListener;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedModeUI;
import org.eclipse.jface.text.link.LinkedPosition;
import org.eclipse.jface.text.link.LinkedPositionGroup;
import org.eclipse.jface.text.link.ProposalPosition;
/**
* A template completion proposal.
*
* Clients may subclass.
*
* @since 3.0
*/
public class TemplateProposal implements ICompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3 {
private final Template fTemplate;
private final TemplateContext fContext;
private final Image fImage;
private final IRegion fRegion;
private int fRelevance;
private IRegion fSelectedRegion; // initialized by apply()
private String fDisplayString;
private InclusivePositionUpdater fUpdater;
private IInformationControlCreator fInformationControlCreator;
/**
* Creates a template proposal with a template and its context.
*
* @param template the template
* @param context the context in which the template was requested.
* @param region the region this proposal is applied to
* @param image the icon of the proposal.
*/
public TemplateProposal(Template template, TemplateContext context, IRegion region, Image image) {
this(template, context, region, image, 0);
}
/**
* Creates a template proposal with a template and its context.
*
* @param template the template
* @param context the context in which the template was requested.
* @param image the icon of the proposal.
* @param region the region this proposal is applied to
* @param relevance the relevance of the proposal
*/
public TemplateProposal(Template template, TemplateContext context, IRegion region, Image image, int relevance) {
Assert.isNotNull(template);
Assert.isNotNull(context);
Assert.isNotNull(region);
fTemplate= template;
fContext= context;
fImage= image;
fRegion= region;
fDisplayString= null;
fRelevance= relevance;
}
/**
* Sets the information control creator for this completion proposal.
*
* @param informationControlCreator the information control creator
* @since 3.1
*/
public final void setInformationControlCreator(IInformationControlCreator informationControlCreator) {
fInformationControlCreator= informationControlCreator;
}
/**
* Returns the template of this proposal.
*
* @return the template of this proposal
* @since 3.1
*/
protected final Template getTemplate() {
return fTemplate;
}
/**
* Returns the context in which the template was requested.
*
* @return the context in which the template was requested
* @since 3.1
*/
protected final TemplateContext getContext() {
return fContext;
}
/**
* {@inheritDoc}
*
* @deprecated This method is no longer called by the framework and clients should overwrite
* {@link #apply(ITextViewer, char, int, int)} instead
*/
@Deprecated
@Override
public final void apply(IDocument document) {
// not called anymore
}
/**
* Inserts the template offered by this proposal into the viewer's document
* and sets up a LinkedModeUI
on the viewer to edit any of
* the template's unresolved variables.
*
* @param viewer {@inheritDoc}
* @param trigger {@inheritDoc}
* @param stateMask {@inheritDoc}
* @param offset {@inheritDoc}
*/
@Override
public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
IDocument document= viewer.getDocument();
try {
fContext.setReadOnly(false);
int start;
TemplateBuffer templateBuffer;
{
int oldReplaceOffset= getReplaceOffset();
try {
// this may already modify the document (e.g. add imports)
templateBuffer= fContext.evaluate(fTemplate);
} catch (TemplateException e1) {
fSelectedRegion= fRegion;
return;
}
start= getReplaceOffset();
int shift= start - oldReplaceOffset;
int end= Math.max(getReplaceEndOffset(), offset + shift);
// insert template string
String templateString= templateBuffer.getString();
document.replace(start, end - start, templateString);
}
// translate positions
LinkedModeModel model= new LinkedModeModel();
TemplateVariable[] variables= templateBuffer.getVariables();
boolean hasPositions= false;
for (int i= 0; i != variables.length; i++) {
TemplateVariable variable= variables[i];
if (variable.isUnambiguous())
continue;
LinkedPositionGroup group= new LinkedPositionGroup();
int[] offsets= variable.getOffsets();
int length= variable.getLength();
LinkedPosition first;
{
String[] values= variable.getValues();
ICompletionProposal[] proposals= new ICompletionProposal[values.length];
for (int j= 0; j < values.length; j++) {
ensurePositionCategoryInstalled(document, model);
Position pos= new Position(offsets[0] + start, length);
document.addPosition(getCategory(), pos);
proposals[j]= new PositionBasedCompletionProposal(values[j], pos, length);
}
if (proposals.length > 1)
first= new ProposalPosition(document, offsets[0] + start, length, proposals);
else
first= new LinkedPosition(document, offsets[0] + start, length);
}
for (int j= 0; j != offsets.length; j++)
if (j == 0)
group.addPosition(first);
else
group.addPosition(new LinkedPosition(document, offsets[j] + start, length));
model.addGroup(group);
hasPositions= true;
}
if (hasPositions) {
model.forceInstall();
LinkedModeUI ui= new LinkedModeUI(model, viewer);
ui.setExitPosition(viewer, getCaretOffset(templateBuffer) + start, 0, Integer.MAX_VALUE);
ui.enter();
fSelectedRegion= ui.getSelectedRegion();
} else {
ensurePositionCategoryRemoved(document);
fSelectedRegion= new Region(getCaretOffset(templateBuffer) + start, 0);
}
} catch (BadLocationException e) {
openErrorDialog(viewer.getTextWidget().getShell(), e);
ensurePositionCategoryRemoved(document);
fSelectedRegion= fRegion;
} catch (BadPositionCategoryException e) {
openErrorDialog(viewer.getTextWidget().getShell(), e);
fSelectedRegion= fRegion;
}
}
private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) {
if (!document.containsPositionCategory(getCategory())) {
document.addPositionCategory(getCategory());
fUpdater= new InclusivePositionUpdater(getCategory());
document.addPositionUpdater(fUpdater);
model.addLinkingListener(new ILinkedModeListener() {
@Override
public void left(LinkedModeModel environment, int flags) {
ensurePositionCategoryRemoved(document);
}
@Override
public void suspend(LinkedModeModel environment) {}
@Override
public void resume(LinkedModeModel environment, int flags) {}
});
}
}
private void ensurePositionCategoryRemoved(IDocument document) {
if (document.containsPositionCategory(getCategory())) {
try {
document.removePositionCategory(getCategory());
} catch (BadPositionCategoryException e) {
// ignore
}
document.removePositionUpdater(fUpdater);
}
}
private String getCategory() {
return "TemplateProposalCategory_" + toString(); //$NON-NLS-1$
}
private int getCaretOffset(TemplateBuffer buffer) {
TemplateVariable[] variables= buffer.getVariables();
for (int i= 0; i != variables.length; i++) {
TemplateVariable variable= variables[i];
if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME))
return variable.getOffsets()[0];
}
return buffer.getString().length();
}
/**
* Returns the offset of the range in the document that will be replaced by
* applying this template.
*
* @return the offset of the range in the document that will be replaced by
* applying this template
* @since 3.1
*/
protected final int getReplaceOffset() {
int start;
if (fContext instanceof DocumentTemplateContext) {
DocumentTemplateContext docContext = (DocumentTemplateContext)fContext;
start= docContext.getStart();
} else {
start= fRegion.getOffset();
}
return start;
}
/**
* Returns the end offset of the range in the document that will be replaced
* by applying this template.
*
* @return the end offset of the range in the document that will be replaced
* by applying this template
* @since 3.1
*/
protected final int getReplaceEndOffset() {
int end;
if (fContext instanceof DocumentTemplateContext) {
DocumentTemplateContext docContext = (DocumentTemplateContext)fContext;
end= docContext.getEnd();
} else {
end= fRegion.getOffset() + fRegion.getLength();
}
return end;
}
@Override
public Point getSelection(IDocument document) {
return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
}
@Override
public String getAdditionalProposalInfo() {
try {
fContext.setReadOnly(true);
TemplateBuffer templateBuffer;
try {
templateBuffer= fContext.evaluate(fTemplate);
} catch (TemplateException e) {
return null;
}
return templateBuffer.getString();
} catch (BadLocationException e) {
return null;
}
}
@Override
public String getDisplayString() {
if (fDisplayString == null) {
String[] arguments= new String[] { fTemplate.getName(), fTemplate.getDescription() };
fDisplayString= JFaceTextTemplateMessages.getFormattedString("TemplateProposal.displayString", arguments); //$NON-NLS-1$
}
return fDisplayString;
}
@Override
public Image getImage() {
return fImage;
}
@Override
public IContextInformation getContextInformation() {
return null;
}
private void openErrorDialog(Shell shell, Exception e) {
MessageDialog.openError(shell, JFaceTextTemplateMessages.getString("TemplateProposal.errorDialog.title"), e.getMessage()); //$NON-NLS-1$
}
/**
* Returns the relevance.
*
* @return the relevance
*/
public int getRelevance() {
return fRelevance;
}
@Override
public IInformationControlCreator getInformationControlCreator() {
return fInformationControlCreator;
}
@Override
public void selected(ITextViewer viewer, boolean smartToggle) {
}
@Override
public void unselected(ITextViewer viewer) {
}
@Override
public boolean validate(IDocument document, int offset, DocumentEvent event) {
try {
int replaceOffset= getReplaceOffset();
if (offset >= replaceOffset) {
String content= document.get(replaceOffset, offset - replaceOffset);
return fTemplate.getName().toLowerCase().startsWith(content.toLowerCase());
}
} catch (BadLocationException e) {
// concurrent modification - ignore
}
return false;
}
@Override
public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
return fTemplate.getName();
}
@Override
public int getPrefixCompletionStart(IDocument document, int completionOffset) {
return getReplaceOffset();
}
/**
* {@inheritDoc}
*
* @deprecated This method is no longer called by the framework and clients should overwrite
* {@link #apply(ITextViewer, char, int, int)} instead
*/
@Deprecated
@Override
public void apply(IDocument document, char trigger, int offset) {
// not called any longer
}
@Override
public boolean isValidFor(IDocument document, int offset) {
// not called any longer
return false;
}
@Override
public char[] getTriggerCharacters() {
// no triggers
return new char[0];
}
@Override
public int getContextInformationPosition() {
return fRegion.getOffset();
}
}