blob: a9cdc03e05445979f5478b1dae79e3b2a5785226 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 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
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.sse.ui.internal;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentAdapter;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.formatter.FormattingContext;
import org.eclipse.jface.text.formatter.FormattingContextProperties;
import org.eclipse.jface.text.formatter.IContentFormatterExtension;
import org.eclipse.jface.text.formatter.IFormattingContext;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.projection.ProjectionDocument;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IOverviewRuler;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.wst.sse.core.internal.cleanup.StructuredContentCleanupHandler;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.undo.IDocumentSelectionMediator;
import org.eclipse.wst.sse.core.internal.undo.IStructuredTextUndoManager;
import org.eclipse.wst.sse.core.internal.undo.UndoDocumentEvent;
import org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration;
import org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.CompatibleHighlighter;
import org.eclipse.wst.sse.ui.internal.provisional.style.Highlighter;
import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.ReconcilerHighlighter;
import org.eclipse.wst.sse.ui.internal.reconcile.StructuredRegionProcessor;
import org.eclipse.wst.sse.ui.internal.util.PlatformStatusLineUtil;
/**
* <p>
* Like {@link org.eclipse.wst.sse.ui.StructuredTextEditor}, this class is not
* meant to be subclassed.<br />
*/
public class StructuredTextViewer extends ProjectionViewer implements IDocumentSelectionMediator {
/** Text operation codes */
private static final int BASE = ProjectionViewer.COLLAPSE_ALL; // see
// ProjectionViewer.COLLAPSE_ALL
private static final int CLEANUP_DOCUMENT = BASE + 4;
public static final int FORMAT_ACTIVE_ELEMENTS = BASE + 3;
private static final String FORMAT_ACTIVE_ELEMENTS_TEXT = SSEUIMessages.Format_Active_Elements_UI_; //$NON-NLS-1$
public static final int FORMAT_DOCUMENT = BASE + 2;
private static final String FORMAT_DOCUMENT_TEXT = SSEUIMessages.Format_Document_UI_; //$NON-NLS-1$
private static final String TEXT_CUT = SSEUIMessages.Text_Cut_UI_; //$NON-NLS-1$
private static final String TEXT_PASTE = SSEUIMessages.Text_Paste_UI_; //$NON-NLS-1$
private static final String TEXT_SHIFT_LEFT = SSEUIMessages.Text_Shift_Left_UI_; //$NON-NLS-1$ = "Text Shift Left"
private static final String TEXT_SHIFT_RIGHT = SSEUIMessages.Text_Shift_Right_UI_; //$NON-NLS-1$ = "Text Shift Right"
private static final boolean TRACE_EXCEPTIONS = true;
/*
* Max length of chars to format before it is considered a "big format"
* This is used to indication a small unrestricted rewrite session.
*/
private final int MAX_SMALL_FORMAT_LENGTH = 1000;
private boolean fBackgroundupdateInProgress;
private StructuredContentCleanupHandler fContentCleanupHandler = null;
//private IDocumentAdapter fDocAdapter;
private Highlighter fHighlighter;
private ReconcilerHighlighter fRecHighlighter = null;
// private ViewerSelectionManager fViewerSelectionManager;
private SourceViewerConfiguration fConfiguration;
/*
* True if formatter has been set
*/
private boolean fFormatterSet = false;
/**
* @see org.eclipse.jface.text.source.SourceViewer#SourceViewer(Composite,
* IVerticalRuler, IOverviewRuler, boolean, int)
*/
public StructuredTextViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean showAnnotationsOverview, int styles) {
super(parent, verticalRuler, overviewRuler, showAnnotationsOverview, styles);
}
/**
*
*/
private void beep() {
getTextWidget().getDisplay().beep();
}
public void beginBackgroundUpdate() {
fBackgroundupdateInProgress = true;
setRedraw(false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.ITextOperationTarget#canDoOperation(int)
*/
public boolean canDoOperation(int operation) {
if (fBackgroundupdateInProgress) {
return false;
}
switch (operation) {
case CONTENTASSIST_PROPOSALS : {
// (pa) if position isn't READ_ONLY (containsReadOnly()
// returns false),
// Otherwise, you DO want content assist (return true)
IDocument doc = getDocument();
if (doc != null && doc instanceof IStructuredDocument) {
return isEditable() && (!((IStructuredDocument) doc).containsReadOnly(getSelectedRange().x, 0));
}
break;
}
case CLEANUP_DOCUMENT : {
return (fContentCleanupHandler != null && isEditable());
}
case FORMAT_DOCUMENT :
case FORMAT_ACTIVE_ELEMENTS : {
// if formatter not set yet, contentformatter can be null
return ((fContentFormatter != null || !fFormatterSet) && isEditable());
}
}
return super.canDoOperation(operation);
}
/**
* Should be identical to superclass version. Plus, we get our own special
* Highlighter. Plus we uninstall before installing.
*/
public void configure(SourceViewerConfiguration configuration) {
if (getTextWidget() == null)
return;
setDocumentPartitioning(configuration.getConfiguredDocumentPartitioning(this));
// always uninstall highlighter and null it out on new configuration
if (fHighlighter != null) {
fHighlighter.uninstall();
fHighlighter = null;
}
if(fRecHighlighter != null) {
fRecHighlighter.uninstall();
fRecHighlighter = null;
}
// Bug 230297 - Uninstall presentation reconciler in preparation of a new one
if(fPresentationReconciler != null) {
fPresentationReconciler.uninstall();
fPresentationReconciler = null;
}
IReconciler newReconciler = configuration.getReconciler(this);
if (newReconciler != fReconciler || newReconciler == null || fReconciler == null) {
if (fReconciler != null) {
fReconciler.uninstall();
}
fReconciler = newReconciler;
if (fReconciler != null) {
fReconciler.install(this);
// https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3858
// still need set document on the reconciler (strategies)
if (fReconciler instanceof StructuredRegionProcessor)
((StructuredRegionProcessor) fReconciler).setDocument(getDocument());
}
}
IContentAssistant newAssistant = configuration.getContentAssistant(this);
if (newAssistant != fContentAssistant || newAssistant == null || fContentAssistant == null) {
if (fContentAssistant != null)
fContentAssistant.uninstall();
fContentAssistant = newAssistant;
if (fContentAssistant != null) {
fContentAssistant.install(this);
fContentAssistantInstalled = true;
}
else {
// 248036
// disable the content assist operation if no content
// assistant
enableOperation(CONTENTASSIST_PROPOSALS, false);
}
}
IQuickAssistAssistant quickAssistant = configuration.getQuickAssistAssistant(this);
if (quickAssistant != fQuickAssistAssistant || quickAssistant == null || fQuickAssistAssistant == null) {
if (fQuickAssistAssistant != null)
fQuickAssistAssistant.uninstall();
fQuickAssistAssistant = quickAssistant;
if (fQuickAssistAssistant != null) {
fQuickAssistAssistant.install(this);
fQuickAssistAssistantInstalled = true;
}
else {
// 248036
// disable the content assist operation if no content
// assistant
enableOperation(QUICK_ASSIST, false);
}
}
fContentFormatter = configuration.getContentFormatter(this);
// do not uninstall old information presenter if it's the same
IInformationPresenter newInformationPresenter = configuration.getInformationPresenter(this);
if (newInformationPresenter == null || fInformationPresenter == null || !(newInformationPresenter.equals(fInformationPresenter))) {
if (fInformationPresenter != null)
fInformationPresenter.uninstall();
fInformationPresenter = newInformationPresenter;
if (fInformationPresenter != null)
fInformationPresenter.install(this);
}
// disconnect from the old undo manager before setting the new one
if (fUndoManager != null) {
fUndoManager.disconnect();
}
setUndoManager(configuration.getUndoManager(this));
// release old annotation hover before setting new one
if (fAnnotationHover instanceof StructuredTextAnnotationHover) {
((StructuredTextAnnotationHover) fAnnotationHover).release();
}
setAnnotationHover(configuration.getAnnotationHover(this));
// release old annotation hover before setting new one
if (fOverviewRulerAnnotationHover instanceof StructuredTextAnnotationHover) {
((StructuredTextAnnotationHover) fOverviewRulerAnnotationHover).release();
}
setOverviewRulerAnnotationHover(configuration.getAnnotationHover(this));
getTextWidget().setTabs(configuration.getTabWidth(this));
setHoverControlCreator(configuration.getInformationControlCreator(this));
// if hyperlink manager has already been created, uninstall it
if (fHyperlinkManager != null) {
setHyperlinkDetectors(null, SWT.NONE);
}
setHyperlinkPresenter(configuration.getHyperlinkPresenter(this));
IHyperlinkDetector[] hyperlinkDetectors = configuration.getHyperlinkDetectors(this);
int eventStateMask = configuration.getHyperlinkStateMask(this);
setHyperlinkDetectors(hyperlinkDetectors, eventStateMask);
String[] types = configuration.getConfiguredContentTypes(this);
// clear autoindent/autoedit strategies
fAutoIndentStrategies = null;
for (int i = 0; i < types.length; i++) {
String t = types[i];
setAutoEditStrategies(configuration.getAutoEditStrategies(this, t), t);
setTextDoubleClickStrategy(configuration.getDoubleClickStrategy(this, t), t);
int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(this, t);
if (stateMasks != null) {
for (int j = 0; j < stateMasks.length; j++) {
int stateMask = stateMasks[j];
setTextHover(configuration.getTextHover(this, t, stateMask), t, stateMask);
}
}
else {
setTextHover(configuration.getTextHover(this, t), t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
}
String[] prefixes = configuration.getIndentPrefixes(this, t);
if (prefixes != null && prefixes.length > 0)
setIndentPrefixes(prefixes, t);
prefixes = configuration.getDefaultPrefixes(this, t);
if (prefixes != null && prefixes.length > 0)
setDefaultPrefixes(prefixes, t);
// Bug 230297 - Add LineStyleProviders from the new configuration if
// the document is set
if(getDocument() != null) {
// add highlighter/linestyleprovider
LineStyleProvider[] providers = ((StructuredTextViewerConfiguration) configuration).getLineStyleProviders(this, t);
if (providers != null) {
for (int j = 0; j < providers.length; ++j) {
if(fRecHighlighter == null) {
fRecHighlighter = new ReconcilerHighlighter();
((StructuredTextViewerConfiguration) configuration).setHighlighter(fRecHighlighter);
}
if (providers[j] instanceof AbstractLineStyleProvider) {
((AbstractLineStyleProvider) providers[j]).init((IStructuredDocument) getDocument(), fRecHighlighter);
fRecHighlighter.addProvider(t, providers[j]);
}
else {
// init with compatibility instance
if (fHighlighter == null) {
fHighlighter = new CompatibleHighlighter();
}
Logger.log(Logger.INFO_DEBUG, "CompatibleHighlighter installing compatibility for " + providers[j].getClass()); //$NON-NLS-1$
providers[j].init((IStructuredDocument) getDocument(), fHighlighter);
fHighlighter.addProvider(t, providers[j]);
}
}
}
}
}
// initialize highlighter after linestyleproviders were added
if (fHighlighter != null) {
fHighlighter.setDocumentPartitioning(configuration.getConfiguredDocumentPartitioning(this));
fHighlighter.setDocument((IStructuredDocument) getDocument());
fHighlighter.install(this);
}
if (fRecHighlighter != null)
fRecHighlighter.install(this);
activatePlugins();
fConfiguration = configuration;
// Update the viewer's presentation reconciler
fPresentationReconciler = configuration.getPresentationReconciler(this);
if(fPresentationReconciler != null)
fPresentationReconciler.install(this);
}
/**
* @param document
* @param startOffset
* @param endOffset
* @return
*/
private boolean containsReadOnly(IDocument document, int startOffset, int endOffset) {
int start = startOffset;
int end = endOffset;
IStructuredDocument structuredDocument = null;
if (document instanceof IStructuredDocument) {
structuredDocument = (IStructuredDocument) document;
}
else {
if (document instanceof ProjectionDocument) {
IDocument doc = ((ProjectionDocument) document).getMasterDocument();
if (doc instanceof IStructuredDocument) {
structuredDocument = (IStructuredDocument) doc;
int adjust = ((ProjectionDocument) document).getProjectionMapping().getCoverage().getOffset();
start = adjust + start;
end = adjust + end;
}
}
}
if (structuredDocument == null) {
return false;
}
else {
int length = end - start;
return structuredDocument.containsReadOnly(start, length);
}
}
/**
* @deprecated - present for compatibility only
*/
protected IDocumentAdapter createDocumentAdapter() {
return super.createDocumentAdapter();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.ITextOperationTarget#doOperation(int)
*/
public void doOperation(int operation) {
Point selection = getTextWidget().getSelection();
int cursorPosition = selection.x;
int selectionLength = selection.y - selection.x;
switch (operation) {
case CUT :
beginRecording(TEXT_CUT, TEXT_CUT, cursorPosition, selectionLength);
super.doOperation(operation);
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
break;
case PASTE :
beginRecording(TEXT_PASTE, TEXT_PASTE, cursorPosition, selectionLength);
super.doOperation(operation);
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
break;
case CONTENTASSIST_PROPOSALS :
// maybe not configured?
if (fContentAssistant != null && isEditable()) {
// CMVC 263269
// need an explicit check here because the
// contentAssistAction is no longer being updated on
// cursor
// position
if (canDoOperation(CONTENTASSIST_PROPOSALS)) {
String err = fContentAssistant.showPossibleCompletions();
if (err != null) {
// don't wanna beep if there is no error
PlatformStatusLineUtil.displayErrorMessage(err);
}
PlatformStatusLineUtil.addOneTimeClearListener();
}
else
beep();
}
break;
case CONTENTASSIST_CONTEXT_INFORMATION :
if (fContentAssistant != null) {
String err = fContentAssistant.showContextInformation();
if (err != null) {
// don't wanna beep if there is no error
PlatformStatusLineUtil.displayErrorMessage(err);
}
PlatformStatusLineUtil.addOneTimeClearListener();
}
break;
case SHIFT_RIGHT :
beginRecording(TEXT_SHIFT_RIGHT, TEXT_SHIFT_RIGHT, cursorPosition, selectionLength);
updateIndentationPrefixes();
super.doOperation(SHIFT_RIGHT);
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
break;
case SHIFT_LEFT :
beginRecording(TEXT_SHIFT_LEFT, TEXT_SHIFT_LEFT, cursorPosition, selectionLength);
updateIndentationPrefixes();
super.doOperation(SHIFT_LEFT);
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
break;
case FORMAT_DOCUMENT :
DocumentRewriteSession rewriteSession = null;
IDocument document = getDocument();
try {
/*
* This command will actually format selection if text is
* selected, otherwise format entire document
*/
// begin recording
beginRecording(FORMAT_DOCUMENT_TEXT, FORMAT_DOCUMENT_TEXT, cursorPosition, selectionLength);
boolean formatDocument = false;
IRegion region = null;
Point s = getSelectedRange();
if (s.y > 0) {
// only format currently selected text
region = new Region(s.x, s.y);
}
else {
// no selection, so format entire document
region = getModelCoverage();
formatDocument = true;
}
if (document instanceof IDocumentExtension4) {
IDocumentExtension4 extension = (IDocumentExtension4) document;
DocumentRewriteSessionType type = (selection.y == 0 || selection.y > MAX_SMALL_FORMAT_LENGTH) ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
rewriteSession = (extension.getActiveRewriteSession() != null) ? null : extension.startRewriteSession(type);
}
else {
setRedraw(false);
}
if (fContentFormatter instanceof IContentFormatterExtension) {
IContentFormatterExtension extension = (IContentFormatterExtension) fContentFormatter;
IFormattingContext context = new FormattingContext();
context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.valueOf(formatDocument));
context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
extension.format(document, context);
}
else {
fContentFormatter.format(document, region);
}
}
finally {
try {
if (rewriteSession != null) {
IDocumentExtension4 extension = (IDocumentExtension4) document;
extension.stopRewriteSession(rewriteSession);
}
else {
setRedraw(true);
}
}
finally {
// end recording
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
}
}
break;
case FORMAT_ACTIVE_ELEMENTS :
rewriteSession = null;
document = getDocument();
try {
/*
* This command will format the node at cursor position
* (and all its children)
*/
// begin recording
beginRecording(FORMAT_ACTIVE_ELEMENTS_TEXT, FORMAT_ACTIVE_ELEMENTS_TEXT, cursorPosition, selectionLength);
IRegion region = null;
Point s = getSelectedRange();
if (s.y > -1) {
// only format node at cursor position
region = new Region(s.x, s.y);
}
if (document instanceof IDocumentExtension4) {
IDocumentExtension4 extension = (IDocumentExtension4) document;
DocumentRewriteSessionType type = (selection.y == 0 || selection.y > MAX_SMALL_FORMAT_LENGTH) ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
rewriteSession = (extension.getActiveRewriteSession() != null) ? null : extension.startRewriteSession(type);
}
else {
setRedraw(false);
}
if (fContentFormatter instanceof IContentFormatterExtension) {
IContentFormatterExtension extension = (IContentFormatterExtension) fContentFormatter;
IFormattingContext context = new FormattingContext();
context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.FALSE);
context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
extension.format(getDocument(), context);
}
else {
fContentFormatter.format(getDocument(), region);
}
}
finally {
try {
if (rewriteSession != null) {
IDocumentExtension4 extension = (IDocumentExtension4) document;
extension.stopRewriteSession(rewriteSession);
}
else {
setRedraw(true);
}
}
finally {
// end recording
selection = getTextWidget().getSelection();
cursorPosition = selection.x;
selectionLength = selection.y - selection.x;
endRecording(cursorPosition, selectionLength);
}
}
break;
default :
super.doOperation(operation);
}
}
private void endRecording(int cursorPosition, int selectionLength) {
IDocument doc = getDocument();
if (doc instanceof IStructuredDocument) {
IStructuredDocument structuredDocument = (IStructuredDocument) doc;
IStructuredTextUndoManager undoManager = structuredDocument.getUndoManager();
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=198617
// undo after paste in document with folds - wrong behavior
IRegion widgetSelection = new Region(cursorPosition, selectionLength);
IRegion documentSelection = widgetRange2ModelRange(widgetSelection);
if (documentSelection == null)
documentSelection = widgetSelection;
undoManager.endRecording(this, documentSelection.getOffset(), documentSelection.getLength());
}
else {
// TODO: how to handle other document types?
}
}
private void beginRecording(String label, String description, int cursorPosition, int selectionLength) {
IDocument doc = getDocument();
if (doc instanceof IStructuredDocument) {
IStructuredDocument structuredDocument = (IStructuredDocument) doc;
IStructuredTextUndoManager undoManager = structuredDocument.getUndoManager();
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=198617
// undo after paste in document with folds - wrong behavior
IRegion widgetSelection = new Region(cursorPosition, selectionLength);
IRegion documentSelection = widgetRange2ModelRange(widgetSelection);
if (documentSelection == null)
documentSelection = widgetSelection;
undoManager.beginRecording(this, label, description, documentSelection.getOffset(), documentSelection.getLength());
}
else {
// TODO: how to handle other document types?
}
}
public void endBackgroundUpdate() {
fBackgroundupdateInProgress = false;
setRedraw(true);
}
protected void handleDispose() {
Logger.trace("Source Editor", "StructuredTextViewer::handleDispose entry"); //$NON-NLS-1$ //$NON-NLS-2$
// before we dispose, we set a special "empty" selection, to prevent
// the "leak one document" that
// otherwise occurs when editor closed (since last selection stays in
// SelectedResourceManager.
// the occurance of the "leak" isn't so bad, but makes debugging other
// leaks very hard.
setSelection(TextSelection.emptySelection());
if (fHighlighter != null) {
fHighlighter.uninstall();
fHighlighter = null;
}
if (fRecHighlighter != null) {
fRecHighlighter.uninstall();
fRecHighlighter = null;
}
super.handleDispose();
Logger.trace("Source Editor", "StructuredTextViewer::handleDispose exit"); //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* Overridden for special support of background update and read-only
* regions
*/
protected void handleVerifyEvent(VerifyEvent e) {
IRegion modelRange = event2ModelRange(e);
if (exposeModelRange(modelRange)) {
e.doit = false;
return;
}
if (fEventConsumer != null) {
fEventConsumer.processEvent(e);
if (!e.doit)
return;
}
if (fBackgroundupdateInProgress) {
e.doit = false;
beep();
return;
}
// for read-only support
if (containsReadOnly(getVisibleDocument(), e.start, e.end)) {
e.doit = false;
beep();
return;
}
try {
super.handleVerifyEvent(e);
}
catch (Exception x) {
/*
* Note, we catch and log any exception, since an otherwise can
* actually prevent typing! see
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=111318
*/
if (TRACE_EXCEPTIONS)
Logger.logException("StructuredTextViewer.exception.verifyText", x); //$NON-NLS-1$
}
}
public int modelLine2WidgetLine(int modelLine) {
/**
* need to override this method as a workaround for Bug 85709
*/
if (fInformationMapping == null) {
IDocument document = getDocument();
if (document != null) {
try {
IRegion modelLineRegion = getDocument().getLineInformation(modelLine);
IRegion region = getModelCoverage();
if (modelLineRegion != null && region != null) {
int modelEnd = modelLineRegion.getOffset() + modelLineRegion.getLength();
int regionEnd = region.getOffset() + region.getLength();
// returns -1 if modelLine is invalid
if ((modelLineRegion.getOffset() < region.getOffset()) || (modelEnd > regionEnd))
return -1;
}
}
catch (BadLocationException e) {
// returns -1 if modelLine is invalid
return -1;
}
}
}
return super.modelLine2WidgetLine(modelLine);
}
public int modelOffset2WidgetOffset(int modelOffset) {
/**
* need to override this method as a workaround for Bug 85709
*/
if (fInformationMapping == null) {
IRegion region = getModelCoverage();
if (region != null) {
// returns -1 if modelOffset is invalid
if (modelOffset < region.getOffset() || modelOffset > (region.getOffset() + region.getLength()))
return -1;
}
}
return super.modelOffset2WidgetOffset(modelOffset);
}
public IRegion modelRange2WidgetRange(IRegion modelRange) {
// need to override this method as workaround for Bug85709
if (fInformationMapping == null) {
IRegion region = getModelCoverage();
if (region != null && modelRange != null) {
int modelEnd = modelRange.getOffset() + modelRange.getLength();
int regionEnd = region.getOffset() + region.getLength();
// returns null if modelRange is invalid
if ((modelRange.getOffset() < region.getOffset()) || (modelEnd > regionEnd))
return null;
}
}
return super.modelRange2WidgetRange(modelRange);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.source.ISourceViewer#setDocument(org.eclipse.jface.text.IDocument,
* org.eclipse.jface.text.source.IAnnotationModel, int, int)
*/
public void setDocument(IDocument document, IAnnotationModel annotationModel, int modelRangeOffset, int modelRangeLength) {
// partial fix for:
// https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=1970
// when our document is set, especially to null during close,
// immediately uninstall the reconciler.
// this is to avoid an unnecessary final "reconcile"
// that blocks display thread
if (document == null) {
if (fReconciler != null) {
fReconciler.uninstall();
}
}
super.setDocument(document, annotationModel, modelRangeOffset, modelRangeLength);
if (document instanceof IStructuredDocument) {
IStructuredDocument structuredDocument = (IStructuredDocument) document;
// notify highlighter
updateHighlighter(structuredDocument);
// set the formatter again now that document has been set
if (!fFormatterSet && fConfiguration != null) {
fContentFormatter = fConfiguration.getContentFormatter(this);
fFormatterSet = true;
}
// set document in the viewer-based undo manager
if (fUndoManager != null) {
fUndoManager.disconnect();
fUndoManager.connect(this);
}
// CaretEvent is not sent to ViewerSelectionManager after Save As.
// Need to notify ViewerSelectionManager here.
// notifyViewerSelectionManager(getSelectedRange().x,
// getSelectedRange().y);
}
}
/**
* Use the active editor to set a status line message
*
* @param msg
*/
private void setErrorMessage(String msg) {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
IEditorPart editor = page.getActiveEditor();
if (editor != null) {
IEditorStatusLine statusLine = (IEditorStatusLine) editor.getAdapter(IEditorStatusLine.class);
if (statusLine != null)
statusLine.setMessage(true, msg, null);
}
}
}
}
/**
* Uninstalls anything that was installed by configure
*/
public void unconfigure() {
Logger.trace("Source Editor", "StructuredTextViewer::unconfigure entry"); //$NON-NLS-1$ //$NON-NLS-2$
if (fHighlighter != null) {
fHighlighter.uninstall();
fHighlighter = null;
}
if (fRecHighlighter != null) {
fRecHighlighter.uninstall();
fRecHighlighter = null;
}
if (fAnnotationHover instanceof StructuredTextAnnotationHover) {
((StructuredTextAnnotationHover) fAnnotationHover).release();
}
if (fOverviewRulerAnnotationHover instanceof StructuredTextAnnotationHover) {
((StructuredTextAnnotationHover) fOverviewRulerAnnotationHover).release();
}
// doesn't seem to be handled elsewhere, so we'll be sure error
// messages's are cleared.
setErrorMessage(null);
super.unconfigure();
fConfiguration = null;
Logger.trace("Source Editor", "StructuredTextViewer::unconfigure exit"); //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* (non-Javadoc)
*
* @see org.eclipse.wst.sse.core.undo.IDocumentSelectionMediator#undoOperationSelectionChanged(org.eclipse.wst.sse.core.undo.UndoDocumentEvent)
*/
public void undoOperationSelectionChanged(UndoDocumentEvent event) {
if (event.getRequester() != null && event.getRequester().equals(this) && event.getDocument().equals(getDocument())) {
// BUG107687: Undo/redo do not scroll editor
ITextSelection selection = new TextSelection(event.getOffset(), event.getLength());
setSelection(selection, true);
}
}
private void updateHighlighter(IStructuredDocument document) {
boolean documentSet = false;
// if highlighter has not been created yet, initialize and install it
if (fRecHighlighter == null && fConfiguration instanceof StructuredTextViewerConfiguration) {
String[] types = fConfiguration.getConfiguredContentTypes(this);
for (int i = 0; i < types.length; i++) {
String t = types[i];
// add highlighter/linestyleprovider
LineStyleProvider[] providers = ((StructuredTextViewerConfiguration) fConfiguration).getLineStyleProviders(this, t);
if (providers != null) {
for (int j = 0; j < providers.length; ++j) {
if(fRecHighlighter == null) {
fRecHighlighter = new ReconcilerHighlighter();
((StructuredTextViewerConfiguration) fConfiguration).setHighlighter(fRecHighlighter);
}
if (providers[j] instanceof AbstractLineStyleProvider) {
((AbstractLineStyleProvider) providers[j]).init(document, fRecHighlighter);
fRecHighlighter.addProvider(t, providers[j]);
}
else {
// init with compatibility instance
if (fHighlighter == null) {
fHighlighter = new CompatibleHighlighter();
}
Logger.log(Logger.INFO_DEBUG, "CompatibleHighlighter installing compatibility for " + providers[j].getClass()); //$NON-NLS-1$
providers[j].init(document, fHighlighter);
fHighlighter.addProvider(t, providers[j]);
}
}
}
}
if(fRecHighlighter != null)
fRecHighlighter.install(this);
if(fHighlighter != null) {
fHighlighter.setDocumentPartitioning(fConfiguration.getConfiguredDocumentPartitioning(this));
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=203347
// make sure to set document before install
fHighlighter.setDocument(document);
fHighlighter.install(this);
documentSet = true;
}
}
if (fHighlighter != null && !documentSet)
fHighlighter.setDocument(document);
// install content type independent plugins
if (fPresentationReconciler != null)
fPresentationReconciler.uninstall();
// 228847 - XSL Content Assist tests fail with Null Pointer on Highlighter
if(fConfiguration != null)
fPresentationReconciler = fConfiguration.getPresentationReconciler(this);
if (fPresentationReconciler != null)
fPresentationReconciler.install(this);
}
/**
* Make sure indentation is correct before using.
*/
private void updateIndentationPrefixes() {
SourceViewerConfiguration configuration = fConfiguration;
if (fConfiguration != null) {
String[] types = configuration.getConfiguredContentTypes(this);
for (int i = 0; i < types.length; i++) {
String[] prefixes = configuration.getIndentPrefixes(this, types[i]);
if (prefixes != null && prefixes.length > 0)
setIndentPrefixes(prefixes, types[i]);
}
}
}
}