⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syntaxview.java

📁 具有不同语法高亮的编辑器实例
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * 02/24/2004
 *
 * SyntaxView.java - The View object used by RSyntaxTextArea when word wrap is
 *                   disabled.
 * 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.event.*;
import javax.swing.text.*;


/**
 * The <code>javax.swing.text.View</code> object used by
 * {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea} when word wrap is
 * disabled.  It implements syntax highlighting for programming languages using
 * the colors and font styles specified by the <code>RSyntaxTextArea</code>.<p>
 *
 * You don't really have to do anything to use this class, as
 * {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI} automatically sets the
 * text area's view to be an instance of this class if word wrap is disabled.<p>
 *
 * The tokens that specify how to paint the syntax-highlighted text are gleaned
 * from the text area's
 * {@link org.fife.ui.rsyntaxtextarea.RSyntaxDocument}.
 *
 * @author Robert Futrell
 * @version 0.3
 */
public class SyntaxView extends View implements TabExpander,
											TokenOrientedView {


	/**
	 * The default font used by the text area.  If this changes we need to
	 * recalculate the longest line.
	 */
	Font font;

	/**
	 * Font metrics for the current font.
	 */
	protected FontMetrics metrics;

	/**
	 * The current longest line.  This is used to calculate the preferred width
	 * of the view.  Since the calculation is potentially expensive, we try to
	 * avoid it by stashing which line is currently the longest.
	 */
	Element longLine;
	float longLineWidth;

	int tabSize;
	int tabBase;
    

	/**
	 * This is reused to keep from allocating/deallocating.
	 */
	private Segment s;

	/**
	 * Cached for each paint() call so each drawLine() call has access to it.
	 */
	private RSyntaxTextArea host;

	/**
	 * Cached values to speed up the painting a tad.
	 */
	private int lineHeight = 0;
	private int ascent;
	private int clipStart;
	private int clipEnd;

	/**
	 * The end-of-line marker.
	 */
	private static final char[] eolMarker = { '.' };


/*****************************************************************************/


	/**
	 * Constructs a new <code>SyntaxView</code> wrapped around an element.
	 *
	 * @param elem The element representing the text to display.
	 */
	public SyntaxView(Element elem) {
		super(elem);
		s = new Segment();
	}


/*****************************************************************************/


	/**
	 * Iterate over the lines represented by the child elements
	 * of the element this view represents, looking for the line
	 * that is the longest.  The <em>longLine</em> variable is updated to
	 * represent the longest line contained.  The <em>font</em> variable
	 * is updated to indicate the font used to calculate the 
	 * longest line.
	 */
	void calculateLongestLine() {
		Component c = getContainer();
		font = c.getFont();
		metrics = c.getFontMetrics(font);
		tabSize = getTabSize() * metrics.charWidth(' ');
		Element lines = getElement();
		int n = lines.getElementCount();
		for (int i=0; i<n; i++) {
			Element line = lines.getElement(i);
			float w = getLineWidth(i);
			if (w > longLineWidth) {
				longLineWidth = w;
				longLine = line;
			}
		}
	}


/*****************************************************************************/


	/**
	 * Gives notification from the document that attributes were changed
	 * in a location that this view is responsible for.
	 *
	 * @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#changedUpdate
	 */
	public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
		updateDamage(changes, a, f);
	}


/*****************************************************************************/


	/**
	 * Repaint the given line range.
	 *
	 * @param line0 The starting line number to repaint.  This must
	 *   be a valid line number in the model.
	 * @param line1 The ending line number to repaint.  This must
	 *   be a valid line number in the model.
	 * @param a  The region allocated for the view to render into.
	 * @param host The component hosting the view (used to call repaint).
	 */
	protected void damageLineRange(int line0, int line1, Shape a,
												Component host) {
		if (a != null) {
			Rectangle area0 = lineToRect(a, line0);
			Rectangle area1 = lineToRect(a, line1);
			if ((area0 != null) && (area1 != null)) {
				Rectangle dmg = area0.union(area1); // damage.
				host.repaint(dmg.x, dmg.y, dmg.width, dmg.height);
			}
			else
				host.repaint();
		}
	}


/*****************************************************************************/


	/**
	 * Draws the passed-in text using syntax highlighting for the current
	 * language.  The tokens used to decide how to paint the syntax
	 * highlighting are grabbed from the text area's document.
	 *
	 * @param token The list of tokens to draw.
	 * @param g The graphics context in which to draw.
	 * @param colorScheme The syntax highlighting color scheme to use.
	 * @param x The x-coordinate at which to draw.
	 * @param y The y-coordinate at which to draw.
	 * @return The x-coordinate representing the end of the painted text.
	 */
	public float drawLine(Token token, Graphics2D g,
					final SyntaxHighlightingColorScheme colorScheme,
					float x, float y) {

		float nextX = x;	// The x-value at the end of our text.

		SyntaxScheme scheme;

		while (token!=null && token.isPaintable() && nextX<clipEnd) {
			scheme = colorScheme.syntaxSchemes[token.type];
			nextX = token.paint(g, nextX,y, scheme, host, this, clipStart);
			token = token.getNextToken();
		}

		//// Paint the "end-of-line" marker if desired.
		//if (true/*host.areEndOfLineMarkersPainted()*/) {
		//	drawTabbedText(eolMarker, nextX,y, g, 0, new Color(170, 205,205), null);
		//}

		// Return the x-coordinate at the end of the painted text.
		return nextX;

	}


/*****************************************************************************/


	/**
	 * Calculates the width of the line represented by the given element.
	 *
	 * @param line The line for which to get the length.
	 * @param lineNumber The line number of the specified line in the document.
	 * @return The width of the line.
	 */
	private float getLineWidth(int lineNumber) {
		Token tokenList = ((RSyntaxDocument)getDocument()).
									getTokenListForLine(lineNumber);
		return RSyntaxUtilities.getTokenListWidth(tokenList,
								(RSyntaxTextArea)getContainer(),
								this);
	}


/*****************************************************************************/


	/**
	 * Provides a way to determine the next visually represented model 
	 * location that one might place a caret.  Some views may not be visible,
	 * they might not be in the same order found in the model, or they just
	 * might not allow access to some of the locations in the model.
	 *
	 * @param pos the position to convert >= 0
	 * @param a the allocated region to render into
	 * @param direction the direction from the current position that can
	 *  be thought of as the arrow keys typically found on a keyboard.
	 *  This may be SwingConstants.WEST, SwingConstants.EAST, 
	 *  SwingConstants.NORTH, or SwingConstants.SOUTH.  
	 * @return the location within the model that best represents the next
	 *  location visual position.
	 * @exception BadLocationException
	 * @exception IllegalArgumentException for an invalid direction
	 */
	public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, 
							int direction, Position.Bias[] biasRet)
							throws BadLocationException {
		return RSyntaxUtilities.getNextVisualPositionFrom(pos, b, a,
										direction, biasRet, this);
	}


