blob: 79350978328b20e64e1791b3f0e4a2c9f96c35fc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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
* Alex Panchenko <alex@xored.com>
*******************************************************************************/
package org.eclipse.dltk.internal.ui.editor;
import java.util.ArrayList;
import org.eclipse.core.runtime.Assert;
import org.eclipse.dltk.ui.text.ScriptSourceViewerConfiguration;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextPresentationListener;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.reconciler.IReconciler;
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.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
public class ScriptSourceViewer extends ProjectionViewer implements
IPropertyChangeListener {
/**
* Text operation code for requesting the outline for the current input.
*/
public static final int SHOW_OUTLINE = 51;
/**
* Text operation code for requesting the outline for the element at the
* current position.
*/
public static final int OPEN_STRUCTURE = 52;
/**
* Text operation code for requesting the hierarchy for the current input.
*/
public static final int SHOW_HIERARCHY = 53;
private IInformationPresenter fOutlinePresenter;
private IInformationPresenter fStructurePresenter;
private IInformationPresenter fHierarchyPresenter;
/**
* This viewer's foreground color.
*/
private Color fForegroundColor;
/**
* The viewer's background color.
*/
private Color fBackgroundColor;
/**
* This viewer's selection foreground color.
*/
private Color fSelectionForegroundColor;
/**
* The viewer's selection background color.
*/
private Color fSelectionBackgroundColor;
/**
* The preference store.
*/
private IPreferenceStore fPreferenceStore;
/**
* Is this source viewer configured?
*/
private boolean fIsConfigured;
// /**
// * The backspace manager of this viewer.
// *
// */
// private SmartBackspaceManager fBackspaceManager;
/**
* Whether to delay setting the visual document until the projection has
* been computed.
* <p>
* Added for performance optimization.
* </p>
*
* @see #prepareDelayedProjection()
*/
private boolean fIsSetVisibleDocumentDelayed = false;
public ScriptSourceViewer(Composite parent, IVerticalRuler verticalRuler,
IOverviewRuler overviewRuler, boolean showAnnotationsOverview,
int styles, IPreferenceStore store) {
super(parent, verticalRuler, overviewRuler, showAnnotationsOverview,
styles);
setPreferenceStore(store);
}
@Override
public void doOperation(int operation) {
if (getTextWidget() == null)
return;
switch (operation) {
case SHOW_OUTLINE:
if (fOutlinePresenter != null)
fOutlinePresenter.showInformation();
return;
case OPEN_STRUCTURE:
if (fStructurePresenter != null)
fStructurePresenter.showInformation();
return;
case SHOW_HIERARCHY:
if (fHierarchyPresenter != null)
fHierarchyPresenter.showInformation();
return;
}
super.doOperation(operation);
}
@Override
public boolean canDoOperation(int operation) {
if (operation == SHOW_OUTLINE)
return fOutlinePresenter != null;
if (operation == OPEN_STRUCTURE)
return fStructurePresenter != null;
if (operation == SHOW_HIERARCHY)
return fHierarchyPresenter != null;
return super.canDoOperation(operation);
}
@Override
public void configure(SourceViewerConfiguration configuration) {
/*
* Prevent access to colors disposed in unconfigure(), see:
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=53641
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=86177
*/
StyledText textWidget = getTextWidget();
if (textWidget != null && !textWidget.isDisposed()) {
Color foregroundColor = textWidget.getForeground();
if (foregroundColor != null && foregroundColor.isDisposed())
textWidget.setForeground(null);
Color backgroundColor = textWidget.getBackground();
if (backgroundColor != null && backgroundColor.isDisposed())
textWidget.setBackground(null);
}
super.configure(configuration);
if (configuration instanceof ScriptSourceViewerConfiguration) {
ScriptSourceViewerConfiguration dltkSVCconfiguration = (ScriptSourceViewerConfiguration) configuration;
fOutlinePresenter = dltkSVCconfiguration.getOutlinePresenter(this,
false);
if (fOutlinePresenter != null)
fOutlinePresenter.install(this);
fStructurePresenter = dltkSVCconfiguration.getOutlinePresenter(
this, true);
if (fStructurePresenter != null)
fStructurePresenter.install(this);
fHierarchyPresenter = dltkSVCconfiguration.getHierarchyPresenter(
this, true);
if (fHierarchyPresenter != null)
fHierarchyPresenter.install(this);
if (textWidget != null) {
textWidget.setFont(JFaceResources.getFont(dltkSVCconfiguration
.getFontPropertyPreferenceKey()));
}
}
if (fPreferenceStore != null) {
fPreferenceStore.addPropertyChangeListener(this);
initializeViewerColors();
}
fIsConfigured = true;
}
public void initializeViewerColors() {
if (fPreferenceStore != null) {
StyledText styledText = getTextWidget();
// ----------- foreground color --------------------
Color color = fPreferenceStore
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT) ? null
: createColor(fPreferenceStore,
AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND,
styledText.getDisplay());
styledText.setForeground(color);
if (fForegroundColor != null)
fForegroundColor.dispose();
fForegroundColor = color;
// ---------- background color ----------------------
color = fPreferenceStore
.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT) ? null
: createColor(fPreferenceStore,
AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND,
styledText.getDisplay());
styledText.setBackground(color);
if (fBackgroundColor != null)
fBackgroundColor.dispose();
fBackgroundColor = color;
// ----------- selection foreground color --------------------
color = fPreferenceStore
.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_DEFAULT_COLOR) ? null
: createColor(
fPreferenceStore,
AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_COLOR,
styledText.getDisplay());
styledText.setSelectionForeground(color);
if (fSelectionForegroundColor != null)
fSelectionForegroundColor.dispose();
fSelectionForegroundColor = color;
// ---------- selection background color ----------------------
color = fPreferenceStore
.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_DEFAULT_COLOR) ? null
: createColor(
fPreferenceStore,
AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_COLOR,
styledText.getDisplay());
styledText.setSelectionBackground(color);
if (fSelectionBackgroundColor != null)
fSelectionBackgroundColor.dispose();
fSelectionBackgroundColor = color;
}
}
/**
* Creates a color from the information stored in the given preference
* store. Returns <code>null</code> if there is no such information
* available.
*
* @param store
* the store to read from
* @param key
* the key used for the lookup in the preference store
* @param display
* the display used create the color
* @return the created color according to the specification in the
* preference store
*/
private Color createColor(IPreferenceStore store, String key,
Display display) {
RGB rgb = null;
if (store.contains(key)) {
if (store.isDefault(key))
rgb = PreferenceConverter.getDefaultColor(store, key);
else
rgb = PreferenceConverter.getColor(store, key);
if (rgb != null)
return new Color(display, rgb);
}
return null;
}
@Override
public void unconfigure() {
if (fOutlinePresenter != null) {
fOutlinePresenter.uninstall();
fOutlinePresenter = null;
}
if (fStructurePresenter != null) {
fStructurePresenter.uninstall();
fStructurePresenter = null;
}
if (fHierarchyPresenter != null) {
fHierarchyPresenter.uninstall();
fHierarchyPresenter = null;
}
if (fForegroundColor != null) {
fForegroundColor.dispose();
fForegroundColor = null;
}
if (fBackgroundColor != null) {
fBackgroundColor.dispose();
fBackgroundColor = null;
}
if (fPreferenceStore != null)
fPreferenceStore.removePropertyChangeListener(this);
super.unconfigure();
fIsConfigured = false;
}
@Override
public Point rememberSelection() {
return super.rememberSelection();
}
@Override
public void restoreSelection() {
super.restoreSelection();
}
@Override
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
if (AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND.equals(property)
|| AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT
.equals(property)
|| AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND
.equals(property)
|| AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT
.equals(property)
|| AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_COLOR
.equals(property)
|| AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_DEFAULT_COLOR
.equals(property)
|| AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_COLOR
.equals(property)
|| AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_DEFAULT_COLOR
.equals(property)) {
initializeViewerColors();
}
}
/**
* Sets the preference store on this viewer.
*
* @param store
* the preference store
*/
public void setPreferenceStore(IPreferenceStore store) {
if (fIsConfigured && fPreferenceStore != null)
fPreferenceStore.removePropertyChangeListener(this);
fPreferenceStore = store;
if (fIsConfigured && fPreferenceStore != null) {
fPreferenceStore.addPropertyChangeListener(this);
initializeViewerColors();
}
}
@Override
public void resetVisibleRegion() {
super.resetVisibleRegion();
// re-enable folding if ProjectionViewer failed to due so
// TODO: Add editor folding option here.
if (fPreferenceStore != null && !isProjectionMode())
enableProjection();
/*
* && fPreferenceStore.getBoolean(PreferenceConstants.
* EDITOR_FOLDING_ENABLED)
*/
}
@Override
protected void createControl(Composite parent, int styles) {
// Use LEFT_TO_RIGHT unless otherwise specified.
if ((styles & SWT.RIGHT_TO_LEFT) == 0
&& (styles & SWT.LEFT_TO_RIGHT) == 0)
styles |= SWT.LEFT_TO_RIGHT;
super.createControl(parent, styles);
// System.err.println("Add backup manager");
// fBackspaceManager= new SmartBackspaceManager();
// fBackspaceManager.install(this);
}
@Override
protected void handleDispose() {
// if (fBackspaceManager != null) {
// fBackspaceManager.uninstall();
// fBackspaceManager = null;
// }
super.handleDispose();
}
/**
* Prepends the text presentation listener at the beginning of the viewer's
* list of text presentation listeners. If the listener is already
* registered with the viewer this call moves the listener to the beginning
* of the list.
*
* @param listener
* the text presentation listener
*/
public void prependTextPresentationListener(
ITextPresentationListener listener) {
Assert.isNotNull(listener);
if (fTextPresentationListeners == null)
fTextPresentationListeners = new ArrayList();
fTextPresentationListeners.remove(listener);
fTextPresentationListeners.add(0, listener);
}
/**
* Sets the given reconciler.
*
* @param reconciler
* the reconciler
*/
void setReconciler(IReconciler reconciler) {
fReconciler = reconciler;
}
/**
* Returns the reconciler.
*
* @return the reconciler or <code>null</code> if not set
*/
IReconciler getReconciler() {
return fReconciler;
}
/**
* Delays setting the visual document until after the projection has been
* computed. This method must only be called before the document is set on
* the viewer.
* <p>
* This is a performance optimization to reduce the computation of the text
* presentation triggered by <code>setVisibleDocument(IDocument)</code>.
* </p>
*
* @see #setVisibleDocument(IDocument)
*/
void prepareDelayedProjection() {
Assert.isTrue(!fIsSetVisibleDocumentDelayed);
fIsSetVisibleDocumentDelayed = true;
}
/**
* {@inheritDoc}
* <p>
* This is a performance optimization to reduce the computation of the text
* presentation triggered by {@link #setVisibleDocument(IDocument)}
* </p>
*
* @see #prepareDelayedProjection()
*/
@Override
protected void setVisibleDocument(IDocument document) {
if (fIsSetVisibleDocumentDelayed) {
fIsSetVisibleDocumentDelayed = false;
IDocument previous = getVisibleDocument();
// will set the visible document if anything is folded
enableProjection();
IDocument current = getVisibleDocument();
// if the visible document was not replaced, continue as usual
if (current != null && current != previous)
return;
}
super.setVisibleDocument(document);
}
/**
* {@inheritDoc}
* <p>
* Performance optimization: since we know at this place that none of the
* clients expects the given range to be untouched we reuse the given range
* as return value.
* </p>
*/
@Override
protected StyleRange modelStyleRange2WidgetStyleRange(StyleRange range) {
IRegion region = modelRange2WidgetRange(new Region(range.start,
range.length));
if (region != null) {
// don't clone the style range, but simply reuse it.
range.start = region.getOffset();
range.length = region.getLength();
return range;
}
return null;
}
}