📄 wrappedsyntaxview_test.java
字号:
/*
* 08/06/2004
*
* WrappedSyntaxView_TEST.java - Test implementation of WrappedSyntaxView that
* is also aware of RSyntaxTextArea's different fonts per token type.
* Copyright (C) 2004 Robert Futrell
* email@address.com
* www.website.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.fife.ui.rsyntaxtextarea;
import java.awt.*;
import javax.swing.text.*;
import javax.swing.event.*;
/**
* The view used by {@link RSyntaxTextArea} when word wrap is enabled.<p>
*
* This class is a work-in-progress and will eventually replace
* {@link WrappedSyntaxView} (which works, but ignores token styles).
*
* @author Robert Futrell
* @version 0.2
*/
public class WrappedSyntaxView_TEST extends BoxView implements TabExpander {
boolean widthChanging;
int tabBase;
int tabSize;
/**
* This is reused to keep from allocating/deallocating.
*/
private Segment s, drawSeg;
/**
* Another variable initialized once to keep from allocating/deallocating.
*/
private Rectangle tempRect;
/**
* Cached for each paint() call so each drawView() call has access to it.
*/
private RSyntaxTextArea host;
private FontMetrics metrics;
private SyntaxHighlightingColorScheme colorScheme;
/**
* The end-of-line marker.
*/
private static final char[] eolMarker = { '.' };
/**
* The width of this view cannot be below this amount, as if the width
* is ever 0 (really a bug), we'll go into an infinite loop.
*/
private static final int MIN_WIDTH = 20;
/*****************************************************************************/
/**
* Creates a new WrappedSyntaxView_TEST. Lines will be wrapped
* on character boundaries.
*
* @param elem the element underlying the view
*/
public WrappedSyntaxView_TEST(Element elem) {
super(elem, Y_AXIS);
s = new Segment();
drawSeg = new Segment();
tempRect = new Rectangle();
}
/*****************************************************************************/
/**
* This is called by the nested wrapped line
* views to determine the break location. This can
* be reimplemented to alter the breaking behavior.
* It will either break at word or character boundaries
* depending upon the break argument given at
* construction.
*/
protected int calculateBreakPosition(int p0, Token tokenList, float x0) {
//System.err.println("------ beginning calculateBreakPosition() --------");
int p = p0;
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
float currentWidth = getWidth();
if (currentWidth==Integer.MAX_VALUE)
currentWidth = getPreferredSpan(X_AXIS);
// Make sure width>0; this is a huge hack to fix a bug where
// loading text into an RTextArea before it is visible if word wrap
// is enabled causes an infinite loop in calculateBreakPosition()
// because of the 0-width! We cannot simply check in setSize()
// because the width is set to 0 somewhere else too somehow...
currentWidth = Math.max(currentWidth, MIN_WIDTH);
Token t = tokenList;
while (t!=null && t.isPaintable()) {
// FIXME: Replace the code below with the commented-out line below. This will
// allow long tokens to be broken at embedded spaces (such as MLC's). But it
// currently throws BadLocationExceptions sometimes...
FontMetrics fm = textArea.getFontMetricsForTokenType(t.type);
float tokenWidth = t.getWidth(fm, this, x0);
if (tokenWidth>currentWidth) {
// If the current token alone is too long for this line,
// break at a character boundary.
if (p==p0) {
return t.getOffsetBeforeX(fm, this, 0, currentWidth);
}
// Return the first non-whitespace char (i.e., don't start
// off the continuation of a wrapped line with whitespace).
return (t.type==Token.WHITESPACE) ? p+t.textCount : p;
//return getBreakLocation(t, fm, x0, currentWidth, this);
}
currentWidth -= tokenWidth;
x0 += tokenWidth;
p += t.textCount;
//System.err.println("*** *** *** token fit entirely (width==" + tokenWidth + "), adding " + t.textCount + " to p, now p==" + p);
t = t.getNextToken();
}
//System.err.println("... ... whole line fits; returning p==" + p);
//System.err.println("------ ending calculateBreakPosition() --------");
// return p;
return p + 1;
}
private int getBreakLocation(Token t, FontMetrics fm, int x0, int x,
TabExpander e) {
Segment s = new Segment();
s.array = t.text;
s.offset = t.textOffset;
s.count = t.textCount;
return t.offset + Utilities.getBreakLocation(s, fm, x0, x, e, t.offset);
}
/*****************************************************************************/
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#changedUpdate
*/
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
updateChildren(e, a);
}
/*****************************************************************************/
/**
* Draws a single view (i.e., a line of text for a wrapped view), wrapping
* the text onto multiple lines if necessary.
*
* @param g The graphics context in which to paint.
* @param r The rectangle in which to paint.
* @param view The <code>View</code> to paint.
* @param fontHeight The height of the font being used.
* @param y The y-coordinate at which to begin painting.
*/
protected void drawView(Graphics2D g, Rectangle r, View view,
int fontHeight, int y) {
float x = r.x;
LayeredHighlighter dh = (LayeredHighlighter)host.getHighlighter();
RSyntaxDocument document = (RSyntaxDocument)getDocument();
Element map = getElement();
int p0 = view.getStartOffset();
int lineNumber = map.getElementIndex(p0);
int p1 = view.getEndOffset();// - 1;
setSegment(p0,p1-1, document, drawSeg);
//System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")");
int start = p0 - drawSeg.offset;
Token token = document.getTokenListForLine(lineNumber);
// If this line is an empty line, then the token list is simply a
// null token. In this case, the line highlight will be skipped in
// the loop below, so unfortunately we must manually do it here.
if (token!=null && token.type==Token.NULL) {
dh.paintLayeredHighlights(g, p0,p1, r, host, this);
return;
}
// Loop through all tokens in this view and paint them!
while (token!=null && token.isPaintable()) {
int p = calculateBreakPosition(p0, token, x);
dh.paintLayeredHighlights(g, p0,p, r, host, this);
while (token!=null && token.isPaintable() && token.offset+token.textCount-1<p) {//<=p) {
SyntaxScheme scheme = colorScheme.syntaxSchemes[token.type];
x = token.paint(g, x,y, scheme, host, this);
token = token.getNextToken();
}
if (token!=null && token.isPaintable() && token.offset<p) {
int tokenOffset = token.offset;
Token temp = new DefaultToken(drawSeg, tokenOffset-start,
p-1-start, tokenOffset,
token.type);
SyntaxScheme scheme = colorScheme.syntaxSchemes[token.type];
temp.paint(g, x,y, scheme, host, this);
temp = null;
token.makeStartAt(p);
}
p0 = (p==p0) ? p1 : p;
x = r.x;
y += fontHeight;
} // End of while (token!=null && token.isPaintable()).
}
/*****************************************************************************/
/**
* Determines the maximum span for this view along an
* axis. This is implemented to provide the superclass
* behavior after first making sure that the current font
* metrics are cached (for the nested lines which use
* the metrics to determine the height of the potentially
* wrapped lines).
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getMaximumSpan
*/
public float getMaximumSpan(int axis) {
updateMetrics();
return super.getMaximumSpan(axis);
}
/*****************************************************************************/
/**
* Determines the minimum span for this view along an
* axis. This is implemented to provide the superclass
* behavior after first making sure that the current font
* metrics are cached (for the nested lines which use
* the metrics to determine the height of the potentially
* wrapped lines).
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getMinimumSpan
*/
public float getMinimumSpan(int axis) {
updateMetrics();
return super.getMinimumSpan(axis);
}
/*****************************************************************************/
/**
* Determines the preferred span for this view along an
* axis. This is implemented to provide the superclass
* behavior after first making sure that the current font
* metrics are cached (for the nested lines which use
* the metrics to determine the height of the potentially
* wrapped lines).
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getPreferredSpan
*/
public float getPreferredSpan(int axis) {
updateMetrics();
return super.getPreferredSpan(axis);
}
/*****************************************************************************/
/**
* Returns the tab size set for the document, defaulting to 5.
*
* @return the tab size
*/
protected int getTabSize() {
Integer i = (Integer) getDocument().getProperty(PlainDocument.tabSizeAttribute);
int size = (i != null) ? i.intValue() : 5;
return size;
}
/*****************************************************************************/
/**
* Gives notification that something was inserted into the
* document in a location that this view is responsible for.
* This is implemented to simply update the children.
*
* @param changes The change information from the associated document.
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#insertUpdate
*/
public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -