You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2007/11/13 01:40:58 UTC
svn commit: r594367 [9/9] - in /xmlgraphics/batik/trunk: ./
resources/org/apache/batik/apps/svgbrowser/resources/
resources/org/apache/batik/util/gui/resources/
sources-1.3/org/apache/batik/util/ sources-1.3/org/apache/batik/util/gui/
sources-1.4/org/a...
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaPainter.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,699 @@
+/*
+ * TextAreaPainter.java - Paints the text area
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.ToolTipManager;
+import javax.swing.text.*;
+import javax.swing.JComponent;
+import java.awt.event.MouseEvent;
+import java.awt.*;
+
+/**
+ * The text area repaint manager. It performs double buffering and paints
+ * lines of text.
+ * @author Slava Pestov
+ * @version $Id: TextAreaPainter.java,v 1.24 1999/12/13 03:40:30 sp Exp $
+ */
+public class TextAreaPainter extends JComponent implements TabExpander
+{
+ /**
+ * Creates a new repaint manager. This should be not be called
+ * directly.
+ */
+ public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
+ {
+ this.textArea = textArea;
+
+ setAutoscrolls(true);
+ setDoubleBuffered(true);
+ setOpaque(true);
+
+ ToolTipManager.sharedInstance().registerComponent(this);
+
+ currentLine = new Segment();
+ currentLineIndex = -1;
+
+ setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+
+ setFont(new Font("Monospaced",Font.PLAIN,14));
+ setForeground(Color.black);
+ setBackground(Color.white);
+
+ blockCaret = defaults.blockCaret;
+ styles = defaults.styles;
+ cols = defaults.cols;
+ rows = defaults.rows;
+ caretColor = defaults.caretColor;
+ selectionColor = defaults.selectionColor;
+ lineHighlightColor = defaults.lineHighlightColor;
+ lineHighlight = defaults.lineHighlight;
+ bracketHighlightColor = defaults.bracketHighlightColor;
+ bracketHighlight = defaults.bracketHighlight;
+ paintInvalid = defaults.paintInvalid;
+ eolMarkerColor = defaults.eolMarkerColor;
+ eolMarkers = defaults.eolMarkers;
+ }
+
+ /**
+ * Returns if this component can be traversed by pressing the
+ * Tab key. This returns false.
+ */
+ public final boolean isManagingFocus()
+ {
+ return false;
+ }
+
+ /**
+ * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
+ * will be used to paint tokens with id = <i>n</i>.
+ * @see org.gjt.sp.jedit.syntax.Token
+ */
+ public final SyntaxStyle[] getStyles()
+ {
+ return styles;
+ }
+
+ /**
+ * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
+ * will be used to paint tokens with id = <i>n</i>.
+ * @param styles The syntax styles
+ * @see org.gjt.sp.jedit.syntax.Token
+ */
+ public final void setStyles(SyntaxStyle[] styles)
+ {
+ this.styles = styles;
+ repaint();
+ }
+
+ /**
+ * Returns the caret color.
+ */
+ public final Color getCaretColor()
+ {
+ return caretColor;
+ }
+
+ /**
+ * Sets the caret color.
+ * @param caretColor The caret color
+ */
+ public final void setCaretColor(Color caretColor)
+ {
+ this.caretColor = caretColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the selection color.
+ */
+ public final Color getSelectionColor()
+ {
+ return selectionColor;
+ }
+
+ /**
+ * Sets the selection color.
+ * @param selectionColor The selection color
+ */
+ public final void setSelectionColor(Color selectionColor)
+ {
+ this.selectionColor = selectionColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the line highlight color.
+ */
+ public final Color getLineHighlightColor()
+ {
+ return lineHighlightColor;
+ }
+
+ /**
+ * Sets the line highlight color.
+ * @param lineHighlightColor The line highlight color
+ */
+ public final void setLineHighlightColor(Color lineHighlightColor)
+ {
+ this.lineHighlightColor = lineHighlightColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if line highlight is enabled, false otherwise.
+ */
+ public final boolean isLineHighlightEnabled()
+ {
+ return lineHighlight;
+ }
+
+ /**
+ * Enables or disables current line highlighting.
+ * @param lineHighlight True if current line highlight should be enabled,
+ * false otherwise
+ */
+ public final void setLineHighlightEnabled(boolean lineHighlight)
+ {
+ this.lineHighlight = lineHighlight;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the bracket highlight color.
+ */
+ public final Color getBracketHighlightColor()
+ {
+ return bracketHighlightColor;
+ }
+
+ /**
+ * Sets the bracket highlight color.
+ * @param bracketHighlightColor The bracket highlight color
+ */
+ public final void setBracketHighlightColor(Color bracketHighlightColor)
+ {
+ this.bracketHighlightColor = bracketHighlightColor;
+ invalidateLine(textArea.getBracketLine());
+ }
+
+ /**
+ * Returns true if bracket highlighting is enabled, false otherwise.
+ * When bracket highlighting is enabled, the bracket matching the
+ * one before the caret (if any) is highlighted.
+ */
+ public final boolean isBracketHighlightEnabled()
+ {
+ return bracketHighlight;
+ }
+
+ /**
+ * Enables or disables bracket highlighting.
+ * When bracket highlighting is enabled, the bracket matching the
+ * one before the caret (if any) is highlighted.
+ * @param bracketHighlight True if bracket highlighting should be
+ * enabled, false otherwise
+ */
+ public final void setBracketHighlightEnabled(boolean bracketHighlight)
+ {
+ this.bracketHighlight = bracketHighlight;
+ invalidateLine(textArea.getBracketLine());
+ }
+
+ /**
+ * Returns true if the caret should be drawn as a block, false otherwise.
+ */
+ public final boolean isBlockCaretEnabled()
+ {
+ return blockCaret;
+ }
+
+ /**
+ * Sets if the caret should be drawn as a block, false otherwise.
+ * @param blockCaret True if the caret should be drawn as a block,
+ * false otherwise.
+ */
+ public final void setBlockCaretEnabled(boolean blockCaret)
+ {
+ this.blockCaret = blockCaret;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the EOL marker color.
+ */
+ public final Color getEOLMarkerColor()
+ {
+ return eolMarkerColor;
+ }
+
+ /**
+ * Sets the EOL marker color.
+ * @param eolMarkerColor The EOL marker color
+ */
+ public final void setEOLMarkerColor(Color eolMarkerColor)
+ {
+ this.eolMarkerColor = eolMarkerColor;
+ repaint();
+ }
+
+ /**
+ * Returns true if EOL markers are drawn, false otherwise.
+ */
+ public final boolean getEOLMarkersPainted()
+ {
+ return eolMarkers;
+ }
+
+ /**
+ * Sets if EOL markers are to be drawn.
+ * @param eolMarkers True if EOL markers should be drawn, false otherwise
+ */
+ public final void setEOLMarkersPainted(boolean eolMarkers)
+ {
+ this.eolMarkers = eolMarkers;
+ repaint();
+ }
+
+ /**
+ * Returns true if invalid lines are painted as red tildes (~),
+ * false otherwise.
+ */
+ public boolean getInvalidLinesPainted()
+ {
+ return paintInvalid;
+ }
+
+ /**
+ * Sets if invalid lines are to be painted as red tildes.
+ * @param paintInvalid True if invalid lines should be drawn, false otherwise
+ */
+ public void setInvalidLinesPainted(boolean paintInvalid)
+ {
+ this.paintInvalid = paintInvalid;
+ }
+
+ /**
+ * Adds a custom highlight painter.
+ * @param highlight The highlight
+ */
+ public void addCustomHighlight(Highlight highlight)
+ {
+ highlight.init(textArea,highlights);
+ highlights = highlight;
+ }
+
+ /**
+ * Highlight interface.
+ */
+ public interface Highlight
+ {
+ /**
+ * Called after the highlight painter has been added.
+ * @param textArea The text area
+ * @param next The painter this one should delegate to
+ */
+ void init(JEditTextArea textArea, Highlight next);
+
+ /**
+ * This should paint the highlight and delgate to the
+ * next highlight painter.
+ * @param gfx The graphics context
+ * @param line The line number
+ * @param y The y co-ordinate of the line
+ */
+ void paintHighlight(Graphics gfx, int line, int y);
+
+ /**
+ * Returns the tool tip to display at the specified
+ * location. If this highlighter doesn't know what to
+ * display, it should delegate to the next highlight
+ * painter.
+ * @param evt The mouse event
+ */
+ String getToolTipText(MouseEvent evt);
+ }
+
+ /**
+ * Returns the tool tip to display at the specified location.
+ * @param evt The mouse event
+ */
+ public String getToolTipText(MouseEvent evt)
+ {
+ if(highlights != null)
+ return highlights.getToolTipText(evt);
+ else
+ return null;
+ }
+
+ /**
+ * Returns the font metrics used by this component.
+ */
+ public FontMetrics getFontMetrics()
+ {
+ return fm;
+ }
+
+ /**
+ * Sets the font for this component. This is overridden to update the
+ * cached font metrics and to recalculate which lines are visible.
+ * @param font The font
+ */
+ public void setFont(Font font)
+ {
+ super.setFont(font);
+ fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
+ textArea.recalculateVisibleLines();
+ }
+
+ /**
+ * Repaints the text.
+ * @param g The graphics context
+ */
+ public void paint(Graphics gfx)
+ {
+ Graphics2D g2d = (Graphics2D) gfx;
+ Object aa = g2d.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ tabSize = fm.charWidth(' ') * ((Integer)textArea
+ .getDocument().getProperty(
+ PlainDocument.tabSizeAttribute)).intValue();
+
+ Rectangle clipRect = gfx.getClipBounds();
+
+ gfx.setColor(getBackground());
+ gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
+
+ // We don't use yToLine() here because that method doesn't
+ // return lines past the end of the document
+ int height = fm.getHeight();
+ int firstLine = textArea.getFirstLine();
+ int firstInvalid = firstLine + clipRect.y / height;
+ // Because the clipRect's height is usually an even multiple
+ // of the font height, we subtract 1 from it, otherwise one
+ // too many lines will always be painted.
+ int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
+
+ try
+ {
+ TokenMarker tokenMarker = textArea.getDocument()
+ .getTokenMarker();
+ int x = textArea.getHorizontalOffset();
+
+ for(int line = firstInvalid; line <= lastInvalid; line++)
+ {
+ paintLine(gfx,tokenMarker,line,x);
+ }
+
+ if(tokenMarker != null && tokenMarker.isNextLineRequested())
+ {
+ int h = clipRect.y + clipRect.height;
+ repaint(0,h,getWidth(),getHeight() - h);
+ }
+ }
+ catch(Exception e)
+ {
+ System.err.println("Error repainting line"
+ + " range {" + firstInvalid + ","
+ + lastInvalid + "}:");
+ e.printStackTrace();
+ }
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, aa);
+ }
+
+ /**
+ * Marks a line as needing a repaint.
+ * @param line The line to invalidate
+ */
+ public final void invalidateLine(int line)
+ {
+ repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
+ getWidth(),fm.getHeight());
+ }
+
+ /**
+ * Marks a range of lines as needing a repaint.
+ * @param firstLine The first line to invalidate
+ * @param lastLine The last line to invalidate
+ */
+ public final void invalidateLineRange(int firstLine, int lastLine)
+ {
+ repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
+ getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
+ }
+
+ /**
+ * Repaints the lines containing the selection.
+ */
+ public final void invalidateSelectedLines()
+ {
+ invalidateLineRange(textArea.getSelectionStartLine(),
+ textArea.getSelectionEndLine());
+ }
+
+ /**
+ * Implementation of TabExpander interface. Returns next tab stop after
+ * a specified point.
+ * @param x The x co-ordinate
+ * @param tabOffset Ignored
+ * @return The next tab stop after <i>x</i>
+ */
+ public float nextTabStop(float x, int tabOffset)
+ {
+ int offset = textArea.getHorizontalOffset();
+ int ntabs = ((int)x - offset) / tabSize;
+ return (ntabs + 1) * tabSize + offset;
+ }
+
+ /**
+ * Returns the painter's preferred size.
+ */
+ public Dimension getPreferredSize()
+ {
+ Dimension dim = new Dimension();
+ dim.width = fm.charWidth('w') * cols;
+ dim.height = fm.getHeight() * rows;
+ return dim;
+ }
+
+
+ /**
+ * Returns the painter's minimum size.
+ */
+ public Dimension getMinimumSize()
+ {
+ return getPreferredSize();
+ }
+
+ // package-private members
+ int currentLineIndex;
+ Token currentLineTokens;
+ Segment currentLine;
+
+ // protected members
+ protected JEditTextArea textArea;
+
+ protected SyntaxStyle[] styles;
+ protected Color caretColor;
+ protected Color selectionColor;
+ protected Color lineHighlightColor;
+ protected Color bracketHighlightColor;
+ protected Color eolMarkerColor;
+
+ protected boolean blockCaret;
+ protected boolean lineHighlight;
+ protected boolean bracketHighlight;
+ protected boolean paintInvalid;
+ protected boolean eolMarkers;
+ protected int cols;
+ protected int rows;
+
+ protected int tabSize;
+ protected FontMetrics fm;
+
+ protected Highlight highlights;
+
+ protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
+ int line, int x)
+ {
+ Font defaultFont = getFont();
+ Color defaultColor = getForeground();
+
+ currentLineIndex = line;
+ int y = textArea.lineToY(line);
+
+ if(line < 0 || line >= textArea.getLineCount())
+ {
+ if(paintInvalid)
+ {
+ paintHighlight(gfx,line,y);
+ styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
+ gfx.drawString("~",0,y + fm.getHeight());
+ }
+ }
+ else if(tokenMarker == null)
+ {
+ paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
+ }
+ else
+ {
+ paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
+ defaultColor,x,y);
+ }
+ }
+
+ protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
+ Color defaultColor, int x, int y)
+ {
+ paintHighlight(gfx,line,y);
+ textArea.getLineText(line,currentLine);
+
+ gfx.setFont(defaultFont);
+ gfx.setColor(defaultColor);
+
+ y += fm.getHeight();
+ x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
+
+ if(eolMarkers)
+ {
+ gfx.setColor(eolMarkerColor);
+ gfx.drawString(".",x,y);
+ }
+ }
+
+ protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
+ int line, Font defaultFont, Color defaultColor, int x, int y)
+ {
+ textArea.getLineText(currentLineIndex,currentLine);
+ currentLineTokens = tokenMarker.markTokens(currentLine,
+ currentLineIndex);
+
+ paintHighlight(gfx,line,y);
+
+ gfx.setFont(defaultFont);
+ gfx.setColor(defaultColor);
+ y += fm.getHeight();
+ x = SyntaxUtilities.paintSyntaxLine(currentLine,
+ currentLineTokens,styles,this,gfx,x,y);
+
+ if(eolMarkers)
+ {
+ gfx.setColor(eolMarkerColor);
+ gfx.drawString(".",x,y);
+ }
+ }
+
+ protected void paintHighlight(Graphics gfx, int line, int y)
+ {
+ if(line >= textArea.getSelectionStartLine()
+ && line <= textArea.getSelectionEndLine())
+ paintLineHighlight(gfx,line,y);
+
+ if(highlights != null)
+ highlights.paintHighlight(gfx,line,y);
+
+ if(bracketHighlight && line == textArea.getBracketLine())
+ paintBracketHighlight(gfx,line,y);
+
+ if(line == textArea.getCaretLine())
+ paintCaret(gfx,line,y);
+ }
+
+ protected void paintLineHighlight(Graphics gfx, int line, int y)
+ {
+ int height = fm.getHeight();
+ y += fm.getLeading() + fm.getMaxDescent();
+
+ int selectionStart = textArea.getSelectionStart();
+ int selectionEnd = textArea.getSelectionEnd();
+
+ if(selectionStart == selectionEnd)
+ {
+ if(lineHighlight)
+ {
+ gfx.setColor(lineHighlightColor);
+ gfx.fillRect(0,y,getWidth(),height);
+ }
+ }
+ else
+ {
+ gfx.setColor(selectionColor);
+
+ int selectionStartLine = textArea.getSelectionStartLine();
+ int selectionEndLine = textArea.getSelectionEndLine();
+ int lineStart = textArea.getLineStartOffset(line);
+
+ int x1, x2;
+ if(textArea.isSelectionRectangular())
+ {
+ int lineLen = textArea.getLineLength(line);
+ x1 = textArea._offsetToX(line,Math.min(lineLen,
+ selectionStart - textArea.getLineStartOffset(
+ selectionStartLine)));
+ x2 = textArea._offsetToX(line,Math.min(lineLen,
+ selectionEnd - textArea.getLineStartOffset(
+ selectionEndLine)));
+ if(x1 == x2)
+ x2++;
+ }
+ else if(selectionStartLine == selectionEndLine)
+ {
+ x1 = textArea._offsetToX(line,
+ selectionStart - lineStart);
+ x2 = textArea._offsetToX(line,
+ selectionEnd - lineStart);
+ }
+ else if(line == selectionStartLine)
+ {
+ x1 = textArea._offsetToX(line,
+ selectionStart - lineStart);
+ x2 = getWidth();
+ }
+ else if(line == selectionEndLine)
+ {
+ x1 = 0;
+ x2 = textArea._offsetToX(line,
+ selectionEnd - lineStart);
+ }
+ else
+ {
+ x1 = 0;
+ x2 = getWidth();
+ }
+
+ // "inlined" min/max()
+ gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
+ (x1 - x2) : (x2 - x1),height);
+ }
+
+ }
+
+ protected void paintBracketHighlight(Graphics gfx, int line, int y)
+ {
+ int position = textArea.getBracketPosition();
+ if(position == -1)
+ return;
+ y += fm.getLeading() + fm.getMaxDescent();
+ int x = textArea._offsetToX(line,position);
+ gfx.setColor(bracketHighlightColor);
+ // Hack!!! Since there is no fast way to get the character
+ // from the bracket matching routine, we use ( since all
+ // brackets probably have the same width anyway
+ gfx.drawRect(x,y,fm.charWidth('(') - 1,
+ fm.getHeight() - 1);
+ }
+
+ protected void paintCaret(Graphics gfx, int line, int y)
+ {
+ if(textArea.isCaretVisible())
+ {
+ int offset = textArea.getCaretPosition()
+ - textArea.getLineStartOffset(line);
+ int caretX = textArea._offsetToX(line,offset);
+ int caretWidth = ((blockCaret ||
+ textArea.isOverwriteEnabled()) ?
+ fm.charWidth('w') : 1);
+ y += fm.getLeading() + fm.getMaxDescent();
+ int height = fm.getHeight();
+
+ gfx.setColor(caretColor);
+
+ if(textArea.isOverwriteEnabled())
+ {
+ gfx.fillRect(caretX,y + height - 1,
+ caretWidth,1);
+ }
+ else
+ {
+ gfx.drawRect(caretX,y,caretWidth - 1,height - 1);
+ }
+ }
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextUtilities.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,183 @@
+/*
+ * TextUtilities.java - Utility functions used by the text area classes
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.*;
+
+/**
+ * Class with several utility functions used by the text area component.
+ * @author Slava Pestov
+ * @version $Id: TextUtilities.java,v 1.4 1999/12/13 03:40:30 sp Exp $
+ */
+public class TextUtilities
+{
+ /**
+ * Returns the offset of the bracket matching the one at the
+ * specified offset of the document, or -1 if the bracket is
+ * unmatched (or if the character is not a bracket).
+ * @param doc The document
+ * @param offset The offset
+ * @exception BadLocationException If an out-of-bounds access
+ * was attempted on the document text
+ */
+ public static int findMatchingBracket(Document doc, int offset)
+ throws BadLocationException
+ {
+ if(doc.getLength() == 0)
+ return -1;
+ char c = doc.getText(offset,1).charAt(0);
+ char cprime; // c` - corresponding character
+ boolean direction; // true = back, false = forward
+
+ switch(c)
+ {
+ case '(': cprime = ')'; direction = false; break;
+ case ')': cprime = '('; direction = true; break;
+ case '[': cprime = ']'; direction = false; break;
+ case ']': cprime = '['; direction = true; break;
+ case '{': cprime = '}'; direction = false; break;
+ case '}': cprime = '{'; direction = true; break;
+ default: return -1;
+ }
+
+ int count;
+
+ // How to merge these two cases is left as an exercise
+ // for the reader.
+
+ // Go back or forward
+ if(direction)
+ {
+ // Count is 1 initially because we have already
+ // `found' one closing bracket
+ count = 1;
+
+ // Get text[0,offset-1];
+ String text = doc.getText(0,offset);
+
+ // Scan backwards
+ for(int i = offset - 1; i >= 0; i--)
+ {
+ // If text[i] == c, we have found another
+ // closing bracket, therefore we will need
+ // two opening brackets to complete the
+ // match.
+ char x = text.charAt(i);
+ if(x == c)
+ count++;
+
+ // If text[i] == cprime, we have found a
+ // opening bracket, so we return i if
+ // --count == 0
+ else if(x == cprime)
+ {
+ if(--count == 0)
+ return i;
+ }
+ }
+ }
+ else
+ {
+ // Count is 1 initially because we have already
+ // `found' one opening bracket
+ count = 1;
+
+ // So we don't have to + 1 in every loop
+ offset++;
+
+ // Number of characters to check
+ int len = doc.getLength() - offset;
+
+ // Get text[offset+1,len];
+ String text = doc.getText(offset,len);
+
+ // Scan forwards
+ for(int i = 0; i < len; i++)
+ {
+ // If text[i] == c, we have found another
+ // opening bracket, therefore we will need
+ // two closing brackets to complete the
+ // match.
+ char x = text.charAt(i);
+
+ if(x == c)
+ count++;
+
+ // If text[i] == cprime, we have found an
+ // closing bracket, so we return i if
+ // --count == 0
+ else if(x == cprime)
+ {
+ if(--count == 0)
+ return i + offset;
+ }
+ }
+ }
+
+ // Nothing found
+ return -1;
+ }
+
+ /**
+ * Locates the start of the word at the specified position.
+ * @param line The text
+ * @param pos The position
+ */
+ public static int findWordStart(String line, int pos, String noWordSep)
+ {
+ char ch = line.charAt(pos - 1);
+
+ if(noWordSep == null)
+ noWordSep = "";
+ boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ int wordStart = 0;
+ for(int i = pos - 1; i >= 0; i--)
+ {
+ ch = line.charAt(i);
+ if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordStart = i + 1;
+ break;
+ }
+ }
+
+ return wordStart;
+ }
+
+ /**
+ * Locates the end of the word at the specified position.
+ * @param line The text
+ * @param pos The position
+ */
+ public static int findWordEnd(String line, int pos, String noWordSep)
+ {
+ char ch = line.charAt(pos);
+
+ if(noWordSep == null)
+ noWordSep = "";
+ boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ int wordEnd = line.length();
+ for(int i = pos; i < line.length(); i++)
+ {
+ ch = line.charAt(i);
+ if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordEnd = i;
+ break;
+ }
+ }
+ return wordEnd;
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/Token.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,155 @@
+/*
+ * Token.java - Generic token
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package org.gjt.sp.jedit.textarea;
+
+/**
+ * A linked list of tokens. Each token has three fields - a token
+ * identifier, which is a byte value that can be looked up in the
+ * array returned by <code>SyntaxDocument.getColors()</code>
+ * to get a color value, a length value which is the length of the
+ * token in the text, and a pointer to the next token in the list.
+ *
+ * @author Slava Pestov
+ * @version $Id: Token.java,v 1.12 1999/12/13 03:40:30 sp Exp $
+ */
+public class Token
+{
+ /**
+ * Normal text token id. This should be used to mark
+ * normal text.
+ */
+ public static final byte NULL = 0;
+
+ /**
+ * Comment 1 token id. This can be used to mark a comment.
+ */
+ public static final byte COMMENT1 = 1;
+
+ /**
+ * Comment 2 token id. This can be used to mark a comment.
+ */
+ public static final byte COMMENT2 = 2;
+
+
+ /**
+ * Literal 1 token id. This can be used to mark a string
+ * literal (eg, C mode uses this to mark "..." literals)
+ */
+ public static final byte LITERAL1 = 3;
+
+ /**
+ * Literal 2 token id. This can be used to mark an object
+ * literal (eg, Java mode uses this to mark true, false, etc)
+ */
+ public static final byte LITERAL2 = 4;
+
+ /**
+ * Label token id. This can be used to mark labels
+ * (eg, C mode uses this to mark ...: sequences)
+ */
+ public static final byte LABEL = 5;
+
+ /**
+ * Keyword 1 token id. This can be used to mark a
+ * keyword. This should be used for general language
+ * constructs.
+ */
+ public static final byte KEYWORD1 = 6;
+
+ /**
+ * Keyword 2 token id. This can be used to mark a
+ * keyword. This should be used for preprocessor
+ * commands, or variables.
+ */
+ public static final byte KEYWORD2 = 7;
+
+ /**
+ * Keyword 3 token id. This can be used to mark a
+ * keyword. This should be used for data types.
+ */
+ public static final byte KEYWORD3 = 8;
+
+ /**
+ * Keyword 3 token id. This can be used to mark a
+ * keyword. This should be used for data types.
+ */
+ public static final byte KEYWORD4 = 9;
+
+ /**
+ * Operator token id. This can be used to mark an
+ * operator. (eg, SQL mode marks +, -, etc with this
+ * token type)
+ */
+ public static final byte OPERATOR = 10;
+
+ /**
+ * Invalid token id. This can be used to mark invalid
+ * or incomplete tokens, so the user can easily spot
+ * syntax errors.
+ */
+ public static final byte INVALID = 11;
+
+ /**
+ * The total number of defined token ids.
+ */
+ public static final byte ID_COUNT = 12;
+
+ /**
+ * The first id that can be used for internal state
+ * in a token marker.
+ */
+ public static final byte INTERNAL_FIRST = 100;
+
+ /**
+ * The last id that can be used for internal state
+ * in a token marker.
+ */
+ public static final byte INTERNAL_LAST = 126;
+
+ /**
+ * The token type, that along with a length of 0
+ * marks the end of the token list.
+ */
+ public static final byte END = 127;
+
+ /**
+ * The length of this token.
+ */
+ public int length;
+
+ /**
+ * The id of this token.
+ */
+ public byte id;
+
+ /**
+ * The next token in the linked list.
+ */
+ public Token next;
+
+ /**
+ * Creates a new token.
+ * @param length The length of the token
+ * @param id The id of the token
+ */
+ public Token(int length, byte id)
+ {
+ this.length = length;
+ this.id = id;
+ }
+
+ /**
+ * Returns a string representation of this token.
+ */
+ public String toString()
+ {
+ return "[id=" + id + ",length=" + length + "]";
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TokenMarker.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,344 @@
+/*
+ * TokenMarker.java - Generic token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.Segment;
+import java.util.*;
+
+/**
+ * A token marker that splits lines of text into tokens. Each token carries
+ * a length field and an indentification tag that can be mapped to a color
+ * for painting that token.<p>
+ *
+ * For performance reasons, the linked list of tokens is reused after each
+ * line is tokenized. Therefore, the return value of <code>markTokens</code>
+ * should only be used for immediate painting. Notably, it cannot be
+ * cached.
+ *
+ * @author Slava Pestov
+ * @version $Id: TokenMarker.java,v 1.32 1999/12/13 03:40:30 sp Exp $
+ *
+ * @see org.gjt.sp.jedit.syntax.Token
+ */
+public abstract class TokenMarker
+{
+ /**
+ * A wrapper for the lower-level <code>markTokensImpl</code> method
+ * that is called to split a line up into tokens.
+ * @param line The line
+ * @param lineIndex The line number
+ */
+ public Token markTokens(Segment line, int lineIndex)
+ {
+ if(lineIndex >= length)
+ {
+ throw new IllegalArgumentException("Tokenizing invalid line: "
+ + lineIndex);
+ }
+
+ lastToken = null;
+
+ LineInfo info = lineInfo[lineIndex];
+ LineInfo prev;
+ if(lineIndex == 0)
+ prev = null;
+ else
+ prev = lineInfo[lineIndex - 1];
+
+ byte oldToken = info.token;
+ byte token = markTokensImpl(prev == null ?
+ Token.NULL : prev.token,line,lineIndex);
+
+ info.token = token;
+
+ /*
+ * This is a foul hack. It stops nextLineRequested
+ * from being cleared if the same line is marked twice.
+ *
+ * Why is this necessary? It's all JEditTextArea's fault.
+ * When something is inserted into the text, firing a
+ * document event, the insertUpdate() method shifts the
+ * caret (if necessary) by the amount inserted.
+ *
+ * All caret movement is handled by the select() method,
+ * which eventually pipes the new position to scrollTo()
+ * and calls repaint().
+ *
+ * Note that at this point in time, the new line hasn't
+ * yet been painted; the caret is moved first.
+ *
+ * scrollTo() calls offsetToX(), which tokenizes the line
+ * unless it is being called on the last line painted
+ * (in which case it uses the text area's painter cached
+ * token list). What scrollTo() does next is irrelevant.
+ *
+ * After scrollTo() has done it's job, repaint() is
+ * called, and eventually we end up in paintLine(), whose
+ * job is to paint the changed line. It, too, calls
+ * markTokens().
+ *
+ * The problem was that if the line started a multiline
+ * token, the first markTokens() (done in offsetToX())
+ * would set nextLineRequested (because the line end
+ * token had changed) but the second would clear it
+ * (because the line was the same that time) and therefore
+ * paintLine() would never know that it needed to repaint
+ * subsequent lines.
+ *
+ * This bug took me ages to track down, that's why I wrote
+ * all the relevant info down so that others wouldn't
+ * duplicate it.
+ */
+ if(!(lastLine == lineIndex && nextLineRequested))
+ nextLineRequested = (oldToken != token);
+
+ lastLine = lineIndex;
+
+ addToken(0,Token.END);
+
+ return firstToken;
+ }
+
+ /**
+ * An abstract method that splits a line up into tokens. It
+ * should parse the line, and call <code>addToken()</code> to
+ * add syntax tokens to the token list. Then, it should return
+ * the initial token type for the next line.<p>
+ *
+ * For example if the current line contains the start of a
+ * multiline comment that doesn't end on that line, this method
+ * should return the comment token type so that it continues on
+ * the next line.
+ *
+ * @param token The initial token type for this line
+ * @param line The line to be tokenized
+ * @param lineIndex The index of the line in the document,
+ * starting at 0
+ * @return The initial token type for the next line
+ */
+ protected abstract byte markTokensImpl(byte token, Segment line,
+ int lineIndex);
+
+ /**
+ * Returns if the token marker supports tokens that span multiple
+ * lines. If this is true, the object using this token marker is
+ * required to pass all lines in the document to the
+ * <code>markTokens()</code> method (in turn).<p>
+ *
+ * The default implementation returns true; it should be overridden
+ * to return false on simpler token markers for increased speed.
+ */
+ public boolean supportsMultilineTokens()
+ {
+ return true;
+ }
+
+ /**
+ * Informs the token marker that lines have been inserted into
+ * the document. This inserts a gap in the <code>lineInfo</code>
+ * array.
+ * @param index The first line number
+ * @param lines The number of lines
+ */
+ public void insertLines(int index, int lines)
+ {
+ if(lines <= 0)
+ return;
+ length += lines;
+ ensureCapacity(length);
+ int len = index + lines;
+ System.arraycopy(lineInfo,index,lineInfo,len,
+ lineInfo.length - len);
+
+ for(int i = index + lines - 1; i >= index; i--)
+ {
+ lineInfo[i] = new LineInfo();
+ }
+ }
+
+ /**
+ * Informs the token marker that line have been deleted from
+ * the document. This removes the lines in question from the
+ * <code>lineInfo</code> array.
+ * @param index The first line number
+ * @param lines The number of lines
+ */
+ public void deleteLines(int index, int lines)
+ {
+ if (lines <= 0)
+ return;
+ int len = index + lines;
+ length -= lines;
+ System.arraycopy(lineInfo,len,lineInfo,
+ index,lineInfo.length - len);
+ }
+
+ /**
+ * Returns the number of lines in this token marker.
+ */
+ public int getLineCount()
+ {
+ return length;
+ }
+
+ /**
+ * Returns true if the next line should be repainted. This
+ * will return true after a line has been tokenized that starts
+ * a multiline token that continues onto the next line.
+ */
+ public boolean isNextLineRequested()
+ {
+ return nextLineRequested;
+ }
+
+ // protected members
+
+ /**
+ * The first token in the list. This should be used as the return
+ * value from <code>markTokens()</code>.
+ */
+ protected Token firstToken;
+
+ /**
+ * The last token in the list. New tokens are added here.
+ * This should be set to null before a new line is to be tokenized.
+ */
+ protected Token lastToken;
+
+ /**
+ * An array for storing information about lines. It is enlarged and
+ * shrunk automatically by the <code>insertLines()</code> and
+ * <code>deleteLines()</code> methods.
+ */
+ protected LineInfo[] lineInfo;
+
+ /**
+ * The number of lines in the model being tokenized. This can be
+ * less than the length of the <code>lineInfo</code> array.
+ */
+ protected int length;
+
+ /**
+ * The last tokenized line.
+ */
+ protected int lastLine;
+
+ /**
+ * True if the next line should be painted.
+ */
+ protected boolean nextLineRequested;
+
+ /**
+ * Creates a new <code>TokenMarker</code>. This DOES NOT create
+ * a lineInfo array; an initial call to <code>insertLines()</code>
+ * does that.
+ */
+ protected TokenMarker()
+ {
+ lastLine = -1;
+ }
+
+ /**
+ * Ensures that the <code>lineInfo</code> array can contain the
+ * specified index. This enlarges it if necessary. No action is
+ * taken if the array is large enough already.<p>
+ *
+ * It should be unnecessary to call this under normal
+ * circumstances; <code>insertLine()</code> should take care of
+ * enlarging the line info array automatically.
+ *
+ * @param index The array index
+ */
+ protected void ensureCapacity(int index)
+ {
+ if(lineInfo == null)
+ lineInfo = new LineInfo[index + 1];
+ else if(lineInfo.length <= index)
+ {
+ LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
+ System.arraycopy(lineInfo,0,lineInfoN,0,
+ lineInfo.length);
+ lineInfo = lineInfoN;
+ }
+ }
+
+ /**
+ * Adds a token to the token list.
+ * @param length The length of the token
+ * @param id The id of the token
+ */
+ protected void addToken(int length, byte id)
+ {
+ if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
+ throw new InternalError("Invalid id: " + id);
+
+ if(length == 0 && id != Token.END)
+ return;
+
+ if(firstToken == null)
+ {
+ firstToken = new Token(length,id);
+ lastToken = firstToken;
+ }
+ else if(lastToken == null)
+ {
+ lastToken = firstToken;
+ firstToken.length = length;
+ firstToken.id = id;
+ }
+ else if(lastToken.next == null)
+ {
+ lastToken.next = new Token(length,id);
+ lastToken = lastToken.next;
+ }
+ else
+ {
+ lastToken = lastToken.next;
+ lastToken.length = length;
+ lastToken.id = id;
+ }
+ }
+
+ /**
+ * Inner class for storing information about tokenized lines.
+ */
+ public class LineInfo
+ {
+ /**
+ * Creates a new LineInfo object with token = Token.NULL
+ * and obj = null.
+ */
+ public LineInfo()
+ {
+ }
+
+ /**
+ * Creates a new LineInfo object with the specified
+ * parameters.
+ */
+ public LineInfo(byte token, Object obj)
+ {
+ this.token = token;
+ this.obj = obj;
+ }
+
+ /**
+ * The id of the last token of the line.
+ */
+ public byte token;
+
+ /**
+ * This is for use by the token marker implementations
+ * themselves. It can be used to store anything that
+ * is an object and that needs to exist on a per-line
+ * basis.
+ */
+ public Object obj;
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/XMLTokenMarker.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,190 @@
+/*
+ * XMLTokenMarker.java - XML token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ * Copyright (C) 2001 Tom Bradford
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+package org.gjt.sp.jedit.textarea;
+
+import javax.swing.text.Segment;
+
+/**
+ * XML Token Marker Rewrite
+ *
+ * @author Tom Bradford
+ * @version $Id: XMLTokenMarker.java,v 1.5 2001/07/29 20:45:43 tom Exp $
+ */
+public class XMLTokenMarker extends TokenMarker {
+ public XMLTokenMarker() {
+ }
+
+ public byte markTokensImpl(byte token, Segment line, int lineIndex) {
+ char[] array = line.array;
+ int offset = line.offset;
+ int lastOffset = offset;
+ int length = line.count + offset;
+
+ // Ugly hack to handle multi-line tags
+ boolean sk1 = token == Token.KEYWORD1;
+
+ for ( int i = offset; i < length; i++ ) {
+ int ip1 = i+1;
+ char c = array[i];
+ switch ( token ) {
+ case Token.NULL: // text
+ switch ( c ) {
+ case '<':
+ addToken(i-lastOffset, token);
+ lastOffset = i;
+ if ( SyntaxUtilities.regionMatches(false, line, ip1, "!--") ) {
+ i += 3;
+ token = Token.COMMENT1;
+ }
+ else if ( array[ip1] == '!' ) {
+ i += 1;
+ token = Token.COMMENT2;
+ }
+ else if ( array[ip1] == '?' ) {
+ i += 1;
+ token = Token.KEYWORD3;
+ }
+ else
+ token = Token.KEYWORD1;
+ break;
+
+ case '&':
+ addToken(i - lastOffset, token);
+ lastOffset = i;
+ token = Token.LABEL;
+ break;
+ }
+ break;
+
+ case Token.KEYWORD1: // tag
+ switch ( c ) {
+ case '>':
+ addToken(ip1-lastOffset, token);
+ lastOffset = ip1;
+ token = Token.NULL;
+ sk1 = false;
+ break;
+
+ case ' ':
+ case '\t':
+ addToken(i-lastOffset, token);
+ lastOffset = i;
+ token = Token.KEYWORD2;
+ sk1 = false;
+ break;
+
+ default:
+ if ( sk1 ) {
+ token = Token.KEYWORD2;
+ sk1 = false;
+ }
+ break;
+ }
+ break;
+
+ case Token.KEYWORD2: // attribute
+ switch ( c ) {
+ case '>':
+ addToken(ip1-lastOffset, token);
+ lastOffset = ip1;
+ token = Token.NULL;
+ break;
+
+ case '/':
+ addToken(i-lastOffset, token);
+ lastOffset = i;
+ token = Token.KEYWORD1;
+ break;
+
+ case '=':
+ addToken(i-lastOffset, token);
+ lastOffset = i;
+ token = Token.OPERATOR;
+ }
+ break;
+
+ case Token.OPERATOR: // equal for attribute
+ switch ( c ) {
+ case '\"':
+ case '\'':
+ addToken(i-lastOffset, token);
+ lastOffset = i;
+ if ( c == '\"' )
+ token = Token.LITERAL1;
+ else
+ token = Token.LITERAL2;
+ break;
+ }
+ break;
+
+ case Token.LITERAL1:
+ case Token.LITERAL2: // strings
+ if ( ( token == Token.LITERAL1 && c == '\"' )
+ || ( token == Token.LITERAL2 && c == '\'' ) ) {
+ addToken(ip1-lastOffset, token);
+ lastOffset = ip1;
+ token = Token.KEYWORD1;
+ }
+ break;
+
+ case Token.LABEL: // entity
+ if ( c == ';' ) {
+ addToken(ip1-lastOffset, token);
+ lastOffset = ip1;
+ token = Token.NULL;
+ break;
+ }
+ break;
+
+ case Token.COMMENT1: // Inside a comment
+ if ( SyntaxUtilities.regionMatches(false, line, i, "-->") ) {
+ addToken((i+3)-lastOffset, token);
+ lastOffset = i+3;
+ token = Token.NULL;
+ }
+ break;
+
+ case Token.COMMENT2: // Inside a declaration
+ if ( SyntaxUtilities.regionMatches(false, line, i, ">") ) {
+ addToken(ip1-lastOffset, token);
+ lastOffset = ip1;
+ token = Token.NULL;
+ }
+ break;
+
+ case Token.KEYWORD3: // Inside a processor instruction
+ if ( SyntaxUtilities.regionMatches(false, line, i, "?>") ) {
+ addToken((i+2)-lastOffset, token);
+ lastOffset = i+2;
+ token = Token.NULL;
+ }
+ break;
+
+ default:
+ throw new InternalError("Invalid state: " + token);
+ }
+ }
+
+ switch ( token ) {
+ case Token.LABEL:
+ addToken(length-lastOffset, Token.INVALID);
+ token = Token.NULL;
+ break;
+
+ default:
+ addToken(length-lastOffset, token);
+ break;
+ }
+
+ return token;
+ }
+}
+
+