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 [8/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/JEditTextArea.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/JEditTextArea.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/JEditTextArea.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/JEditTextArea.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,2128 @@
+/*
+ * JEditTextArea.java - jEdit's text component
+ * 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.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+import javax.swing.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * jEdit's text area component. It is more suited for editing program
+ * source code than JEditorPane, because it drops the unnecessary features
+ * (images, variable-width lines, and so on) and adds a whole bunch of
+ * useful goodies such as:
+ * <ul>
+ * <li>More flexible key binding scheme
+ * <li>Supports macro recorders
+ * <li>Rectangular selection
+ * <li>Bracket highlighting
+ * <li>Syntax highlighting
+ * <li>Command repetition
+ * <li>Block caret can be enabled
+ * </ul>
+ * It is also faster and doesn't have as many problems. It can be used
+ * in other applications; the only other part of jEdit it depends on is
+ * the syntax package.<p>
+ *
+ * To use it in your app, treat it like any other component, for example:
+ * <pre>JEditTextArea ta = new JEditTextArea();
+ * ta.setTokenMarker(new JavaTokenMarker());
+ * ta.setText("public class Test {\n"
+ * + " public static void main(String[] args) {\n"
+ * + " System.out.println(\"Hello World\");\n"
+ * + " }\n"
+ * + "}");</pre>
+ *
+ * @author Slava Pestov
+ * @version $Id: JEditTextArea.java,v 1.36 1999/12/13 03:40:30 sp Exp $
+ */
+public class JEditTextArea extends JComponent
+{
+ /**
+ * Adding components with this name to the text area will place
+ * them left of the horizontal scroll bar. In jEdit, the status
+ * bar is added this way.
+ */
+ public static String LEFT_OF_SCROLLBAR = "los";
+
+ /**
+ * Creates a new JEditTextArea with the default settings.
+ */
+ public JEditTextArea()
+ {
+ this(TextAreaDefaults.getDefaults());
+ }
+
+ /**
+ * Creates a new JEditTextArea with the specified settings.
+ * @param defaults The default settings
+ */
+ public JEditTextArea(TextAreaDefaults defaults)
+ {
+ // Enable the necessary events
+ enableEvents(AWTEvent.KEY_EVENT_MASK);
+
+ // Initialize some misc. stuff
+ painter = new TextAreaPainter(this,defaults);
+ documentHandler = new DocumentHandler();
+ listenerList = new EventListenerList();
+ caretEvent = new MutableCaretEvent();
+ lineSegment = new Segment();
+ bracketLine = bracketPosition = -1;
+ blink = true;
+
+ // Initialize the GUI
+ setLayout(new ScrollLayout());
+ add(CENTER,painter);
+ add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL));
+ add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
+
+ // Add some event listeners
+ vertical.addAdjustmentListener(new AdjustHandler());
+ horizontal.addAdjustmentListener(new AdjustHandler());
+ painter.addComponentListener(new ComponentHandler());
+ painter.addMouseListener(new MouseHandler());
+ painter.addMouseMotionListener(new DragHandler());
+ addFocusListener(new FocusHandler());
+
+ // Load the defaults
+ setInputHandler(defaults.inputHandler);
+ setDocument(defaults.document);
+ editable = defaults.editable;
+ caretVisible = defaults.caretVisible;
+ caretBlinks = defaults.caretBlinks;
+ electricScroll = defaults.electricScroll;
+
+ popup = defaults.popup;
+
+ // We don't seem to get the initial focus event?
+ focusedComponent = this;
+ }
+
+ /**
+ * Returns if this component can be traversed by pressing
+ * the Tab key. This returns false.
+ */
+ public final boolean isManagingFocus()
+ {
+ return true;
+ }
+
+ /**
+ * Returns the object responsible for painting this text area.
+ */
+ public final TextAreaPainter getPainter()
+ {
+ return painter;
+ }
+
+ /**
+ * Returns the input handler.
+ */
+ public final InputHandler getInputHandler()
+ {
+ return inputHandler;
+ }
+
+ /**
+ * Sets the input handler.
+ * @param inputHandler The new input handler
+ */
+ public void setInputHandler(InputHandler inputHandler)
+ {
+ this.inputHandler = inputHandler;
+ }
+
+ /**
+ * Returns true if the caret is blinking, false otherwise.
+ */
+ public final boolean isCaretBlinkEnabled()
+ {
+ return caretBlinks;
+ }
+
+ /**
+ * Toggles caret blinking.
+ * @param caretBlinks True if the caret should blink, false otherwise
+ */
+ public void setCaretBlinkEnabled(boolean caretBlinks)
+ {
+ this.caretBlinks = caretBlinks;
+ if(!caretBlinks)
+ blink = false;
+
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if the caret is visible, false otherwise.
+ */
+ public final boolean isCaretVisible()
+ {
+ return (!caretBlinks || blink) && caretVisible;
+ }
+
+ /**
+ * Sets if the caret should be visible.
+ * @param caretVisible True if the caret should be visible, false
+ * otherwise
+ */
+ public void setCaretVisible(boolean caretVisible)
+ {
+ this.caretVisible = caretVisible;
+ blink = true;
+
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Blinks the caret.
+ */
+ public final void blinkCaret()
+ {
+ if(caretBlinks)
+ {
+ blink = !blink;
+ painter.invalidateSelectedLines();
+ }
+ else
+ blink = true;
+ }
+
+ /**
+ * Returns the number of lines from the top and button of the
+ * text area that are always visible.
+ */
+ public final int getElectricScroll()
+ {
+ return electricScroll;
+ }
+
+ /**
+ * Sets the number of lines from the top and bottom of the text
+ * area that are always visible
+ * @param electricScroll The number of lines always visible from
+ * the top or bottom
+ */
+ public final void setElectricScroll(int electricScroll)
+ {
+ this.electricScroll = electricScroll;
+ }
+
+ /**
+ * Updates the state of the scroll bars. This should be called
+ * if the number of lines in the document changes, or when the
+ * size of the text are changes.
+ */
+ public void updateScrollBars()
+ {
+ if(vertical != null && visibleLines != 0)
+ {
+ vertical.setValues(firstLine,visibleLines,0,getLineCount());
+ vertical.setUnitIncrement(2);
+ vertical.setBlockIncrement(visibleLines);
+ }
+
+ int width = painter.getWidth();
+ if(horizontal != null && width != 0)
+ {
+ horizontal.setValues(-horizontalOffset,width,0,width * 5);
+ horizontal.setUnitIncrement(painter.getFontMetrics()
+ .charWidth('w'));
+ horizontal.setBlockIncrement(width / 2);
+ }
+ }
+
+ /**
+ * Returns the line displayed at the text area's origin.
+ */
+ public final int getFirstLine()
+ {
+ return firstLine;
+ }
+
+ /**
+ * Sets the line displayed at the text area's origin without
+ * updating the scroll bars.
+ */
+ public void setFirstLine(int firstLine)
+ {
+ if(firstLine == this.firstLine)
+ return;
+ int oldFirstLine = this.firstLine;
+ this.firstLine = firstLine;
+ if(firstLine != vertical.getValue())
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ /**
+ * Returns the number of lines visible in this text area.
+ */
+ public final int getVisibleLines()
+ {
+ return visibleLines;
+ }
+
+ /**
+ * Recalculates the number of visible lines. This should not
+ * be called directly.
+ */
+ public final void recalculateVisibleLines()
+ {
+ if(painter == null)
+ return;
+ int height = painter.getHeight();
+ int lineHeight = painter.getFontMetrics().getHeight();
+ int oldVisibleLines = visibleLines;
+ visibleLines = height / lineHeight;
+ updateScrollBars();
+ }
+
+ /**
+ * Returns the horizontal offset of drawn lines.
+ */
+ public final int getHorizontalOffset()
+ {
+ return horizontalOffset;
+ }
+
+ /**
+ * Sets the horizontal offset of drawn lines. This can be used to
+ * implement horizontal scrolling.
+ * @param horizontalOffset offset The new horizontal offset
+ */
+ public void setHorizontalOffset(int horizontalOffset)
+ {
+ if(horizontalOffset == this.horizontalOffset)
+ return;
+ this.horizontalOffset = horizontalOffset;
+ if(horizontalOffset != horizontal.getValue())
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ /**
+ * A fast way of changing both the first line and horizontal
+ * offset.
+ * @param firstLine The new first line
+ * @param horizontalOffset The new horizontal offset
+ * @return True if any of the values were changed, false otherwise
+ */
+ public boolean setOrigin(int firstLine, int horizontalOffset)
+ {
+ boolean changed = false;
+ int oldFirstLine = this.firstLine;
+
+ if(horizontalOffset != this.horizontalOffset)
+ {
+ this.horizontalOffset = horizontalOffset;
+ changed = true;
+ }
+
+ if(firstLine != this.firstLine)
+ {
+ this.firstLine = firstLine;
+ changed = true;
+ }
+
+ if(changed)
+ {
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ return changed;
+ }
+
+ /**
+ * Ensures that the caret is visible by scrolling the text area if
+ * necessary.
+ * @return True if scrolling was actually performed, false if the
+ * caret was already visible
+ */
+ public boolean scrollToCaret()
+ {
+ int line = getCaretLine();
+ int lineStart = getLineStartOffset(line);
+ int offset = Math.max(0,Math.min(getLineLength(line) - 1,
+ getCaretPosition() - lineStart));
+
+ return scrollTo(line,offset);
+ }
+
+ /**
+ * Ensures that the specified line and offset is visible by scrolling
+ * the text area if necessary.
+ * @param line The line to scroll to
+ * @param offset The offset in the line to scroll to
+ * @return True if scrolling was actually performed, false if the
+ * line and offset was already visible
+ */
+ public boolean scrollTo(int line, int offset)
+ {
+ // visibleLines == 0 before the component is realized
+ // we can't do any proper scrolling then, so we have
+ // this hack...
+ if(visibleLines == 0)
+ {
+ setFirstLine(Math.max(0,line - electricScroll));
+ return true;
+ }
+
+ int newFirstLine = firstLine;
+ int newHorizontalOffset = horizontalOffset;
+
+ if(line < firstLine + electricScroll)
+ {
+ newFirstLine = Math.max(0,line - electricScroll);
+ }
+ else if(line + electricScroll >= firstLine + visibleLines)
+ {
+ newFirstLine = (line - visibleLines) + electricScroll + 1;
+ if(newFirstLine + visibleLines >= getLineCount())
+ newFirstLine = getLineCount() - visibleLines;
+ if(newFirstLine < 0)
+ newFirstLine = 0;
+ }
+
+ int x = _offsetToX(line,offset);
+ int width = painter.getFontMetrics().charWidth('w');
+
+ if(x < 0)
+ {
+ newHorizontalOffset = Math.min(0,horizontalOffset
+ - x + width + 5);
+ }
+ else if(x + width >= painter.getWidth())
+ {
+ newHorizontalOffset = horizontalOffset +
+ (painter.getWidth() - x) - width - 5;
+ }
+
+ return setOrigin(newFirstLine,newHorizontalOffset);
+ }
+
+ /**
+ * Converts a line index to a y co-ordinate.
+ * @param line The line
+ */
+ public int lineToY(int line)
+ {
+ FontMetrics fm = painter.getFontMetrics();
+ return (line - firstLine) * fm.getHeight()
+ - (fm.getLeading() + fm.getMaxDescent());
+ }
+
+ /**
+ * Converts a y co-ordinate to a line index.
+ * @param y The y co-ordinate
+ */
+ public int yToLine(int y)
+ {
+ FontMetrics fm = painter.getFontMetrics();
+ int height = fm.getHeight();
+ return Math.max(0,Math.min(getLineCount() - 1,
+ y / height + firstLine));
+ }
+
+ /**
+ * Converts an offset in a line into an x co-ordinate. This is a
+ * slow version that can be used any time.
+ * @param line The line
+ * @param offset The offset, from the start of the line
+ */
+ public final int offsetToX(int line, int offset)
+ {
+ // don't use cached tokens
+ painter.currentLineTokens = null;
+ return _offsetToX(line,offset);
+ }
+
+ /**
+ * Converts an offset in a line into an x co-ordinate. This is a
+ * fast version that should only be used if no changes were made
+ * to the text since the last repaint.
+ * @param line The line
+ * @param offset The offset, from the start of the line
+ */
+ public int _offsetToX(int line, int offset)
+ {
+ TokenMarker tokenMarker = getTokenMarker();
+
+ /* Use painter's cached info for speed */
+ FontMetrics fm = painter.getFontMetrics();
+
+ getLineText(line,lineSegment);
+
+ int segmentOffset = lineSegment.offset;
+ int x = horizontalOffset;
+
+ /* If syntax coloring is disabled, do simple translation */
+ if(tokenMarker == null)
+ {
+ lineSegment.count = offset;
+ return x + Utilities.getTabbedTextWidth(lineSegment,
+ fm,x,painter,0);
+ }
+ /* If syntax coloring is enabled, we have to do this because
+ * tokens can vary in width */
+ else
+ {
+ Token tokens;
+ if(painter.currentLineIndex == line
+ && painter.currentLineTokens != null)
+ tokens = painter.currentLineTokens;
+ else
+ {
+ painter.currentLineIndex = line;
+ tokens = painter.currentLineTokens
+ = tokenMarker.markTokens(lineSegment,line);
+ }
+
+ Toolkit toolkit = painter.getToolkit();
+ Font defaultFont = painter.getFont();
+ SyntaxStyle[] styles = painter.getStyles();
+
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ {
+ return x;
+ }
+
+ if(id == Token.NULL)
+ fm = painter.getFontMetrics();
+ else
+ fm = styles[id].getFontMetrics(defaultFont);
+
+ int length = tokens.length;
+
+ if(offset + segmentOffset < lineSegment.offset + length)
+ {
+ lineSegment.count = offset - (lineSegment.offset - segmentOffset);
+ return x + Utilities.getTabbedTextWidth(
+ lineSegment,fm,x,painter,0);
+ }
+ else
+ {
+ lineSegment.count = length;
+ x += Utilities.getTabbedTextWidth(
+ lineSegment,fm,x,painter,0);
+ lineSegment.offset += length;
+ }
+ tokens = tokens.next;
+ }
+ }
+ }
+
+ /**
+ * Converts an x co-ordinate to an offset within a line.
+ * @param line The line
+ * @param x The x co-ordinate
+ */
+ public int xToOffset(int line, int x)
+ {
+ TokenMarker tokenMarker = getTokenMarker();
+
+ /* Use painter's cached info for speed */
+ FontMetrics fm = painter.getFontMetrics();
+
+ getLineText(line,lineSegment);
+
+ char[] segmentArray = lineSegment.array;
+ int segmentOffset = lineSegment.offset;
+ int segmentCount = lineSegment.count;
+
+ int width = horizontalOffset;
+
+ if(tokenMarker == null)
+ {
+ for(int i = 0; i < segmentCount; i++)
+ {
+ char c = segmentArray[i + segmentOffset];
+ int charWidth;
+ if(c == '\t')
+ charWidth = (int)painter.nextTabStop(width,i)
+ - width;
+ else
+ charWidth = fm.charWidth(c);
+
+ if(painter.isBlockCaretEnabled())
+ {
+ if(x - charWidth <= width)
+ return i;
+ }
+ else
+ {
+ if(x - charWidth / 2 <= width)
+ return i;
+ }
+
+ width += charWidth;
+ }
+
+ return segmentCount;
+ }
+ else
+ {
+ Token tokens;
+ if(painter.currentLineIndex == line && painter
+ .currentLineTokens != null)
+ tokens = painter.currentLineTokens;
+ else
+ {
+ painter.currentLineIndex = line;
+ tokens = painter.currentLineTokens
+ = tokenMarker.markTokens(lineSegment,line);
+ }
+
+ int offset = 0;
+ Toolkit toolkit = painter.getToolkit();
+ Font defaultFont = painter.getFont();
+ SyntaxStyle[] styles = painter.getStyles();
+
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ return offset;
+
+ if(id == Token.NULL)
+ fm = painter.getFontMetrics();
+ else
+ fm = styles[id].getFontMetrics(defaultFont);
+
+ int length = tokens.length;
+
+ for(int i = 0; i < length; i++)
+ {
+ char c = segmentArray[segmentOffset + offset + i];
+ int charWidth;
+ if(c == '\t')
+ charWidth = (int)painter.nextTabStop(width,offset + i)
+ - width;
+ else
+ charWidth = fm.charWidth(c);
+
+ if(painter.isBlockCaretEnabled())
+ {
+ if(x - charWidth <= width)
+ return offset + i;
+ }
+ else
+ {
+ if(x - charWidth / 2 <= width)
+ return offset + i;
+ }
+
+ width += charWidth;
+ }
+
+ offset += length;
+ tokens = tokens.next;
+ }
+ }
+ }
+
+ /**
+ * Converts a point to an offset, from the start of the text.
+ * @param x The x co-ordinate of the point
+ * @param y The y co-ordinate of the point
+ */
+ public int xyToOffset(int x, int y)
+ {
+ int line = yToLine(y);
+ int start = getLineStartOffset(line);
+ return start + xToOffset(line,x);
+ }
+
+ /**
+ * Returns the document this text area is editing.
+ */
+ public final SyntaxDocument getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * Sets the document this text area is editing.
+ * @param document The document
+ */
+ public void setDocument(SyntaxDocument document)
+ {
+ if(this.document == document)
+ return;
+ if(this.document != null)
+ this.document.removeDocumentListener(documentHandler);
+ this.document = document;
+
+ document.addDocumentListener(documentHandler);
+
+ select(0,0);
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ /**
+ * Returns the document's token marker. Equivalent to calling
+ * <code>getDocument().getTokenMarker()</code>.
+ */
+ public final TokenMarker getTokenMarker()
+ {
+ return document.getTokenMarker();
+ }
+
+ /**
+ * Sets the document's token marker. Equivalent to caling
+ * <code>getDocument().setTokenMarker()</code>.
+ * @param tokenMarker The token marker
+ */
+ public final void setTokenMarker(TokenMarker tokenMarker)
+ {
+ document.setTokenMarker(tokenMarker);
+ }
+
+ /**
+ * Returns the length of the document. Equivalent to calling
+ * <code>getDocument().getLength()</code>.
+ */
+ public final int getDocumentLength()
+ {
+ return document.getLength();
+ }
+
+ /**
+ * Returns the number of lines in the document.
+ */
+ public final int getLineCount()
+ {
+ return document.getDefaultRootElement().getElementCount();
+ }
+
+ /**
+ * Returns the line containing the specified offset.
+ * @param offset The offset
+ */
+ public final int getLineOfOffset(int offset)
+ {
+ return document.getDefaultRootElement().getElementIndex(offset);
+ }
+
+ /**
+ * Returns the start offset of the specified line.
+ * @param line The line
+ * @return The start offset of the specified line, or -1 if the line is
+ * invalid
+ */
+ public int getLineStartOffset(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getStartOffset();
+ }
+
+ /**
+ * Returns the end offset of the specified line.
+ * @param line The line
+ * @return The end offset of the specified line, or -1 if the line is
+ * invalid.
+ */
+ public int getLineEndOffset(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getEndOffset();
+ }
+
+ /**
+ * Returns the length of the specified line.
+ * @param line The line
+ */
+ public int getLineLength(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getEndOffset()
+ - lineElement.getStartOffset() - 1;
+ }
+
+ /**
+ * Returns the entire text of this text area.
+ */
+ public String getText()
+ {
+ try
+ {
+ return document.getText(0,document.getLength());
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Sets the entire text of this text area.
+ */
+ public void setText(String text)
+ {
+ try
+ {
+ document.beginCompoundEdit();
+ document.remove(0,document.getLength());
+ document.insertString(0,text,null);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ finally
+ {
+ document.endCompoundEdit();
+ }
+ }
+
+ /**
+ * Returns the specified substring of the document.
+ * @param start The start offset
+ * @param len The length of the substring
+ * @return The substring, or null if the offsets are invalid
+ */
+ public final String getText(int start, int len)
+ {
+ try
+ {
+ return document.getText(start,len);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Copies the specified substring of the document into a segment.
+ * If the offsets are invalid, the segment will contain a null string.
+ * @param start The start offset
+ * @param len The length of the substring
+ * @param segment The segment
+ */
+ public final void getText(int start, int len, Segment segment)
+ {
+ try
+ {
+ document.getText(start,len,segment);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ segment.offset = segment.count = 0;
+ }
+ }
+
+ /**
+ * Returns the text on the specified line.
+ * @param lineIndex The line
+ * @return The text, or null if the line is invalid
+ */
+ public final String getLineText(int lineIndex)
+ {
+ int start = getLineStartOffset(lineIndex);
+ return getText(start,getLineEndOffset(lineIndex) - start - 1);
+ }
+
+ /**
+ * Copies the text on the specified line into a segment. If the line
+ * is invalid, the segment will contain a null string.
+ * @param lineIndex The line
+ */
+ public final void getLineText(int lineIndex, Segment segment)
+ {
+ int start = getLineStartOffset(lineIndex);
+ getText(start,getLineEndOffset(lineIndex) - start - 1,segment);
+ }
+
+ /**
+ * Returns the selection start offset.
+ */
+ public final int getSelectionStart()
+ {
+ return selectionStart;
+ }
+
+ /**
+ * Returns the offset where the selection starts on the specified
+ * line.
+ */
+ public int getSelectionStart(int line)
+ {
+ if(line == selectionStartLine)
+ return selectionStart;
+ else if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+
+ Element lineElement = map.getElement(line);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ return Math.min(lineEnd,lineStart + start);
+ }
+ else
+ return getLineStartOffset(line);
+ }
+
+ /**
+ * Returns the selection start line.
+ */
+ public final int getSelectionStartLine()
+ {
+ return selectionStartLine;
+ }
+
+ /**
+ * Sets the selection start. The new selection will be the new
+ * selection start and the old selection end.
+ * @param selectionStart The selection start
+ * @see #select(int,int)
+ */
+ public final void setSelectionStart(int selectionStart)
+ {
+ select(selectionStart,selectionEnd);
+ }
+
+ /**
+ * Returns the selection end offset.
+ */
+ public final int getSelectionEnd()
+ {
+ return selectionEnd;
+ }
+
+ /**
+ * Returns the offset where the selection ends on the specified
+ * line.
+ */
+ public int getSelectionEnd(int line)
+ {
+ if(line == selectionEndLine)
+ return selectionEnd;
+ else if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ Element lineElement = map.getElement(line);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ return Math.min(lineEnd,lineStart + end);
+ }
+ else
+ return getLineEndOffset(line) - 1;
+ }
+
+ /**
+ * Returns the selection end line.
+ */
+ public final int getSelectionEndLine()
+ {
+ return selectionEndLine;
+ }
+
+ /**
+ * Sets the selection end. The new selection will be the old
+ * selection start and the bew selection end.
+ * @param selectionEnd The selection end
+ * @see #select(int,int)
+ */
+ public final void setSelectionEnd(int selectionEnd)
+ {
+ select(selectionStart,selectionEnd);
+ }
+
+ /**
+ * Returns the caret position. This will either be the selection
+ * start or the selection end, depending on which direction the
+ * selection was made in.
+ */
+ public final int getCaretPosition()
+ {
+ return (biasLeft ? selectionStart : selectionEnd);
+ }
+
+ /**
+ * Returns the caret line.
+ */
+ public final int getCaretLine()
+ {
+ return (biasLeft ? selectionStartLine : selectionEndLine);
+ }
+
+ /**
+ * Returns the mark position. This will be the opposite selection
+ * bound to the caret position.
+ * @see #getCaretPosition()
+ */
+ public final int getMarkPosition()
+ {
+ return (biasLeft ? selectionEnd : selectionStart);
+ }
+
+ /**
+ * Returns the mark line.
+ */
+ public final int getMarkLine()
+ {
+ return (biasLeft ? selectionEndLine : selectionStartLine);
+ }
+
+ /**
+ * Sets the caret position. The new selection will consist of the
+ * caret position only (hence no text will be selected)
+ * @param caret The caret position
+ * @see #select(int,int)
+ */
+ public final void setCaretPosition(int caret)
+ {
+ select(caret,caret);
+ }
+
+ /**
+ * Selects all text in the document.
+ */
+ public final void selectAll()
+ {
+ select(0,getDocumentLength());
+ }
+
+ /**
+ * Moves the mark to the caret position.
+ */
+ public final void selectNone()
+ {
+ select(getCaretPosition(),getCaretPosition());
+ }
+
+ /**
+ * Selects from the start offset to the end offset. This is the
+ * general selection method used by all other selecting methods.
+ * The caret position will be start if start < end, and end
+ * if end > start.
+ * @param start The start offset
+ * @param end The end offset
+ */
+ public void select(int start, int end)
+ {
+ int newStart, newEnd;
+ boolean newBias;
+ if(start <= end)
+ {
+ newStart = start;
+ newEnd = end;
+ newBias = false;
+ }
+ else
+ {
+ newStart = end;
+ newEnd = start;
+ newBias = true;
+ }
+
+ if(newStart < 0 || newEnd > getDocumentLength())
+ {
+ throw new IllegalArgumentException("Bounds out of"
+ + " range: " + newStart + "," +
+ newEnd);
+ }
+
+ // If the new position is the same as the old, we don't
+ // do all this crap, however we still do the stuff at
+ // the end (clearing magic position, scrolling)
+ if(newStart != selectionStart || newEnd != selectionEnd
+ || newBias != biasLeft)
+ {
+ int newStartLine = getLineOfOffset(newStart);
+ int newEndLine = getLineOfOffset(newEnd);
+
+ if(painter.isBracketHighlightEnabled())
+ {
+ if(bracketLine != -1)
+ painter.invalidateLine(bracketLine);
+ updateBracketHighlight(end);
+ if(bracketLine != -1)
+ painter.invalidateLine(bracketLine);
+ }
+
+ painter.invalidateLineRange(selectionStartLine,selectionEndLine);
+ painter.invalidateLineRange(newStartLine,newEndLine);
+
+ document.addUndoableEdit(new CaretUndo(
+ selectionStart,selectionEnd));
+
+ selectionStart = newStart;
+ selectionEnd = newEnd;
+ selectionStartLine = newStartLine;
+ selectionEndLine = newEndLine;
+ biasLeft = newBias;
+
+ fireCaretEvent();
+ }
+
+ // When the user is typing, etc, we don't want the caret
+ // to blink
+ blink = true;
+ caretTimer.restart();
+
+ // Disable rectangle select if selection start = selection end
+ if(selectionStart == selectionEnd)
+ rectSelect = false;
+
+ // Clear the `magic' caret position used by up/down
+ magicCaret = -1;
+
+ scrollToCaret();
+ }
+
+ /**
+ * Returns the selected text, or null if no selection is active.
+ */
+ public final String getSelectedText()
+ {
+ if(selectionStart == selectionEnd)
+ return null;
+
+ if(rectSelect)
+ {
+ // Return each row of the selection on a new line
+
+ Element map = document.getDefaultRootElement();
+
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ // Certain rectangles satisfy this condition...
+ if(end < start)
+ {
+ int tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ StringBuffer buf = new StringBuffer();
+ Segment seg = new Segment();
+
+ for(int i = selectionStartLine; i <= selectionEndLine; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ int lineLen = lineEnd - lineStart;
+
+ lineStart = Math.min(lineStart + start,lineEnd);
+ lineLen = Math.min(end - start,lineEnd - lineStart);
+
+ getText(lineStart,lineLen,seg);
+ buf.append(seg.array,seg.offset,seg.count);
+
+ if(i != selectionEndLine)
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+ else
+ {
+ return getText(selectionStart,
+ selectionEnd - selectionStart);
+ }
+ }
+
+ /**
+ * Replaces the selection with the specified text.
+ * @param selectedText The replacement text for the selection
+ */
+ public void setSelectedText(String selectedText)
+ {
+ if(!editable)
+ {
+ throw new InternalError("Text component"
+ + " read only");
+ }
+
+ document.beginCompoundEdit();
+
+ try
+ {
+ if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ // Certain rectangles satisfy this condition...
+ if(end < start)
+ {
+ int tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ int lastNewline = 0;
+ int currNewline = 0;
+
+ for(int i = selectionStartLine; i <= selectionEndLine; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ int rectStart = Math.min(lineEnd,lineStart + start);
+
+ document.remove(rectStart,Math.min(lineEnd - rectStart,
+ end - start));
+
+ if(selectedText == null)
+ continue;
+
+ currNewline = selectedText.indexOf('\n',lastNewline);
+ if(currNewline == -1)
+ currNewline = selectedText.length();
+
+ document.insertString(rectStart,selectedText
+ .substring(lastNewline,currNewline),null);
+
+ lastNewline = Math.min(selectedText.length(),
+ currNewline + 1);
+ }
+
+ if(selectedText != null &&
+ currNewline != selectedText.length())
+ {
+ int offset = map.getElement(selectionEndLine)
+ .getEndOffset() - 1;
+ document.insertString(offset,"\n",null);
+ document.insertString(offset + 1,selectedText
+ .substring(currNewline + 1),null);
+ }
+ }
+ else
+ {
+ document.remove(selectionStart,
+ selectionEnd - selectionStart);
+ if(selectedText != null)
+ {
+ document.insertString(selectionStart,
+ selectedText,null);
+ }
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ throw new InternalError("Cannot replace"
+ + " selection");
+ }
+ // No matter what happends... stops us from leaving document
+ // in a bad state
+ finally
+ {
+ document.endCompoundEdit();
+ }
+
+ setCaretPosition(selectionEnd);
+ }
+
+ /**
+ * Returns true if this text area is editable, false otherwise.
+ */
+ public final boolean isEditable()
+ {
+ return editable;
+ }
+
+ /**
+ * Sets if this component is editable.
+ * @param editable True if this text area should be editable,
+ * false otherwise
+ */
+ public final void setEditable(boolean editable)
+ {
+ this.editable = editable;
+ }
+
+ /**
+ * Returns the right click popup menu.
+ */
+ public final JPopupMenu getRightClickPopup()
+ {
+ return popup;
+ }
+
+ /**
+ * Sets the right click popup menu.
+ * @param popup The popup
+ */
+ public final void setRightClickPopup(JPopupMenu popup)
+ {
+ this.popup = popup;
+ }
+
+ /**
+ * Returns the `magic' caret position. This can be used to preserve
+ * the column position when moving up and down lines.
+ */
+ public final int getMagicCaretPosition()
+ {
+ return magicCaret;
+ }
+
+ /**
+ * Sets the `magic' caret position. This can be used to preserve
+ * the column position when moving up and down lines.
+ * @param magicCaret The magic caret position
+ */
+ public final void setMagicCaretPosition(int magicCaret)
+ {
+ this.magicCaret = magicCaret;
+ }
+
+ /**
+ * Similar to <code>setSelectedText()</code>, but overstrikes the
+ * appropriate number of characters if overwrite mode is enabled.
+ * @param str The string
+ * @see #setSelectedText(String)
+ * @see #isOverwriteEnabled()
+ */
+ public void overwriteSetSelectedText(String str)
+ {
+ // Don't overstrike if there is a selection
+ if(!overwrite || selectionStart != selectionEnd)
+ {
+ setSelectedText(str);
+ return;
+ }
+
+ // Don't overstrike if we're on the end of
+ // the line
+ int caret = getCaretPosition();
+ int caretLineEnd = getLineEndOffset(getCaretLine());
+ if(caretLineEnd - caret <= str.length())
+ {
+ setSelectedText(str);
+ return;
+ }
+
+ document.beginCompoundEdit();
+
+ try
+ {
+ document.remove(caret,str.length());
+ document.insertString(caret,str,null);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ finally
+ {
+ document.endCompoundEdit();
+ }
+ }
+
+ /**
+ * Returns true if overwrite mode is enabled, false otherwise.
+ */
+ public final boolean isOverwriteEnabled()
+ {
+ return overwrite;
+ }
+
+ /**
+ * Sets if overwrite mode should be enabled.
+ * @param overwrite True if overwrite mode should be enabled,
+ * false otherwise.
+ */
+ public final void setOverwriteEnabled(boolean overwrite)
+ {
+ this.overwrite = overwrite;
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if the selection is rectangular, false otherwise.
+ */
+ public final boolean isSelectionRectangular()
+ {
+ return rectSelect;
+ }
+
+ /**
+ * Sets if the selection should be rectangular.
+ * @param overwrite True if the selection should be rectangular,
+ * false otherwise.
+ */
+ public final void setSelectionRectangular(boolean rectSelect)
+ {
+ this.rectSelect = rectSelect;
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the position of the highlighted bracket (the bracket
+ * matching the one before the caret)
+ */
+ public final int getBracketPosition()
+ {
+ return bracketPosition;
+ }
+
+ /**
+ * Returns the line of the highlighted bracket (the bracket
+ * matching the one before the caret)
+ */
+ public final int getBracketLine()
+ {
+ return bracketLine;
+ }
+
+ /**
+ * Adds a caret change listener to this text area.
+ * @param listener The listener
+ */
+ public final void addCaretListener(CaretListener listener)
+ {
+ listenerList.add(CaretListener.class,listener);
+ }
+
+ /**
+ * Removes a caret change listener from this text area.
+ * @param listener The listener
+ */
+ public final void removeCaretListener(CaretListener listener)
+ {
+ listenerList.remove(CaretListener.class,listener);
+ }
+
+ /**
+ * Deletes the selected text from the text area and places it
+ * into the clipboard.
+ */
+ public void cut()
+ {
+ if(editable)
+ {
+ copy();
+ setSelectedText("");
+ }
+ }
+
+ /**
+ * Places the selected text into the clipboard.
+ */
+ public void copy()
+ {
+ if(selectionStart != selectionEnd)
+ {
+ Clipboard clipboard = getToolkit().getSystemClipboard();
+
+ String selection = getSelectedText();
+
+ int repeatCount = inputHandler.getRepeatCount();
+ StringBuffer buf = new StringBuffer();
+ for(int i = 0; i < repeatCount; i++)
+ buf.append(selection);
+
+ clipboard.setContents(new StringSelection(buf.toString()),null);
+ }
+ }
+
+ /**
+ * Inserts the clipboard contents into the text.
+ */
+ public void paste()
+ {
+ if(editable)
+ {
+ Clipboard clipboard = getToolkit().getSystemClipboard();
+ try
+ {
+ // The MacOS MRJ doesn't convert \r to \n,
+ // so do it here
+ String selection = ((String)clipboard
+ .getContents(this).getTransferData(
+ DataFlavor.stringFlavor))
+ .replace('\r','\n');
+
+ int repeatCount = inputHandler.getRepeatCount();
+ StringBuffer buf = new StringBuffer();
+ for(int i = 0; i < repeatCount; i++)
+ buf.append(selection);
+ selection = buf.toString();
+ setSelectedText(selection);
+ }
+ catch(Exception e)
+ {
+ getToolkit().beep();
+ System.err.println("Clipboard does not"
+ + " contain a string");
+ }
+ }
+ }
+
+ /**
+ * Called by the AWT when this component is removed from it's parent.
+ * This stops clears the currently focused component.
+ */
+ public void removeNotify()
+ {
+ super.removeNotify();
+ if(focusedComponent == this)
+ focusedComponent = null;
+ }
+
+ /**
+ * Forwards key events directly to the input handler.
+ * This is slightly faster than using a KeyListener
+ * because some Swing overhead is avoided.
+ */
+ public void processKeyEvent(KeyEvent evt)
+ {
+ if(inputHandler == null)
+ return;
+ switch(evt.getID())
+ {
+ case KeyEvent.KEY_TYPED:
+ inputHandler.keyTyped(evt);
+ break;
+ case KeyEvent.KEY_PRESSED:
+ inputHandler.keyPressed(evt);
+ break;
+ case KeyEvent.KEY_RELEASED:
+ inputHandler.keyReleased(evt);
+ break;
+ }
+ }
+
+ // protected members
+ protected static String CENTER = "center";
+ protected static String RIGHT = "right";
+ protected static String BOTTOM = "bottom";
+
+ protected static JEditTextArea focusedComponent;
+ protected static Timer caretTimer;
+
+ protected TextAreaPainter painter;
+
+ protected JPopupMenu popup;
+
+ protected EventListenerList listenerList;
+ protected MutableCaretEvent caretEvent;
+
+ protected boolean caretBlinks;
+ protected boolean caretVisible;
+ protected boolean blink;
+
+ protected boolean editable;
+
+ protected int firstLine;
+ protected int visibleLines;
+ protected int electricScroll;
+
+ protected int horizontalOffset;
+
+ protected JScrollBar vertical;
+ protected JScrollBar horizontal;
+ protected boolean scrollBarsInitialized;
+
+ protected InputHandler inputHandler;
+ protected SyntaxDocument document;
+ protected DocumentHandler documentHandler;
+
+ protected Segment lineSegment;
+
+ protected int selectionStart;
+ protected int selectionStartLine;
+ protected int selectionEnd;
+ protected int selectionEndLine;
+ protected boolean biasLeft;
+
+ protected int bracketPosition;
+ protected int bracketLine;
+
+ protected int magicCaret;
+ protected boolean overwrite;
+ protected boolean rectSelect;
+
+ protected void fireCaretEvent()
+ {
+ Object[] listeners = listenerList.getListenerList();
+ for(int i = listeners.length - 2; i >= 0; i--)
+ {
+ if(listeners[i] == CaretListener.class)
+ {
+ ((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
+ }
+ }
+ }
+
+ protected void updateBracketHighlight(int newCaretPosition)
+ {
+ if(newCaretPosition == 0)
+ {
+ bracketPosition = bracketLine = -1;
+ return;
+ }
+
+ try
+ {
+ int offset = TextUtilities.findMatchingBracket(
+ document,newCaretPosition - 1);
+ if(offset != -1)
+ {
+ bracketLine = getLineOfOffset(offset);
+ bracketPosition = offset - getLineStartOffset(bracketLine);
+ return;
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+
+ bracketLine = bracketPosition = -1;
+ }
+
+ protected void documentChanged(DocumentEvent evt)
+ {
+ DocumentEvent.ElementChange ch = evt.getChange(
+ document.getDefaultRootElement());
+
+ int count;
+ if(ch == null)
+ count = 0;
+ else
+ count = ch.getChildrenAdded().length -
+ ch.getChildrenRemoved().length;
+
+ int line = getLineOfOffset(evt.getOffset());
+ if(count == 0)
+ {
+ painter.invalidateLine(line);
+ }
+ // do magic stuff
+ else if(line < firstLine)
+ {
+ setFirstLine(firstLine + count);
+ }
+ // end of magic stuff
+ else
+ {
+ painter.invalidateLineRange(line,firstLine + visibleLines);
+ updateScrollBars();
+ }
+ }
+
+ class ScrollLayout implements LayoutManager
+ {
+ public void addLayoutComponent(String name, Component comp)
+ {
+ if(name.equals(CENTER))
+ center = comp;
+ else if(name.equals(RIGHT))
+ right = comp;
+ else if(name.equals(BOTTOM))
+ bottom = comp;
+ else if(name.equals(LEFT_OF_SCROLLBAR))
+ leftOfScrollBar.addElement(comp);
+ }
+
+ public void removeLayoutComponent(Component comp)
+ {
+ if(center == comp)
+ center = null;
+ if(right == comp)
+ right = null;
+ if(bottom == comp)
+ bottom = null;
+ else
+ leftOfScrollBar.removeElement(comp);
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ Dimension dim = new Dimension();
+ Insets insets = getInsets();
+ dim.width = insets.left + insets.right;
+ dim.height = insets.top + insets.bottom;
+
+ Dimension centerPref = center.getPreferredSize();
+ dim.width += centerPref.width;
+ dim.height += centerPref.height;
+ Dimension rightPref = right.getPreferredSize();
+ dim.width += rightPref.width;
+ Dimension bottomPref = bottom.getPreferredSize();
+ dim.height += bottomPref.height;
+
+ return dim;
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ Dimension dim = new Dimension();
+ Insets insets = getInsets();
+ dim.width = insets.left + insets.right;
+ dim.height = insets.top + insets.bottom;
+
+ Dimension centerPref = center.getMinimumSize();
+ dim.width += centerPref.width;
+ dim.height += centerPref.height;
+ Dimension rightPref = right.getMinimumSize();
+ dim.width += rightPref.width;
+ Dimension bottomPref = bottom.getMinimumSize();
+ dim.height += bottomPref.height;
+
+ return dim;
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ Dimension size = parent.getSize();
+ Insets insets = parent.getInsets();
+ int itop = insets.top;
+ int ileft = insets.left;
+ int ibottom = insets.bottom;
+ int iright = insets.right;
+
+ int rightWidth = right.getPreferredSize().width;
+ int bottomHeight = bottom.getPreferredSize().height;
+ int centerWidth = size.width - rightWidth - ileft - iright;
+ int centerHeight = size.height - bottomHeight - itop - ibottom;
+
+ center.setBounds(
+ ileft,
+ itop,
+ centerWidth,
+ centerHeight);
+
+ right.setBounds(
+ ileft + centerWidth,
+ itop,
+ rightWidth,
+ centerHeight);
+
+ // Lay out all status components, in order
+ Enumeration status = leftOfScrollBar.elements();
+ while(status.hasMoreElements())
+ {
+ Component comp = (Component)status.nextElement();
+ Dimension dim = comp.getPreferredSize();
+ comp.setBounds(ileft,
+ itop + centerHeight,
+ dim.width,
+ bottomHeight);
+ ileft += dim.width;
+ }
+
+ bottom.setBounds(
+ ileft,
+ itop + centerHeight,
+ size.width - rightWidth - ileft - iright,
+ bottomHeight);
+ }
+
+ // private members
+ private Component center;
+ private Component right;
+ private Component bottom;
+ private Vector leftOfScrollBar = new Vector();
+ }
+
+ static class CaretBlinker implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ if(focusedComponent != null
+ && focusedComponent.hasFocus())
+ focusedComponent.blinkCaret();
+ }
+ }
+
+ class MutableCaretEvent extends CaretEvent
+ {
+ MutableCaretEvent()
+ {
+ super(JEditTextArea.this);
+ }
+
+ public int getDot()
+ {
+ return getCaretPosition();
+ }
+
+ public int getMark()
+ {
+ return getMarkPosition();
+ }
+ }
+
+ class AdjustHandler implements AdjustmentListener
+ {
+ public void adjustmentValueChanged(final AdjustmentEvent evt)
+ {
+ if(!scrollBarsInitialized)
+ return;
+
+ // If this is not done, mousePressed events accumilate
+ // and the result is that scrolling doesn't stop after
+ // the mouse is released
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run()
+ {
+ if(evt.getAdjustable() == vertical)
+ setFirstLine(vertical.getValue());
+ else
+ setHorizontalOffset(-horizontal.getValue());
+ }
+ });
+ }
+ }
+
+ class ComponentHandler extends ComponentAdapter
+ {
+ public void componentResized(ComponentEvent evt)
+ {
+ recalculateVisibleLines();
+ scrollBarsInitialized = true;
+ }
+ }
+
+ class DocumentHandler implements DocumentListener
+ {
+ public void insertUpdate(DocumentEvent evt)
+ {
+ documentChanged(evt);
+
+ int offset = evt.getOffset();
+ int length = evt.getLength();
+
+ int newStart;
+ int newEnd;
+
+ if(selectionStart > offset || (selectionStart
+ == selectionEnd && selectionStart == offset))
+ newStart = selectionStart + length;
+ else
+ newStart = selectionStart;
+
+ if(selectionEnd >= offset)
+ newEnd = selectionEnd + length;
+ else
+ newEnd = selectionEnd;
+
+ select(newStart,newEnd);
+ }
+
+ public void removeUpdate(DocumentEvent evt)
+ {
+ documentChanged(evt);
+
+ int offset = evt.getOffset();
+ int length = evt.getLength();
+
+ int newStart;
+ int newEnd;
+
+ if(selectionStart > offset)
+ {
+ if(selectionStart > offset + length)
+ newStart = selectionStart - length;
+ else
+ newStart = offset;
+ }
+ else
+ newStart = selectionStart;
+
+ if(selectionEnd > offset)
+ {
+ if(selectionEnd > offset + length)
+ newEnd = selectionEnd - length;
+ else
+ newEnd = offset;
+ }
+ else
+ newEnd = selectionEnd;
+
+ select(newStart,newEnd);
+ }
+
+ public void changedUpdate(DocumentEvent evt)
+ {
+ }
+ }
+
+ class DragHandler implements MouseMotionListener
+ {
+ public void mouseDragged(MouseEvent evt)
+ {
+ if(popup != null && popup.isVisible())
+ return;
+
+ setSelectionRectangular((evt.getModifiers()
+ & InputEvent.CTRL_MASK) != 0);
+ select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
+ }
+
+ public void mouseMoved(MouseEvent evt) {}
+ }
+
+ class FocusHandler implements FocusListener
+ {
+ public void focusGained(FocusEvent evt)
+ {
+ setCaretVisible(true);
+ focusedComponent = JEditTextArea.this;
+ }
+
+ public void focusLost(FocusEvent evt)
+ {
+ setCaretVisible(false);
+ focusedComponent = null;
+ }
+ }
+
+ class MouseHandler extends MouseAdapter
+ {
+ public void mousePressed(MouseEvent evt)
+ {
+ requestFocus();
+
+ // Focus events not fired sometimes?
+ setCaretVisible(true);
+ focusedComponent = JEditTextArea.this;
+
+ if((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0
+ && popup != null)
+ {
+ popup.show(painter,evt.getX(),evt.getY());
+ return;
+ }
+
+ int line = yToLine(evt.getY());
+ int offset = xToOffset(line,evt.getX());
+ int dot = getLineStartOffset(line) + offset;
+
+ switch(evt.getClickCount())
+ {
+ case 1:
+ doSingleClick(evt,line,offset,dot);
+ break;
+ case 2:
+ // It uses the bracket matching stuff, so
+ // it can throw a BLE
+ try
+ {
+ doDoubleClick(evt,line,offset,dot);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ break;
+ case 3:
+ doTripleClick(evt,line,offset,dot);
+ break;
+ }
+ }
+
+ private void doSingleClick(MouseEvent evt, int line,
+ int offset, int dot)
+ {
+ if((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0)
+ {
+ rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
+ select(getMarkPosition(),dot);
+ }
+ else
+ setCaretPosition(dot);
+ }
+
+ private void doDoubleClick(MouseEvent evt, int line,
+ int offset, int dot) throws BadLocationException
+ {
+ // Ignore empty lines
+ if(getLineLength(line) == 0)
+ return;
+
+ try
+ {
+ int bracket = TextUtilities.findMatchingBracket(
+ document,Math.max(0,dot - 1));
+ if(bracket != -1)
+ {
+ int mark = getMarkPosition();
+ // Hack
+ if(bracket > mark)
+ {
+ bracket++;
+ mark--;
+ }
+ select(mark,bracket);
+ return;
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+
+ // Ok, it's not a bracket... select the word
+ String lineText = getLineText(line);
+ char ch = lineText.charAt(Math.max(0,offset - 1));
+
+ String noWordSep = (String)document.getProperty("noWordSep");
+ if(noWordSep == null)
+ noWordSep = "";
+
+ // If the user clicked on a non-letter char,
+ // we select the surrounding non-letters
+ boolean selectNoLetter = (!Character
+ .isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ int wordStart = 0;
+
+ for(int i = offset - 1; i >= 0; i--)
+ {
+ ch = lineText.charAt(i);
+ if(selectNoLetter ^ (!Character
+ .isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordStart = i + 1;
+ break;
+ }
+ }
+
+ int wordEnd = lineText.length();
+ for(int i = offset; i < lineText.length(); i++)
+ {
+ ch = lineText.charAt(i);
+ if(selectNoLetter ^ (!Character
+ .isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordEnd = i;
+ break;
+ }
+ }
+
+ int lineStart = getLineStartOffset(line);
+ select(lineStart + wordStart,lineStart + wordEnd);
+
+ /*
+ String lineText = getLineText(line);
+ String noWordSep = (String)document.getProperty("noWordSep");
+ int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
+ int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
+
+ int lineStart = getLineStartOffset(line);
+ select(lineStart + wordStart,lineStart + wordEnd);
+ */
+ }
+
+ private void doTripleClick(MouseEvent evt, int line,
+ int offset, int dot)
+ {
+ select(getLineStartOffset(line),getLineEndOffset(line)-1);
+ }
+ }
+
+ class CaretUndo extends AbstractUndoableEdit
+ {
+ private int start;
+ private int end;
+
+ CaretUndo(int start, int end)
+ {
+ this.start = start;
+ this.end = end;
+ }
+
+ public boolean isSignificant()
+ {
+ return false;
+ }
+
+ public String getPresentationName()
+ {
+ return "caret move";
+ }
+
+ public void undo() throws CannotUndoException
+ {
+ super.undo();
+
+ select(start,end);
+ }
+
+ public void redo() throws CannotRedoException
+ {
+ super.redo();
+
+ select(start,end);
+ }
+
+ public boolean addEdit(UndoableEdit edit)
+ {
+ if(edit instanceof CaretUndo)
+ {
+ CaretUndo cedit = (CaretUndo)edit;
+ start = cedit.start;
+ end = cedit.end;
+ cedit.die();
+
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ static
+ {
+ caretTimer = new Timer(500,new CaretBlinker());
+ caretTimer.setInitialDelay(500);
+ caretTimer.start();
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/KeywordMap.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/KeywordMap.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/KeywordMap.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/KeywordMap.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,139 @@
+/*
+ * KeywordMap.java - Fast keyword->id map
+ * Copyright (C) 1998, 1999 Slava Pestov
+ * Copyright (C) 1999 Mike Dillon
+ *
+ * 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;
+
+/**
+ * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
+ * to values. However, the `keys' are Swing segments. This allows lookups of
+ * text substrings without the overhead of creating a new string object.
+ * <p>
+ * This class is used by <code>CTokenMarker</code> to map keywords to ids.
+ *
+ * @author Slava Pestov, Mike Dillon
+ * @version $Id: KeywordMap.java,v 1.16 1999/12/13 03:40:30 sp Exp $
+ */
+public class KeywordMap
+{
+ /**
+ * Creates a new <code>KeywordMap</code>.
+ * @param ignoreCase True if keys are case insensitive
+ */
+ public KeywordMap(boolean ignoreCase)
+ {
+ this(ignoreCase, 52);
+ this.ignoreCase = ignoreCase;
+ }
+
+ /**
+ * Creates a new <code>KeywordMap</code>.
+ * @param ignoreCase True if the keys are case insensitive
+ * @param mapLength The number of `buckets' to create.
+ * A value of 52 will give good performance for most maps.
+ */
+ public KeywordMap(boolean ignoreCase, int mapLength)
+ {
+ this.mapLength = mapLength;
+ this.ignoreCase = ignoreCase;
+ map = new Keyword[mapLength];
+ }
+
+ /**
+ * Looks up a key.
+ * @param text The text segment
+ * @param offset The offset of the substring within the text segment
+ * @param length The length of the substring
+ */
+ public byte lookup(Segment text, int offset, int length)
+ {
+ if(length == 0)
+ return Token.NULL;
+ Keyword k = map[getSegmentMapKey(text, offset, length)];
+ while(k != null)
+ {
+ if(length != k.keyword.length)
+ {
+ k = k.next;
+ continue;
+ }
+ if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
+ k.keyword))
+ return k.id;
+ k = k.next;
+ }
+ return Token.NULL;
+ }
+
+ /**
+ * Adds a key-value mapping.
+ * @param keyword The key
+ * @Param id The value
+ */
+ public void add(String keyword, byte id)
+ {
+ int key = getStringMapKey(keyword);
+ map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
+ }
+
+ /**
+ * Returns true if the keyword map is set to be case insensitive,
+ * false otherwise.
+ */
+ public boolean getIgnoreCase()
+ {
+ return ignoreCase;
+ }
+
+ /**
+ * Sets if the keyword map should be case insensitive.
+ * @param ignoreCase True if the keyword map should be case
+ * insensitive, false otherwise
+ */
+ public void setIgnoreCase(boolean ignoreCase)
+ {
+ this.ignoreCase = ignoreCase;
+ }
+
+ // protected members
+ protected int mapLength;
+
+ protected int getStringMapKey(String s)
+ {
+ return (Character.toUpperCase(s.charAt(0)) +
+ Character.toUpperCase(s.charAt(s.length()-1)))
+ % mapLength;
+ }
+
+ protected int getSegmentMapKey(Segment s, int off, int len)
+ {
+ return (Character.toUpperCase(s.array[off]) +
+ Character.toUpperCase(s.array[off + len - 1]))
+ % mapLength;
+ }
+
+ // private members
+ class Keyword
+ {
+ public Keyword(char[] keyword, byte id, Keyword next)
+ {
+ this.keyword = keyword;
+ this.id = id;
+ this.next = next;
+ }
+
+ public char[] keyword;
+ public byte id;
+ public Keyword next;
+ }
+
+ private Keyword[] map;
+ private boolean ignoreCase;
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxDocument.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxDocument.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxDocument.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxDocument.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,165 @@
+/*
+ * SyntaxDocument.java - Document that can be tokenized
+ * 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.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.UndoableEdit;
+
+/**
+ * A document implementation that can be tokenized by the syntax highlighting
+ * system.
+ *
+ * @author Slava Pestov
+ * @version $Id: SyntaxDocument.java,v 1.14 1999/12/13 03:40:30 sp Exp $
+ */
+public class SyntaxDocument extends PlainDocument
+{
+ /**
+ * Returns the token marker that is to be used to split lines
+ * of this document up into tokens. May return null if this
+ * document is not to be colorized.
+ */
+ public TokenMarker getTokenMarker()
+ {
+ return tokenMarker;
+ }
+
+ /**
+ * Sets the token marker that is to be used to split lines of
+ * this document up into tokens. May throw an exception if
+ * this is not supported for this type of document.
+ * @param tm The new token marker
+ */
+ public void setTokenMarker(TokenMarker tm)
+ {
+ tokenMarker = tm;
+ if(tm == null)
+ return;
+ tokenMarker.insertLines(0,getDefaultRootElement()
+ .getElementCount());
+ tokenizeLines();
+ }
+
+ /**
+ * Reparses the document, by passing all lines to the token
+ * marker. This should be called after the document is first
+ * loaded.
+ */
+ public void tokenizeLines()
+ {
+ tokenizeLines(0,getDefaultRootElement().getElementCount());
+ }
+
+ /**
+ * Reparses the document, by passing the specified lines to the
+ * token marker. This should be called after a large quantity of
+ * text is first inserted.
+ * @param start The first line to parse
+ * @param len The number of lines, after the first one to parse
+ */
+ public void tokenizeLines(int start, int len)
+ {
+ if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
+ return;
+
+ Segment lineSegment = new Segment();
+ Element map = getDefaultRootElement();
+
+ len += start;
+
+ try
+ {
+ for(int i = start; i < len; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ getText(lineStart,lineElement.getEndOffset()
+ - lineStart - 1,lineSegment);
+ tokenMarker.markTokens(lineSegment,i);
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+
+ /**
+ * Starts a compound edit that can be undone in one operation.
+ * Subclasses that implement undo should override this method;
+ * this class has no undo functionality so this method is
+ * empty.
+ */
+ public void beginCompoundEdit() {}
+
+ /**
+ * Ends a compound edit that can be undone in one operation.
+ * Subclasses that implement undo should override this method;
+ * this class has no undo functionality so this method is
+ * empty.
+ */
+ public void endCompoundEdit() {}
+
+ /**
+ * Adds an undoable edit to this document's undo list. The edit
+ * should be ignored if something is currently being undone.
+ * @param edit The undoable edit
+ *
+ * @since jEdit 2.2pre1
+ */
+ public void addUndoableEdit(UndoableEdit edit) {}
+
+ // protected members
+ protected TokenMarker tokenMarker;
+
+ /**
+ * We overwrite this method to update the token marker
+ * state immediately so that any event listeners get a
+ * consistent token marker.
+ */
+ protected void fireInsertUpdate(DocumentEvent evt)
+ {
+ if(tokenMarker != null)
+ {
+ DocumentEvent.ElementChange ch = evt.getChange(
+ getDefaultRootElement());
+ if(ch != null)
+ {
+ tokenMarker.insertLines(ch.getIndex() + 1,
+ ch.getChildrenAdded().length -
+ ch.getChildrenRemoved().length);
+ }
+ }
+
+ super.fireInsertUpdate(evt);
+ }
+
+ /**
+ * We overwrite this method to update the token marker
+ * state immediately so that any event listeners get a
+ * consistent token marker.
+ */
+ protected void fireRemoveUpdate(DocumentEvent evt)
+ {
+ if(tokenMarker != null)
+ {
+ DocumentEvent.ElementChange ch = evt.getChange(
+ getDefaultRootElement());
+ if(ch != null)
+ {
+ tokenMarker.deleteLines(ch.getIndex() + 1,
+ ch.getChildrenRemoved().length -
+ ch.getChildrenAdded().length);
+ }
+ }
+
+ super.fireRemoveUpdate(evt);
+ }
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxStyle.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxStyle.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxStyle.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxStyle.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,136 @@
+/*
+ * SyntaxStyle.java - A simple text style class
+ * 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 java.awt.*;
+import java.util.StringTokenizer;
+
+/**
+ * A simple text style class. It can specify the color, italic flag,
+ * and bold flag of a run of text.
+ * @author Slava Pestov
+ * @version $Id: SyntaxStyle.java,v 1.6 1999/12/13 03:40:30 sp Exp $
+ */
+public class SyntaxStyle
+{
+ /**
+ * Creates a new SyntaxStyle.
+ * @param color The text color
+ * @param italic True if the text should be italics
+ * @param bold True if the text should be bold
+ */
+ public SyntaxStyle(Color color, boolean italic, boolean bold)
+ {
+ this.color = color;
+ this.italic = italic;
+ this.bold = bold;
+ }
+
+ /**
+ * Returns the color specified in this style.
+ */
+ public Color getColor()
+ {
+ return color;
+ }
+
+ /**
+ * Returns true if no font styles are enabled.
+ */
+ public boolean isPlain()
+ {
+ return !(bold || italic);
+ }
+
+ /**
+ * Returns true if italics is enabled for this style.
+ */
+ public boolean isItalic()
+ {
+ return italic;
+ }
+
+ /**
+ * Returns true if boldface is enabled for this style.
+ */
+ public boolean isBold()
+ {
+ return bold;
+ }
+
+ /**
+ * Returns the specified font, but with the style's bold and
+ * italic flags applied.
+ */
+ public Font getStyledFont(Font font)
+ {
+ if(font == null)
+ throw new NullPointerException("font param must not"
+ + " be null");
+ if(font.equals(lastFont))
+ return lastStyledFont;
+ lastFont = font;
+ lastStyledFont = new Font(font.getFamily(),
+ (bold ? Font.BOLD : 0)
+ | (italic ? Font.ITALIC : 0),
+ font.getSize());
+ return lastStyledFont;
+ }
+
+ /**
+ * Returns the font metrics for the styled font.
+ */
+ public FontMetrics getFontMetrics(Font font)
+ {
+ if(font == null)
+ throw new NullPointerException("font param must not"
+ + " be null");
+ if(font.equals(lastFont) && fontMetrics != null)
+ return fontMetrics;
+ lastFont = font;
+ lastStyledFont = new Font(font.getFamily(),
+ (bold ? Font.BOLD : 0)
+ | (italic ? Font.ITALIC : 0),
+ font.getSize());
+ fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(
+ lastStyledFont);
+ return fontMetrics;
+ }
+
+ /**
+ * Sets the foreground color and font of the specified graphics
+ * context to that specified in this style.
+ * @param gfx The graphics context
+ * @param font The font to add the styles to
+ */
+ public void setGraphicsFlags(Graphics gfx, Font font)
+ {
+ Font _font = getStyledFont(font);
+ gfx.setFont(_font);
+ gfx.setColor(color);
+ }
+
+ /**
+ * Returns a string representation of this object.
+ */
+ public String toString()
+ {
+ return getClass().getName() + "[color=" + color +
+ (italic ? ",italic" : "") +
+ (bold ? ",bold" : "") + "]";
+ }
+
+ // private members
+ private Color color;
+ private boolean italic;
+ private boolean bold;
+ private Font lastFont;
+ private Font lastStyledFont;
+ private FontMetrics fontMetrics;
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxUtilities.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxUtilities.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxUtilities.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/SyntaxUtilities.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,158 @@
+/*
+ * SyntaxUtilities.java - Utility functions used by syntax colorizing
+ * 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.*;
+import java.awt.*;
+
+/**
+ * Class with several utility functions used by jEdit's syntax colorizing
+ * subsystem.
+ *
+ * @author Slava Pestov
+ * @version $Id: SyntaxUtilities.java,v 1.9 1999/12/13 03:40:30 sp Exp $
+ */
+public class SyntaxUtilities
+{
+ /**
+ * Checks if a subregion of a <code>Segment</code> is equal to a
+ * string.
+ * @param ignoreCase True if case should be ignored, false otherwise
+ * @param text The segment
+ * @param offset The offset into the segment
+ * @param match The string to match
+ */
+ public static boolean regionMatches(boolean ignoreCase, Segment text,
+ int offset, String match)
+ {
+ int length = offset + match.length();
+ char[] textArray = text.array;
+ if(length > text.offset + text.count)
+ return false;
+ for(int i = offset, j = 0; i < length; i++, j++)
+ {
+ char c1 = textArray[i];
+ char c2 = match.charAt(j);
+ if(ignoreCase)
+ {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ }
+ if(c1 != c2)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if a subregion of a <code>Segment</code> is equal to a
+ * character array.
+ * @param ignoreCase True if case should be ignored, false otherwise
+ * @param text The segment
+ * @param offset The offset into the segment
+ * @param match The character array to match
+ */
+ public static boolean regionMatches(boolean ignoreCase, Segment text,
+ int offset, char[] match)
+ {
+ int length = offset + match.length;
+ char[] textArray = text.array;
+ if(length > text.offset + text.count)
+ return false;
+ for(int i = offset, j = 0; i < length; i++, j++)
+ {
+ char c1 = textArray[i];
+ char c2 = match[j];
+ if(ignoreCase)
+ {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ }
+ if(c1 != c2)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the default style table. This can be passed to the
+ * <code>setStyles()</code> method of <code>SyntaxDocument</code>
+ * to use the default syntax styles.
+ */
+ public static SyntaxStyle[] getDefaultSyntaxStyles()
+ {
+ SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
+
+ styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,true);
+ styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,true);
+ styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
+ styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,true);
+ styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
+ styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x659600),false,false);
+ styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
+ styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
+ styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
+ styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
+ styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
+
+ return styles;
+ }
+
+ /**
+ * Paints the specified line onto the graphics context. Note that this
+ * method munges the offset and count values of the segment.
+ * @param line The line segment
+ * @param tokens The token list for the line
+ * @param styles The syntax style list
+ * @param expander The tab expander used to determine tab stops. May
+ * be null
+ * @param gfx The graphics context
+ * @param x The x co-ordinate
+ * @param y The y co-ordinate
+ * @return The x co-ordinate, plus the width of the painted string
+ */
+ public static int paintSyntaxLine(Segment line, Token tokens,
+ SyntaxStyle[] styles, TabExpander expander, Graphics gfx,
+ int x, int y)
+ {
+ Font defaultFont = gfx.getFont();
+ Color defaultColor = gfx.getColor();
+
+ int offset = 0;
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ break;
+
+ int length = tokens.length;
+ if(id == Token.NULL)
+ {
+ if(!defaultColor.equals(gfx.getColor()))
+ gfx.setColor(defaultColor);
+ if(!defaultFont.equals(gfx.getFont()))
+ gfx.setFont(defaultFont);
+ }
+ else
+ styles[id].setGraphicsFlags(gfx,defaultFont);
+
+ line.count = length;
+ x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
+ line.offset += length;
+ offset += length;
+
+ tokens = tokens.next;
+ }
+
+ return x;
+ }
+
+ // private members
+ private SyntaxUtilities() {}
+}
Added: xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaDefaults.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaDefaults.java?rev=594367&view=auto
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaDefaults.java (added)
+++ xmlgraphics/batik/trunk/sources/org/gjt/sp/jedit/textarea/TextAreaDefaults.java Mon Nov 12 16:40:53 2007
@@ -0,0 +1,83 @@
+/*
+ * TextAreaDefaults.java - Encapsulates default values for various settings
+ * 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.JPopupMenu;
+import java.awt.Color;
+
+/**
+ * Encapsulates default settings for a text area. This can be passed
+ * to the constructor once the necessary fields have been filled out.
+ * The advantage of doing this over calling lots of set() methods after
+ * creating the text area is that this method is faster.
+ */
+public class TextAreaDefaults
+{
+ private static TextAreaDefaults DEFAULTS;
+
+ public InputHandler inputHandler;
+ public SyntaxDocument document;
+ public boolean editable;
+
+ public boolean caretVisible;
+ public boolean caretBlinks;
+ public boolean blockCaret;
+ public int electricScroll;
+
+ public int cols;
+ public int rows;
+ public SyntaxStyle[] styles;
+ public Color caretColor;
+ public Color selectionColor;
+ public Color lineHighlightColor;
+ public boolean lineHighlight;
+ public Color bracketHighlightColor;
+ public boolean bracketHighlight;
+ public Color eolMarkerColor;
+ public boolean eolMarkers;
+ public boolean paintInvalid;
+
+ public JPopupMenu popup;
+
+ /**
+ * Returns a new TextAreaDefaults object with the default values filled
+ * in.
+ */
+ public static TextAreaDefaults getDefaults()
+ {
+ if(DEFAULTS == null)
+ {
+ DEFAULTS = new TextAreaDefaults();
+
+ DEFAULTS.inputHandler = new DefaultInputHandler();
+ DEFAULTS.inputHandler.addDefaultKeyBindings();
+ DEFAULTS.document = new SyntaxDocument();
+ DEFAULTS.editable = true;
+
+ DEFAULTS.caretVisible = true;
+ DEFAULTS.caretBlinks = true;
+ DEFAULTS.electricScroll = 3;
+
+ DEFAULTS.cols = 80;
+ DEFAULTS.rows = 25;
+ DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
+ DEFAULTS.caretColor = Color.red;
+ DEFAULTS.selectionColor = new Color(0xccccff);
+ DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
+ DEFAULTS.lineHighlight = true;
+ DEFAULTS.bracketHighlightColor = Color.black;
+ DEFAULTS.bracketHighlight = true;
+ DEFAULTS.eolMarkerColor = new Color(0x009999);
+ DEFAULTS.eolMarkers = true;
+ DEFAULTS.paintInvalid = true;
+ }
+
+ return DEFAULTS;
+ }
+}