/*****************************************************************************/


	/**
	 * Determines the preferred span for this view along an
	 * axis.
	 *
	 * @param axis may be either View.X_AXIS or View.Y_AXIS
	 * @return   the span the view would like to be rendered into >= 0.
	 *           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.
	 * @exception IllegalArgumentException for an invalid axis
	 */
	public float getPreferredSpan(int axis) {
		updateMetrics();
		switch (axis) {
			case View.X_AXIS:
				return longLineWidth + 10; // "fudge factor."
			case View.Y_AXIS:
				// We update lineHeight here as when this method is first
				// called, lineHeight isn't initialized.  If we don't do it
				// here, we get no vertical scrollbar (as lineHeight==0).
				lineHeight = host!=null ? host.getLineHeight() : lineHeight;
				return getElement().getElementCount() * lineHeight;
			default:
				throw new IllegalArgumentException("Invalid axis: " + 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;
	}


/*****************************************************************************/


	/**
	 * Returns a token list for the <i>physical</i> line above the physical
	 * line containing the specified offset into the document.  Note that for
	 * this plain (non-wrapped) view, this is simply the token list for the
	 * logical line above the line containing <code>offset</code>, since lines
	 * are not wrapped.
	 *
	 * @param offset The offset in question.
	 * @return A token list for the physical (and in this view, logical) line
	 *         before this one.  If <code>offset</code> is in the first line in
	 *         the document, <code>null</code> is returned.
	 */
	public Token getTokenListForPhysicalLineAbove(int offset) {
		RSyntaxDocument document = (RSyntaxDocument)getDocument();
		Element map = document.getDefaultRootElement();
		int line = map.getElementIndex(offset) - 1;
		if (line>=0)
			return document.getTokenListForLine(line);
		return null;
	}


/*****************************************************************************/


	/**
	 * Returns a token list for the <i>physical</i> line below the physical
	 * line containing the specified offset into the document.  Note that for
	 * this plain (non-wrapped) view, this is simply the token list for the
	 * logical line below the line containing <code>offset</code>, since lines
	 * are not wrapped.
	 *
	 * @param offset The offset in question.
	 * @return A token list for the physical (and in this view, logical) line
	 *         after this one.  If <code>offset</code> is in the last physical
	 *         line in the document, <code>null</code> is returned.
	 */
	public Token getTokenListForPhysicalLineBelow(int offset) {
		RSyntaxDocument document = (RSyntaxDocument)getDocument();
		Element map = document.getDefaultRootElement();
		int line = map.getElementIndex(offset);
		int lineCount = map.getElementCount();
		if (line<lineCount-1)
			return document.getTokenListForLine(line+1);
		return null;
	}


/*****************************************************************************/



	/**
	 * Gives notification that something was inserted into the document
	 * in a location that this view is responsible for.
	 *
	 * @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.
	 */
	public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
		updateDamage(changes, a, f);
	}


/*****************************************************************************/


	/**
	 * Determine the rectangle that represents the given line.
	 *
	 * @param a The region allocated for the view to render into
	 * @param line The line number to find the region of.  This must
	 *             be a valid line number in the model.
	 */
	protected Rectangle lineToRect(Shape a, int line) {
		Rectangle r = null;
		updateMetrics();
		if (metrics != null) {
			Rectangle alloc = a.getBounds();
			// NOTE:  lineHeight is not initially set here, leading to the
			// current line not being highlighted when a document is first
			// opened.  So, we set it here just in case.
			lineHeight = host!=null ? host.getLineHeight() : lineHeight;
			r = new Rectangle(alloc.x, alloc.y + line*lineHeight,
									alloc.width, lineHeight);
		}
		return r;
	}


/*****************************************************************************/


	/**
	 * Provides a mapping from the document model coordinate space
	 * to the coordinate space of the view mapped to it.
	 *
	 * @param pos the position to convert >= 0
	 * @param a the allocated region to render into
	 * @return the bounding box of the given position
	 * @exception BadLocationException  if the given position does not
	 *   represent a valid location in the associated document
	 * @see View#modelToView
	 */
	public Shape modelToView(int pos, Shape a, Position.Bias b)
										throws BadLocationException {

		// line coordinates
		Element map = getElement();
		RSyntaxDocument doc = (RSyntaxDocument)getDocument();
		int lineIndex = map.getElementIndex(pos);
		Rectangle lineArea = lineToRect(a, lineIndex);
		tabBase = lineArea.x; // Used by listOffsetToView().

		Token tokenList = doc.getTokenListForLine(lineIndex);

		//int x = (int)RSyntaxUtilities.getTokenListWidthUpTo(tokenList,
		//							(RSyntaxTextArea)getContainer(),
		//							this, 0, pos);
		// We use this method instead as it returns the actual bounding box,
		// not just the x-coordinate.
		lineArea = tokenList.listOffsetToView(
						(RSyntaxTextArea)getContainer(), this, pos,
						tabBase, lineArea);

		return lineArea;

	}


/*****************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -