blob: b30518087dc8cf72d974efd8df3dcfccaf17f7bb [file] [log] [blame]
package org.eclipse.jface.text;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.jface.text.AbstractHoverInformationControlManager;
import org.eclipse.jface.text.IInformationControlCreator;
/**
* This manager controls the layout, content, visibility, etc. of an information
* control in reaction to mouse hover events issued by the text widget of a
* text viewer.
*/
class TextViewerHoverManager extends AbstractHoverInformationControlManager {
/** The text viewer */
private TextViewer fTextViewer;
/**
* Creates a new text viewer hover manager specific for the given text viewer.
* The manager uses the given information control creator.
*
* @param textViewer the viewer for which the controller is created
* @param creator the information control creator
*/
public TextViewerHoverManager(TextViewer textViewer, IInformationControlCreator creator) {
super(creator);
fTextViewer= textViewer;
}
/**
* @see AbstractHoverInformationControlManager#computeInformation
*/
protected void computeInformation() {
Point location= getHoverEventLocation();
int offset= computeOffsetAtLocation(location.x, location.y);
if (offset == -1)
return;
ITextHover hover= fTextViewer.getTextHover(offset);
if (hover == null)
return;
IRegion region= hover.getHoverRegion(fTextViewer, offset);
if (region == null)
return;
setInformation(hover.getHoverInfo(fTextViewer, region), computeArea(region));
}
/**
* Computes the document offset underlying the given text widget coordinates.
* This method uses a linear search as it cannot make any assumption about
* how the document is actually presented in the widget. (Covers cases such
* as bidi text.)
*
* @param x the x coordinate inside the text widget
* @param y the y coordinate inside the text widget
* @return the document offset corresponding to the given point
*/
private int computeOffsetAtLocation(int x, int y) {
IDocument document= fTextViewer.getVisibleDocument();
StyledText styledText= fTextViewer.getTextWidget();
int line= (y + styledText.getTopPixel()) / styledText.getLineHeight();
int lineCount= document.getNumberOfLines();
if (line > lineCount - 1)
line= lineCount - 1;
if (line < 0)
line= 0;
try {
IRegion lineInfo= document.getLineInformation(line);
int low= lineInfo.getOffset();
int high= low + lineInfo.getLength();
int lookup= styledText.getLocationAtOffset(low).x;
int guess= low;
int guessDelta= Math.abs(lookup - x);
for (int i= low + 1; i < high; i++) {
lookup= styledText.getLocationAtOffset(i).x;
int delta= Math.abs(lookup - x);
if (delta < guessDelta) {
guess= i;
guessDelta= delta;
}
}
return guess + fTextViewer.getVisibleRegionOffset();
} catch (BadLocationException e) {
}
return -1;
}
/**
* Determines graphical area covered by the given text region.
*
* @param region the region whose graphical extend must be computed
* @return the graphical extend of the given region
*/
private Rectangle computeArea(IRegion region) {
StyledText styledText= fTextViewer.getTextWidget();
IRegion visibleRegion= fTextViewer.getVisibleRegion();
int start= region.getOffset() - visibleRegion.getOffset();
int end= start + region.getLength();
if (end > visibleRegion.getLength())
end= visibleRegion.getLength();
Point upperLeft= styledText.getLocationAtOffset(start);
Point lowerRight= new Point(upperLeft.x, upperLeft.y);
for (int i= start +1; i < end; i++) {
Point p= styledText.getLocationAtOffset(i);
if (upperLeft.x > p.x)
upperLeft.x= p.x;
if (upperLeft.y > p.y)
upperLeft.y= p.y;
if (lowerRight.x < p.x)
lowerRight.x= p.x;
if (lowerRight.y < p.y)
lowerRight.y= p.y;
}
lowerRight.x += fTextViewer.getAverageCharWidth();
lowerRight.y += styledText.getLineHeight();
int width= lowerRight.x - upperLeft.x;
int height= lowerRight.y - upperLeft.y;
return new Rectangle(upperLeft.x, upperLeft.y, width, height);
}
/*
* @see AbstractInformationControlManager#showInformationControl(Rectangle)
*/
protected void showInformationControl(Rectangle subjectArea) {
if (fTextViewer != null && fTextViewer.requestWidgetToken(this))
super.showInformationControl(subjectArea);
}
/*
* @see AbstractInformationControlManager#hideInformationControl()
*/
protected void hideInformationControl() {
try {
super.hideInformationControl();
} finally {
if (fTextViewer != null)
fTextViewer.releaseWidgetToken(this);
}
}
/*
* @see AbstractInformationControlManager#handleInformationControlDisposed()
*/
protected void handleInformationControlDisposed() {
try {
super.handleInformationControlDisposed();
} finally {
if (fTextViewer != null)
fTextViewer.releaseWidgetToken(this);
}
}
}