blob: 6e3aaccfaecc2d80821da8c8c880a0cce60a9bc1 [file] [log] [blame]
package org.eclipse.jface.text.source;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.jface.text.AbstractHoverInformationControlManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.formatter.IContentFormatter;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.reconciler.IReconciler;
/**
* SWT based implementation of <code>ISourceViewer</code>. The same rules apply
* as for <code>TextViewer</code>. A source viewer uses an <code>IVerticalRuler</code>
* as its annotation presentation area. The vertical ruler is a small strip shown left
* of the viewer's text widget.<p>
* Clients are supposed to instantiate a source viewer and subsequently to communicate
* with it exclusively using the <code>ISourceViewer</code> interface. Clients should not
* subclass this class as it is rather likely that subclasses will be broken by future releases.
*/
public class SourceViewer extends TextViewer implements ISourceViewer {
/**
* Layout of a source viewer. Vertical ruler and text widget are shown side by side.
*/
class RulerLayout extends Layout {
protected int fGap;
protected RulerLayout(int gap) {
fGap= gap;
}
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Control[] children= composite.getChildren();
Point s= children[children.length - 1].computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
if (fVerticalRuler != null && fIsVerticalRulerVisible)
s.x += fVerticalRuler.getWidth() + fGap;
return s;
}
protected void layout(Composite composite, boolean flushCache) {
Rectangle clArea= composite.getClientArea();
if (fVerticalRuler != null && fIsVerticalRulerVisible) {
Rectangle trim= getTextWidget().computeTrim(0, 0, 0, 0);
int scrollbarHeight= trim.height;
int rulerWidth= fVerticalRuler.getWidth();
fVerticalRuler.getControl().setBounds(0, 0, rulerWidth, clArea.height - scrollbarHeight);
getTextWidget().setBounds(rulerWidth + fGap, 0, clArea.width - rulerWidth - fGap, clArea.height);
} else
getTextWidget().setBounds(0, 0, clArea.width, clArea.height);
}
};
/** The viewer's content assistant */
protected IContentAssistant fContentAssistant;
/** The viewer's content formatter */
protected IContentFormatter fContentFormatter;
/** The viewer's model reconciler */
protected IReconciler fReconciler;
/** The viewer's presentation reconciler */
protected IPresentationReconciler fPresentationReconciler;
/** The viewer's annotation hover */
protected IAnnotationHover fAnnotationHover;
/** The viewer's information presenter */
protected IInformationPresenter fInformationPresenter;
/** Visual vertical ruler */
private IVerticalRuler fVerticalRuler;
/** Visibility of vertical ruler */
private boolean fIsVerticalRulerVisible;
/** The SWT widget used when supporting a vertical ruler */
private Composite fComposite;
/** The vertical ruler's annotation model */
private VisualAnnotationModel fVisualAnnotationModel;
/** The viewer's range indicator to be shown in the vertical ruler */
private Annotation fRangeIndicator;
/** The viewer's vertical ruler hovering controller */
private AbstractHoverInformationControlManager fVerticalRulerHoveringController;
/** The size of the gap between the vertical ruler and the text widget */
protected final static int GAP_SIZE= 2;
/**
* Constructs a new source viewer. The vertical ruler is initially visible.
* The viewer has not yet been initialized with a source viewer configuration.
*
* @param parent the parent of the viewer's control
* @param ruler the vertical ruler used by this source viewer
* @patam styles the SWT style bits
*/
public SourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
super();
fVerticalRuler= ruler;
fIsVerticalRulerVisible= (ruler != null);
createControl(parent, styles);
}
/*
* @see TextViewer#createControl
*/
protected void createControl(Composite parent, int styles) {
if (fVerticalRuler != null) {
styles= (styles & ~SWT.BORDER);
fComposite= new Canvas(parent, SWT.NONE);
fComposite.setLayout(new RulerLayout(GAP_SIZE));
parent= fComposite;
}
super.createControl(parent, styles);
if (fComposite != null)
fVerticalRuler.createControl(fComposite, this);
}
/*
* @see TextViewer#getControl
*/
public Control getControl() {
if (fComposite != null)
return fComposite;
return super.getControl();
}
/*
* @see ISourceViewer#setAnnotationHover
*/
public void setAnnotationHover(IAnnotationHover annotationHover) {
fAnnotationHover= annotationHover;
}
/*
* @see ISourceViewer#configure
*/
public void configure(SourceViewerConfiguration configuration) {
if (getTextWidget() == null)
return;
// install content type independent plugins
fPresentationReconciler= configuration.getPresentationReconciler(this);
if (fPresentationReconciler != null)
fPresentationReconciler.install(this);
fReconciler= configuration.getReconciler(this);
if (fReconciler != null)
fReconciler.install(this);
fContentAssistant= configuration.getContentAssistant(this);
if (fContentAssistant != null)
fContentAssistant.install(this);
fContentFormatter= configuration.getContentFormatter(this);
fInformationPresenter= configuration.getInformationPresenter(this);
if (fInformationPresenter != null)
fInformationPresenter.install(this);
setUndoManager(configuration.getUndoManager(this));
getTextWidget().setTabs(configuration.getTabWidth(this));
setAnnotationHover(configuration.getAnnotationHover(this));
setHoverControlCreator(configuration.getInformationControlCreator(this));
// install content type specific plugins
String[] types= configuration.getConfiguredContentTypes(this);
for (int i= 0; i < types.length; i++) {
String t= types[i];
setAutoIndentStrategy(configuration.getAutoIndentStrategy(this, t), t);
setTextDoubleClickStrategy(configuration.getDoubleClickStrategy(this, t), t);
setTextHover(configuration.getTextHover(this, t), t);
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);
}
activatePlugins();
}
/*
* @see TextViewer#activatePlugins
*/
public void activatePlugins() {
if (fVerticalRuler != null && fAnnotationHover != null && fVerticalRulerHoveringController == null) {
fVerticalRulerHoveringController= new AnnotationBarHoverManager(this, fVerticalRuler, fAnnotationHover, fHoverControlCreator);
fVerticalRulerHoveringController.install(fVerticalRuler.getControl());
}
super.activatePlugins();
}
/*
* @see ISourceViewer#setDocument(IDocument, IAnnotationModel)
*/
public void setDocument(IDocument document) {
setDocument(document, null, -1, -1);
}
/*
* @see ISourceViewer#setDocument(IDocument, IAnnotationModel, int, int)
*/
public void setDocument(IDocument document, int visibleRegionOffset, int visibleRegionLength) {
setDocument(document, null, visibleRegionOffset, visibleRegionLength);
}
/*
* @see ISourceViewer#setDocument(IDocument, IAnnotationModel)
*/
public void setDocument(IDocument document, IAnnotationModel annotationModel) {
setDocument(document, annotationModel, -1, -1);
}
/*
* @see ISourceViewer#setDocument(IDocument, IAnnotationModel, int, int)
*/
public void setDocument(IDocument document, IAnnotationModel annotationModel, int visibleRegionOffset, int visibleRegionLength) {
if (fVerticalRuler == null) {
if (visibleRegionOffset == -1 && visibleRegionLength == -1)
super.setDocument(document);
else
super.setDocument(document, visibleRegionOffset, visibleRegionLength);
} else {
if (fVisualAnnotationModel != null && getDocument() != null)
fVisualAnnotationModel.disconnect(getDocument());
if (visibleRegionOffset == -1 && visibleRegionLength == -1)
super.setDocument(document);
else
super.setDocument(document, visibleRegionOffset, visibleRegionLength);
if (annotationModel != null && document != null) {
fVisualAnnotationModel= new VisualAnnotationModel(annotationModel);
fVisualAnnotationModel.connect(document);
} else {
fVisualAnnotationModel= null;
}
fVerticalRuler.setModel(fVisualAnnotationModel);
}
}
/*
* @see ISourceViewer#getAnnotationModel
*/
public IAnnotationModel getAnnotationModel() {
if (fVisualAnnotationModel != null)
return fVisualAnnotationModel.getModelAnnotationModel();
return null;
}
/*
* @see TextViewer#handleDispose
*/
protected void handleDispose() {
if (fPresentationReconciler != null) {
fPresentationReconciler.uninstall();
fPresentationReconciler= null;
}
if (fReconciler != null) {
fReconciler.uninstall();
fReconciler= null;
}
if (fContentAssistant != null) {
fContentAssistant.uninstall();
fContentAssistant= null;
}
fContentFormatter= null;
if (fInformationPresenter != null) {
fInformationPresenter.uninstall();
fInformationPresenter= null;
}
if (fVisualAnnotationModel != null && getDocument() != null) {
fVisualAnnotationModel.disconnect(getDocument());
fVisualAnnotationModel= null;
}
fVerticalRuler= null;
if (fVerticalRulerHoveringController != null) {
fVerticalRulerHoveringController.dispose();
fVerticalRulerHoveringController= null;
}
super.handleDispose();
}
/*
* @see ITextOperationTarget#canDoOperation
*/
public boolean canDoOperation(int operation) {
if (getTextWidget() == null)
return false;
if (operation == CONTENTASSIST_PROPOSALS)
return fContentAssistant != null && isEditable();
if (operation == CONTENTASSIST_CONTEXT_INFORMATION)
return fContentAssistant != null;
if (operation == INFORMATION)
return fInformationPresenter != null;
if (operation == FORMAT) {
Point p= getSelectedRange();
int length= (p == null ? -1 : p.y);
return (fContentFormatter != null && isEditable() && (length == 0 || isBlockSelected()));
}
return super.canDoOperation(operation);
}
/*
* @see ITextOperationTarget#doOperation
*/
public void doOperation(int operation) {
if (getTextWidget() == null)
return;
switch (operation) {
case CONTENTASSIST_PROPOSALS:
fContentAssistant.showPossibleCompletions();
return;
case CONTENTASSIST_CONTEXT_INFORMATION:
fContentAssistant.showContextInformation();
return;
case INFORMATION:
fInformationPresenter.showInformation();
return;
case FORMAT: {
Point s= getSelectedRange();
IDocument document= getDocument();
Position p= new Position(s.x, s.y);
IRegion r= (s.y == 0) ? getVisibleRegion() : new Region(s.x, s.y);
try {
document.addPosition(p);
fContentFormatter.format(document, r);
setSelectedRange(p.getOffset(), p.getLength());
} catch (BadLocationException e) {
// should not happen
} finally {
document.removePosition(p);
}
return;
}
default:
super.doOperation(operation);
}
}
/*
* @see ISourceViewer#setRangeIndicator
*/
public void setRangeIndicator(Annotation rangeIndicator) {
fRangeIndicator= rangeIndicator;
}
/*
* @see ISourceViewer#setRangeIndication
*/
public void setRangeIndication(int start, int length, boolean moveCursor) {
if (moveCursor) {
setSelectedRange(start, 0);
revealRange(start, length);
}
if (fRangeIndicator != null && fVisualAnnotationModel != null)
fVisualAnnotationModel.modifyAnnotation(fRangeIndicator, new Position(start, length));
}
/*
* @see ISourceViewer#getRangeIndication
*/
public IRegion getRangeIndication() {
if (fRangeIndicator != null && fVisualAnnotationModel != null) {
Position position= fVisualAnnotationModel.getPosition(fRangeIndicator);
if (position != null)
return new Region(position.getOffset(), position.getLength());
}
return null;
}
/*
* @see ISourceViewer#removeRangeIndication
*/
public void removeRangeIndication() {
if (fRangeIndicator != null && fVisualAnnotationModel != null)
fVisualAnnotationModel.modifyAnnotation(fRangeIndicator, null);
}
/*
* @see ISourceViewer#showAnnotations
*/
public void showAnnotations(boolean show) {
boolean old= fIsVerticalRulerVisible;
fIsVerticalRulerVisible= (show && fVerticalRuler != null);
if (old != fIsVerticalRulerVisible)
fComposite.layout();
}
}