/******************************************************************************* * Copyright (c) 2000, 2006 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.source; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Rectangle; /** * This class is here to help transitioning to the new StyledText APIs. * * @since 3.2 */ public final class JFaceTextUtil { private JFaceTextUtil() { // Do not instantiate } /** * Computes the line height for the given line range. * * @param textWidget * the <code>StyledText</code> widget * @param startLine * the start line * @param endLine * the end line (exclusive) * @param lineCount * the line count used by the old API * @return the height of all lines starting with <code>startLine</code> and ending above <code>endLime</code> */ public static int computeLineHeight(StyledText textWidget, int startLine, int endLine, int lineCount) { return getLinePixel(textWidget, endLine) - getLinePixel(textWidget, startLine); } /** * Returns the last fully visible line of the widget. The exact semantics of "last fully visible line" are: * <ul> * <li>the last line of which the last pixel is visible, if any * <li>otherwise, the only line that is partially visible * </ul> * * @param widget * the widget * @return the last fully visible line */ public static int getBottomIndex(StyledText widget) { int lastPixel = computeLastVisiblePixel(widget); // bottom is in [0 .. lineCount - 1] int bottom = widget.getLineIndex(lastPixel); // bottom is the first line - no more checking if (bottom == 0) return bottom; int pixel = widget.getLinePixel(bottom); // bottom starts on or before the client area start - bottom is the only visible line if (pixel <= 0) return bottom; int offset = widget.getOffsetAtLine(bottom); int height = widget.getLineHeight(offset); // bottom is not showing entirely - use the previous line if (pixel + height - 1 > lastPixel) return bottom - 1; // bottom is fully visible and its last line is exactly the last pixel return bottom; } /** * Returns the index of the first (possibly only partially) visible line of the widget * * @param widget * the widget * @return the index of the first line of which a pixel is visible */ public static int getPartialTopIndex(StyledText widget) { // see StyledText#getPartialTopIndex() int top = widget.getTopIndex(); int pixels = widget.getLinePixel(top); // FIXME remove when https://bugs.eclipse.org/bugs/show_bug.cgi?id=123770 is fixed if (pixels == -widget.getLineHeight(widget.getOffsetAtLine(top))) { top++; pixels = 0; } if (pixels > 0) top--; return top; } /** * Returns the index of the last (possibly only partially) visible line of the widget * * @param widget * the text widget * @return the index of the last line of which a pixel is visible */ public static int getPartialBottomIndex(StyledText widget) { // @see StyledText#getPartialBottomIndex() int lastPixel = computeLastVisiblePixel(widget); int bottom = widget.getLineIndex(lastPixel); return bottom; } /** * Returns the last visible pixel in the widget's client area. * * @param widget * the widget * @return the last visible pixel in the widget's client area */ private static int computeLastVisiblePixel(StyledText widget) { int caHeight = widget.getClientArea().height; int lastPixel = caHeight - 1; // XXX what if there is a margin? can't take trim as this includes the scrollbars which are not part of the // client area // if ((textWidget.getStyle() & SWT.BORDER) != 0) // lastPixel -= 4; return lastPixel; } /** * Returns the line index of the first visible model line in the viewer. The line may be only partially visible. * * @param viewer * the text viewer * @return the first line of which a pixel is visible, or -1 for no line */ public static int getPartialTopIndex(ITextViewer viewer) { StyledText widget = viewer.getTextWidget(); int widgetTop = getPartialTopIndex(widget); return widgetLine2ModelLine(viewer, widgetTop); } /** * Returns the last, possibly partially, visible line in the view port. * * @param viewer * the text viewer * @return the last, possibly partially, visible line in the view port */ public static int getPartialBottomIndex(ITextViewer viewer) { StyledText textWidget = viewer.getTextWidget(); int widgetBottom = getPartialBottomIndex(textWidget); return widgetLine2ModelLine(viewer, widgetBottom); } /** * Returns the range of lines that is visible in the viewer, including any partially visible lines. * * @param viewer * the viewer * @return the range of lines that is visible in the viewer, <code>null</code> if no lines are visible */ public static ILineRange getVisibleModelLines(ITextViewer viewer) { int top = getPartialTopIndex(viewer); int bottom = getPartialBottomIndex(viewer); if (top == -1 || bottom == -1) return null; return new LineRange(top, bottom - top + 1); } /** * Converts a widget line into a model (i.e. {@link IDocument}) line using the {@link ITextViewerExtension5} if * available, otherwise by adapting the widget line to the viewer's * {@link ITextViewer#getVisibleRegion() visible region}. * * @param viewer * the viewer * @param widgetLine * the widget line to convert. * @return the model line corresponding to <code>widgetLine</code> or -1 to signal that there is no corresponding * model line */ public static int widgetLine2ModelLine(ITextViewer viewer, int widgetLine) { int modelLine; if (viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; modelLine = extension.widgetLine2ModelLine(widgetLine); } else { try { IRegion r = viewer.getVisibleRegion(); IDocument d = viewer.getDocument(); modelLine = widgetLine + d.getLineOfOffset(r.getOffset()); } catch (BadLocationException x) { modelLine = widgetLine; } } return modelLine; } /** * Converts a model (i.e. {@link IDocument}) line into a widget line using the {@link ITextViewerExtension5} if * available, otherwise by adapting the model line to the viewer's * {@link ITextViewer#getVisibleRegion() visible region}. * * @param viewer * the viewer * @param modelLine * the model line to convert. * @return the widget line corresponding to <code>modelLine</code> or -1 to signal that there is no corresponding * widget line */ public static int modelLineToWidgetLine(ITextViewer viewer, final int modelLine) { int widgetLine; if (viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; widgetLine = extension.modelLine2WidgetLine(modelLine); } else { IRegion region = viewer.getVisibleRegion(); IDocument document = viewer.getDocument(); try { int visibleStartLine = document.getLineOfOffset(region.getOffset()); int visibleEndLine = document.getLineOfOffset(region.getOffset() + region.getLength()); if (modelLine < visibleStartLine || modelLine > visibleEndLine) widgetLine = -1; else widgetLine = modelLine - visibleStartLine; } catch (BadLocationException x) { // ignore and return -1 widgetLine = -1; } } return widgetLine; } /** * Returns the number of hidden pixels of the first partially visible line. If there is no partially visible line, * zero is returned. * * @param textWidget * the widget * @return the number of hidden pixels of the first partial line, always >= 0 */ public static int getHiddenTopLinePixels(StyledText textWidget) { int top = getPartialTopIndex(textWidget); return -textWidget.getLinePixel(top); } /** * Returns the number of lines in the view port. * * @param textWidget * @return the number of lines visible in the view port <code>-1</code> if there's no client area * @deprecated this method should not be used - it relies on the widget using a uniform line height */ public static int getVisibleLinesInViewport(StyledText textWidget) { if (textWidget != null) { Rectangle clArea = textWidget.getClientArea(); if (!clArea.isEmpty()) { int firstPixel = 0; int lastPixel = clArea.height - 1; // XXX what about margins? don't take trims as they include // scrollbars int first = getLineIndex(textWidget, firstPixel); int last = getLineIndex(textWidget, lastPixel); return last - first; } } return -1; } /** * Gets the line pixel * * @param textWidget * @param line * @return - line pixel */ public static int getLinePixel(StyledText textWidget, int line) { return textWidget.getLinePixel(line); } /** * Gets the line index * * @param textWidget * @param y * @return - line index */ public static int getLineIndex(StyledText textWidget, int y) { int lineIndex = textWidget.getLineIndex(y); return lineIndex; } /** * Returns <code>true</code> if the widget displays the entire contents, i.e. it cannot be vertically scrolled. * * @param widget * the widget * @return <code>true</code> if the widget displays the entire contents, i.e. it cannot be vertically scrolled, * <code>false</code> otherwise */ public static boolean isShowingEntireContents(StyledText widget) { if (widget.getTopPixel() != 0) // more efficient shortcut return false; int lastVisiblePixel = computeLastVisiblePixel(widget); int lastPossiblePixel = widget.getLinePixel(widget.getLineCount()); return lastPossiblePixel <= lastVisiblePixel; } }