rsyntaxtextarea-2.5.0.orig/ 0000755 0001750 0000144 00000000000 12231031523 014376 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/ 0000755 0001750 0000144 00000000000 12201172610 015165 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/ 0000755 0001750 0000144 00000000000 12200540536 015761 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/fife/ 0000755 0001750 0000144 00000000000 12200540536 016672 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/fife/io/ 0000755 0001750 0000144 00000000000 12202002500 017263 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/fife/io/UnicodeWriter.java 0000644 0001750 0000144 00000016200 12202002500 022710 0 ustar ben users /*
* 09/24/2004
*
* UnicodeWriter.java - Writes Unicode output with the proper BOM.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
/**
* Writes Unicode text to an output stream. If the specified encoding is a
* Unicode, then the text is preceded by the proper Unicode BOM. If it is any
* other encoding, this class behaves just like OutputStreamWriter
.
* This class is here because Java's OutputStreamWriter
apparently
* doesn't believe in writing BOMs.
*
*
* For optimum performance, it is recommended that you wrap all instances of
* UnicodeWriter
with a java.io.BufferedWriter
.
*
* @author Robert Futrell
* @version 0.7
*/
public class UnicodeWriter extends Writer {
/**
* If this system property evaluates to "false
", ignoring
* case, files written out as UTF-8 will not have a BOM written for them.
* Otherwise (even if the property is not set), UTF-8 files will have a
* BOM written.
*/
public static final String PROPERTY_WRITE_UTF8_BOM =
"UnicodeWriter.writeUtf8BOM";
/**
* The writer actually doing the writing.
*/
private OutputStreamWriter internalOut;
private static final byte[] UTF8_BOM = new byte[] {
(byte)0xEF,
(byte)0xBB,
(byte)0xBF
};
private static final byte[] UTF16LE_BOM = new byte[] {
(byte)0xFF,
(byte)0xFE
};
private static final byte[] UTF16BE_BOM = new byte[] {
(byte)0xFE,
(byte)0xFF
};
private static final byte[] UTF32LE_BOM = new byte[] {
(byte)0xFF,
(byte)0xFE,
(byte)0x00,
(byte)0x00
};
private static final byte[] UTF32BE_BOM = new byte[] {
(byte)0x00,
(byte)0x00,
(byte)0xFE,
(byte)0xFF
};
/**
* This is a utility constructor since the vast majority of the time, this
* class will be used to write Unicode files.
*
* @param fileName The file to which to write the Unicode output.
* @param encoding The encoding to use.
* @throws UnsupportedEncodingException If the specified encoding is not
* supported.
* @throws IOException If an IO exception occurs.
*/
public UnicodeWriter(String fileName, String encoding)
throws UnsupportedEncodingException, IOException {
this(new FileOutputStream(fileName), encoding);
}
/**
* This is a utility constructor since the vast majority of the time, this
* class will be used to write Unicode files.
*
* @param file The file to which to write the Unicode output.
* @param encoding The encoding to use.
* @throws UnsupportedEncodingException If the specified encoding is not
* supported.
* @throws IOException If an IO exception occurs.
*/
public UnicodeWriter(File file, String encoding)
throws UnsupportedEncodingException, IOException {
this(new FileOutputStream(file), encoding);
}
/**
* Creates a new writer.
*
* @param out The output stream to write.
* @param encoding The encoding to use.
* @throws UnsupportedEncodingException If the specified encoding is not
* supported.
* @throws IOException If an IO exception occurs.
*/
public UnicodeWriter(OutputStream out, String encoding)
throws UnsupportedEncodingException, IOException {
init(out, encoding);
}
/**
* Closes this writer.
*
* @throws IOException If an IO exception occurs.
*/
@Override
public void close() throws IOException {
internalOut.close();
}
/**
* Flushes the stream.
*
* @throws IOException If an IO exception occurs.
*/
@Override
public void flush() throws IOException {
internalOut.flush();
}
/**
* Returns the encoding being used to write this output stream (i.e., the
* encoding of the file).
*
* @return The encoding of the stream.
*/
public String getEncoding() {
return internalOut.getEncoding();
}
/**
* Returns whether UTF-8 files should have a BOM in them when written.
*
* @return Whether to write a BOM for UTF-8 files.
*/
public static boolean getWriteUtf8BOM() {
String prop = System.getProperty(PROPERTY_WRITE_UTF8_BOM);
if (prop!=null && Boolean.valueOf(prop).equals(Boolean.FALSE)) {
return false;
}
return true;
}
/**
* Initializes the internal output stream and writes the BOM if the
* specified encoding is a Unicode encoding.
*
* @param out The output stream we are writing.
* @param encoding The encoding in which to write.
* @throws UnsupportedEncodingException If the specified encoding isn't
* supported.
* @throws IOException If an I/O error occurs while writing a BOM.
*/
private void init(OutputStream out, String encoding)
throws UnsupportedEncodingException, IOException {
internalOut = new OutputStreamWriter(out, encoding);
// Write the proper BOM if they specified a Unicode encoding.
// NOTE: Creating an OutputStreamWriter with encoding "UTF-16" DOES
// DOES write out the BOM; "UTF-16LE", "UTF-16BE", "UTF-32", "UTF-32LE"
// and "UTF-32BE" don't.
if ("UTF-8".equals(encoding)) {
if (getWriteUtf8BOM()) {
out.write(UTF8_BOM, 0, UTF8_BOM.length);
}
}
else if ("UTF-16LE".equals(encoding)) {
out.write(UTF16LE_BOM, 0, UTF16LE_BOM.length);
}
else if (/*"UTF-16".equals(encoding) || */"UTF-16BE".equals(encoding)) {
out.write(UTF16BE_BOM, 0, UTF16BE_BOM.length);
}
else if ("UTF-32LE".equals(encoding)) {
out.write(UTF32LE_BOM, 0, UTF32LE_BOM.length);
}
else if ("UTF-32".equals(encoding) || "UTF-32BE".equals(encoding)) {
out.write(UTF32BE_BOM, 0, UTF32BE_BOM.length);
}
}
/**
* Writes a portion of an array of characters.
*
* @param cbuf The buffer of characters.
* @param off The offset from which to start writing characters.
* @param len The number of characters to write.
* @throws IOException If an I/O error occurs.
*/
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
internalOut.write(cbuf, off, len);
}
/**
* Writes a single character.
*
* @param c An integer specifying the character to write.
* @throws IOException If an IO error occurs.
*/
@Override
public void write(int c) throws IOException {
internalOut.write(c);
}
/**
* Writes a portion of a string.
*
* @param str The string from which to write.
* @param off The offset from which to start writing characters.
* @param len The number of characters to write.
* @throws IOException If an IO error occurs.
*/
@Override
public void write(String str, int off, int len) throws IOException {
internalOut.write(str, off, len);
}
} rsyntaxtextarea-2.5.0.orig/src/org/fife/io/DocumentReader.java 0000644 0001750 0000144 00000011452 12202002500 023032 0 ustar ben users /*
* 02/24/2004
*
* DocumentReader.java - A reader for javax.swing.text.Document
* objects.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.io;
import java.io.Reader;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
/**
* A Reader
for javax.swing.text.Document
objects.
*
* @author Robert Futrell
* @version 1.0
*/
public class DocumentReader extends Reader {
/**
* The stream's position in the document.
*/
private long position;
/**
* A remembered position in the document.
*/
private long mark;
/**
* The document we're working on.
*/
private Document document;
/**
* Used for fast character access.
*/
private Segment segment;
/**
* Constructor.
*
* @param document The document we're 'reading'.
*/
public DocumentReader(Document document) {
position = 0;
mark = -1;
this.document = document;
this.segment = new Segment();
}
/**
* This currently does nothing...
*/
@Override
public void close() {
}
/**
* Marks the present position in the stream. Subsequent calls to
* reset()
will reposition the stream to this point.
*
* @param readAheadLimit Ignored.
*/
@Override
public void mark(int readAheadLimit) {
mark = position;
}
/**
* Tells whether this reader supports the mark
operation.
* This always returns true
for DocumentReader
.
*/
@Override
public boolean markSupported() {
return true;
}
/**
* Reads the single character at the current position in the document.
*/
@Override
public int read() {
if(position>=document.getLength()) {
return -1; // Read past end of document.
}
try {
document.getText((int)position,1, segment);
position++;
return segment.array[segment.offset];
} catch (BadLocationException ble) {
/* Should never happen?? */
ble.printStackTrace();
return -1;
}
}
/**
* Read array.length
characters from the beginning
* of the document into array
.
*
* @param array The array to read characters into.
* @return The number of characters read.
*/
@Override
public int read(char array[]) {
return read(array, 0, array.length);
}
/**
* Reads characters into a portion of an array.
*
* @param cbuf The destination buffer.
* @param off Offset at which to start storing characters.
* @param len Maximum number of characters to read.
* @return The number of characters read, or -1
if the
* end of the stream (document) has been reached.
*/
@Override
public int read(char cbuf[], int off, int len) {
int k;
if(position>=document.getLength()) {
return -1; // Read past end of document.
}
k = len;
if((position+k)>=document.getLength())
k = document.getLength() - (int)position;
if(off + k >= cbuf.length)
k = cbuf.length - off;
try {
document.getText((int)position, k, segment);
position += k;
System.arraycopy(segment.array,segment.offset,
cbuf,off,
k);
return k;
} catch (BadLocationException ble) {
/* Should never happen ? */
return -1;
}
}
/**
* Tells whether this reader is ready to be read without
* blocking for input. DocumentReader
will
* always return true.
*
* @return true
if the next read operation will
* return without blocking.
*/
@Override
public boolean ready() {
return true;
}
/**
* Resets the stream. If the stream has been marked, then attempt to
* reposition it at the mark. If the stream has not been marked, then
* move it to the beginning of the document.
*/
@Override
public void reset() {
if(mark==-1) {
position = 0;
}
else {
position = mark;
mark = -1;
}
}
/**
* Skips characters. This will not 'skip' past the end of the document.
*
* @param n The number of characters to skip.
* @return The number of characters actually skipped.
*/
@Override
public long skip(long n) {
if (position+n<=document.getLength()) {
position += n;
return n;
}
long temp = position;
position = document.getLength();
return document.getLength() - temp;
}
/**
* Move to the specified position in the document. If pos
* is greater than the document's length, the stream's position is moved
* to the end of the document.
*
* @param pos The position in the document to move to.
*/
public void seek(long pos) {
position = Math.min(pos, document.getLength());
}
} rsyntaxtextarea-2.5.0.orig/src/org/fife/io/package.html 0000644 0001750 0000144 00000000073 12200540536 021562 0 ustar ben users
*
* For optimum performance, it is recommended that you wrap all instances of
* UnicodeReader
with a java.io.BufferedReader
.
*
* This class is mostly ripped off from the workaround in the description of
* Java Bug 4508058.
*
* @author Robert Futrell
* @version 0.9
*/
public class UnicodeReader extends Reader {
/**
* The input stream from which we're really reading.
*/
private InputStreamReader internalIn = null;
/**
* The encoding being used. We keep our own instead of using the string
* returned by java.io.InputStreamReader
since that class
* does not return user-friendly names.
*/
private String encoding;
/**
* The size of a BOM.
*/
private static final int BOM_SIZE = 4;
/**
* This utility constructor is here because you will usually use a
* UnicodeReader
on files.
* Creates a reader using the encoding specified by the BOM in the file;
* if there is no recognized BOM, then a system default encoding is used.
*
* @param file The file from which you want to read.
* @throws IOException If an error occurs when checking for/reading the
* BOM.
* @throws FileNotFoundException If the file does not exist, is a
* directory, or cannot be opened for reading.
* @throws SecurityException If a security manager exists and its
* checkRead method denies read access to the file.
*/
public UnicodeReader(String file) throws IOException,
FileNotFoundException, SecurityException {
this(new File(file));
}
/**
* This utility constructor is here because you will usually use a
* UnicodeReader
on files.
* Creates a reader using the encoding specified by the BOM in the file;
* if there is no recognized BOM, then a system default encoding is used.
*
* @param file The file from which you want to read.
* @throws IOException If an error occurs when checking for/reading the
* BOM.
* @throws FileNotFoundException If the file does not exist, is a
* directory, or cannot be opened for reading.
* @throws SecurityException If a security manager exists and its
* checkRead method denies read access to the file.
*/
public UnicodeReader(File file) throws IOException, FileNotFoundException,
SecurityException {
this(new FileInputStream(file));
}
/**
* This utility constructor is here because you will usually use a
* UnicodeReader
on files.
* Creates a reader using the encoding specified by the BOM in the file;
* if there is no recognized BOM, then a specified default encoding is
* used.
*
* @param file The file from which you want to read.
* @param defaultEncoding The encoding to use if no BOM is found. If
* this value is null
, a system default is used.
* @throws IOException If an error occurs when checking for/reading the
* BOM.
* @throws FileNotFoundException If the file does not exist, is a
* directory, or cannot be opened for reading.
* @throws SecurityException If a security manager exists and its
* checkRead method denies read access to the file.
*/
public UnicodeReader(File file, String defaultEncoding)
throws IOException, FileNotFoundException,
SecurityException {
this(new FileInputStream(file), defaultEncoding);
}
/**
* Creates a reader using the encoding specified by the BOM in the file;
* if there is no recognized BOM, then a system default encoding is used.
*
* @param in The input stream from which to read.
* @throws IOException If an error occurs when checking for/reading the
* BOM.
*/
public UnicodeReader(InputStream in) throws IOException {
this(in, null);
}
/**
* Creates a reader using the encoding specified by the BOM in the file;
* if there is no recognized BOM, then defaultEncoding
is
* used.
*
* @param in The input stream from which to read.
* @param defaultEncoding The encoding to use if no recognized BOM is
* found. If this value is null
, a system default
* is used.
* @throws IOException If an error occurs when checking for/reading the
* BOM.
*/
public UnicodeReader(InputStream in, String defaultEncoding)
throws IOException {
init(in, defaultEncoding);
}
/**
* Closes this reader.
*/
@Override
public void close() throws IOException {
internalIn.close();
}
/**
* Returns the encoding being used to read this input stream (i.e., the
* encoding of the file). If a BOM was recognized, then the specific
* Unicode type is returned; otherwise, either the default encoding passed
* into the constructor or the system default is returned.
*
* @return The encoding of the stream.
*/
public String getEncoding() {
return encoding;
}
/**
* Read-ahead four bytes and check for BOM marks. Extra bytes are
* unread back to the stream, only BOM bytes are skipped.
*
* @param defaultEncoding The encoding to use if no BOM was recognized. If
* this value is null
, then a system default is used.
* @throws IOException If an error occurs when trying to read a BOM.
*/
protected void init(InputStream in, String defaultEncoding)
throws IOException {
PushbackInputStream tempIn = new PushbackInputStream(in, BOM_SIZE);
byte bom[] = new byte[BOM_SIZE];
int n, unread;
n = tempIn.read(bom, 0, bom.length);
if ((bom[0]==(byte)0x00) && (bom[1]==(byte)0x00) &&
(bom[2]==(byte)0xFE) && (bom[3]==(byte)0xFF)) {
encoding = "UTF-32BE";
unread = n - 4;
}
else if (n==BOM_SIZE && // Last 2 bytes are 0; could be an empty UTF-16
(bom[0]==(byte)0xFF) && (bom[1]==(byte)0xFE) &&
(bom[2]==(byte)0x00) && (bom[3]==(byte)0x00)) {
encoding = "UTF-32LE";
unread = n - 4;
}
else if ((bom[0]==(byte)0xEF) &&
(bom[1]==(byte)0xBB) &&
(bom[2]==(byte)0xBF)) {
encoding = "UTF-8";
unread = n - 3;
}
else if ((bom[0]==(byte)0xFE) && (bom[1] == (byte)0xFF)) {
encoding = "UTF-16BE";
unread = n - 2;
}
else if ((bom[0]==(byte)0xFF) && (bom[1]== (byte)0xFE)) {
encoding = "UTF-16LE";
unread = n - 2;
}
else {
// Unicode BOM mark not found, unread all bytes
encoding = defaultEncoding;
unread = n;
}
if (unread > 0)
tempIn.unread(bom, (n - unread), unread);
else if (unread < -1)
tempIn.unread(bom, 0, 0);
// Use given encoding
if (encoding == null) {
internalIn = new InputStreamReader(tempIn);
encoding = internalIn.getEncoding(); // Get the default.
}
else {
internalIn = new InputStreamReader(tempIn, encoding);
}
}
/**
* Read characters into a portion of an array. This method will block until
* some input is available, an I/O error occurs, or the end of the stream
* is reached.
*
* @param cbuf The buffer into which to read.
* @param off The offset at which to start storing characters.
* @param len The maximum number of characters to read.
*
* @return The number of characters read, or -1
if the end
* of the stream has been reached.
*/
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return internalIn.read(cbuf, off, len);
}
} rsyntaxtextarea-2.5.0.orig/src/org/fife/ui/ 0000755 0001750 0000144 00000000000 12200540536 017307 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/fife/ui/rsyntaxtextarea/ 0000755 0001750 0000144 00000000000 12206726410 022560 5 ustar ben users rsyntaxtextarea-2.5.0.orig/src/org/fife/ui/rsyntaxtextarea/TokenOrientedView.java 0000644 0001750 0000144 00000004535 12201172436 027035 0 ustar ben users /*
* 08/06/2004
*
* TokenOrientedView.java - An interface for the syntax-highlighting token-
* oriented views for token-oriented methods.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* An interface for the syntax-highlighting token oriented views for
* token-oriented methods. This way callers won't need to know what specific
* class a view is an instance of to access its tokens.
*
* Currently, this interface is only useful for obtaining token lists for
* "physical lines" (i.e., a word-wrapped view's logical lines may be
* represented as several physical lines, thus getting the "physical line" above
* a given position may prove complicated).
*
* @author Robert Futrell
* @version 0.1
*/
public interface TokenOrientedView {
/**
* Returns a token list for the physical line above the physical
* line containing the specified offset into the document. Note that for
* a plain (non-wrapped) view, this is simply the token list for the
* logical line above the line containing offset
, since lines
* are not wrapped. For a wrapped view, this may or may not be tokens from
* the same line.
*
* @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line
* before this one. If no physical line is above the one
* containing offset
, null
is returned.
*/
public Token getTokenListForPhysicalLineAbove(int offset);
/**
* Returns a token list for the physical line below the physical
* line containing the specified offset into the document. Note that for
* a plain (non-wrapped) view, this is simply the token list for the
* logical line below the line containing offset
, since lines
* are not wrapped. For a wrapped view, this may or may not be tokens from
* the same line.
*
* @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line
* after this one. If no physical line is after the one
* containing offset
, null
is returned.
*/
public Token getTokenListForPhysicalLineBelow(int offset);
} rsyntaxtextarea-2.5.0.orig/src/org/fife/ui/rsyntaxtextarea/WrappedSyntaxView.java 0000644 0001750 0000144 00000132146 12202002500 027055 0 ustar ben users /*
* 08/06/2004
*
* WrappedSyntaxView.java - Test implementation of WrappedSyntaxView that
* is also aware of RSyntaxTextArea's different fonts per token type.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import java.awt.*;
import javax.swing.text.*;
import javax.swing.text.Position.Bias;
import javax.swing.event.*;
import org.fife.ui.rsyntaxtextarea.TokenUtils.TokenSubList;
import org.fife.ui.rsyntaxtextarea.folding.Fold;
import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
import org.fife.ui.rtextarea.Gutter;
/**
* The view used by {@link RSyntaxTextArea} when word wrap is enabled.
*
* @author Robert Futrell
* @version 0.2
*/
public class WrappedSyntaxView extends BoxView implements TabExpander,
RSTAView {
boolean widthChanging;
int tabBase;
int tabSize;
/**
* This is reused to keep from allocating/deallocating.
*/
private Segment s, drawSeg;
/**
* Another variable initialized once to keep from allocating/deallocating.
*/
private Rectangle tempRect;
/**
* Cached for each paint() call so each drawView() call has access to it.
*/
private RSyntaxTextArea host;
private FontMetrics metrics;
private TokenImpl tempToken;
private TokenImpl lineCountTempToken;
// /**
// * The end-of-line marker.
// */
// private static final char[] eolMarker = { '.' };
/**
* The width of this view cannot be below this amount, as if the width
* is ever 0 (really a bug), we'll go into an infinite loop.
*/
private static final int MIN_WIDTH = 20;
/**
* Creates a new WrappedSyntaxView. Lines will be wrapped
* on character boundaries.
*
* @param elem the element underlying the view
*/
public WrappedSyntaxView(Element elem) {
super(elem, Y_AXIS);
tempToken = new TokenImpl();
s = new Segment();
drawSeg = new Segment();
tempRect = new Rectangle();
lineCountTempToken = new TokenImpl();
}
/**
* This is called by the nested wrapped line
* views to determine the break location. This can
* be reimplemented to alter the breaking behavior.
* It will either break at word or character boundaries
* depending upon the break argument given at
* construction.
*/
protected int calculateBreakPosition(int p0, Token tokenList, float x0) {
//System.err.println("------ beginning calculateBreakPosition() --------");
int p = p0;
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
float currentWidth = getWidth();
if (currentWidth==Integer.MAX_VALUE)
currentWidth = getPreferredSpan(X_AXIS);
// Make sure width>0; this is a huge hack to fix a bug where
// loading text into an RTextArea before it is visible if word wrap
// is enabled causes an infinite loop in calculateBreakPosition()
// because of the 0-width! We cannot simply check in setSize()
// because the width is set to 0 somewhere else too somehow...
currentWidth = Math.max(currentWidth, MIN_WIDTH);
Token t = tokenList;
while (t!=null && t.isPaintable()) {
// FIXME: Replace the code below with the commented-out line below. This will
// allow long tokens to be broken at embedded spaces (such as MLC's). But it
// currently throws BadLocationExceptions sometimes...
float tokenWidth = t.getWidth(textArea, this, x0);
if (tokenWidth>currentWidth) {
// If the current token alone is too long for this line,
// break at a character boundary.
if (p==p0) {
return t.getOffsetBeforeX(textArea, this, 0, currentWidth);
}
// Return the first non-whitespace char (i.e., don't start
// off the continuation of a wrapped line with whitespace).
return t.isWhitespace() ? p+t.length() : p;
//return getBreakLocation(t, fm, x0, currentWidth, this);
}
currentWidth -= tokenWidth;
x0 += tokenWidth;
p += t.length();
//System.err.println("*** *** *** token fit entirely (width==" + tokenWidth + "), adding " + t.textCount + " to p, now p==" + p);
t = t.getNextToken();
}
//System.err.println("... ... whole line fits; returning p==" + p);
//System.err.println("------ ending calculateBreakPosition() --------");
// return p;
return p + 1;
}
//private int getBreakLocation(Token t, FontMetrics fm, int x0, int x,
// TabExpander e) {
// Segment s = new Segment();
// s.array = t.text;
// s.offset = t.getTextOffset();
// s.count = t.textCount;
// return t.offset + Utilities.getBreakLocation(s, fm, x0, x, e, t.offset);
//}
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#changedUpdate
*/
@Override
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
updateChildren(e, a);
}
/**
* Sets the allocation rectangle for a given line's view, but sets the
* y value to the passed-in value. This should be used instead of
* {@link #childAllocation(int, Rectangle)} since it allows you to account
* for hidden lines in collapsed fold regions.
*
* @param line
* @param y
* @param alloc
*/
private void childAllocation2(int line, int y, Rectangle alloc) {
alloc.x += getOffset(X_AXIS, line);
alloc.y += y;
alloc.width = getSpan(X_AXIS, line);
alloc.height = getSpan(Y_AXIS, line);
// FIXME: This is required due to a bug that I can't track down. The
// top margin is being added twice somewhere in wrapped views, so we
// have to adjust for it here.
alloc.y -= host.getMargin().top;
}
/**
* Draws a single view (i.e., a line of text for a wrapped view),
* wrapping the text onto multiple lines if necessary.
*
* @param painter The painter to use to render tokens.
* @param g The graphics context in which to paint.
* @param r The rectangle in which to paint.
* @param view The View
to paint.
* @param fontHeight The height of the font being used.
* @param y The y-coordinate at which to begin painting.
*/
protected void drawView(TokenPainter painter, Graphics2D g, Rectangle r,
View view, int fontHeight, int y) {
float x = r.x;
LayeredHighlighter h = (LayeredHighlighter)host.getHighlighter();
RSyntaxDocument document = (RSyntaxDocument)getDocument();
Element map = getElement();
int p0 = view.getStartOffset();
int lineNumber = map.getElementIndex(p0);
int p1 = view.getEndOffset();// - 1;
setSegment(p0,p1-1, document, drawSeg);
//System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")");
int start = p0 - drawSeg.offset;
Token token = document.getTokenListForLine(lineNumber);
// If this line is an empty line, then the token list is simply a
// null token. In this case, the line highlight will be skipped in
// the loop below, so unfortunately we must manually do it here.
if (token!=null && token.getType()==Token.NULL) {
h.paintLayeredHighlights(g, p0,p1, r, host, this);
return;
}
// Loop through all tokens in this view and paint them!
while (token!=null && token.isPaintable()) {
int p = calculateBreakPosition(p0, token, x);
x = r.x;
h.paintLayeredHighlights(g, p0,p, r, host, this);
while (token!=null && token.isPaintable() && token.getEndOffset()-1
View to paint. * @param fontHeight The height of the font being used. * @param y The y-coordinate at which to begin painting. * @param selStart The start of the selection. * @param selEnd The end of the selection. */ protected void drawViewWithSelection(TokenPainter painter, Graphics2D g, Rectangle r, View view, int fontHeight, int y, int selStart, int selEnd) { float x = r.x; LayeredHighlighter h = (LayeredHighlighter)host.getHighlighter(); RSyntaxDocument document = (RSyntaxDocument)getDocument(); Element map = getElement(); int p0 = view.getStartOffset(); int lineNumber = map.getElementIndex(p0); int p1 = view.getEndOffset();// - 1; setSegment(p0,p1-1, document, drawSeg); //System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")"); int start = p0 - drawSeg.offset; Token token = document.getTokenListForLine(lineNumber); // If this line is an empty line, then the token list is simply a // null token. In this case, the line highlight will be skipped in // the loop below, so unfortunately we must manually do it here. if (token!=null && token.getType()==Token.NULL) { h.paintLayeredHighlights(g, p0,p1, r, host, this); return; } // Loop through all tokens in this view and paint them! while (token!=null && token.isPaintable()) { int p = calculateBreakPosition(p0, token, x); x = r.x; h.paintLayeredHighlights(g, p0,p, r, host, this); while (token!=null && token.isPaintable() && token.getEndOffset()-1
token.getOffset()) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.getOffset(); x = painter.paint(tempToken,g,x,y,host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selStart); // Clone required since token and tempToken must be // different tokens for else statement below token = new TokenImpl(tempToken); } int selCount = Math.min(token.length(), selEnd-token.getOffset()); if (selCount==token.length()) { x = painter.paintSelected(token, g, x,y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x,y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(token.getOffset() + selCount); token = tempToken; x = painter.paint(token, g, x,y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.getOffset(); x = painter.paintSelected(tempToken, g, x,y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selEnd); token = tempToken; x = painter.paint(token, g, x,y, host, this); } // This token is entirely selected else if (token.getOffset()>=selStart && token.getEndOffset()<=selEnd) { x = painter.paintSelected(token, g, x,y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x,y, host, this); } token = token.getNextToken(); } // If there's a token that's going to be split onto the next line if (token!=null && token.isPaintable() && token.getOffset()
token.getOffset()) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.getOffset(); x = painter.paint(tempToken,g,x,y,host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selStart); // Clone required since token and tempToken must be // different tokens for else statement below token = new TokenImpl(tempToken); } int selCount = Math.min(token.length(), selEnd-token.getOffset()); if (selCount==token.length()) { x = painter.paintSelected(token, g, x,y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x,y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(token.getOffset() + selCount); token = tempToken; x = painter.paint(token, g, x,y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.getOffset(); x = painter.paintSelected(tempToken, g, x,y, host, this); tempToken.textCount = token.length(); tempToken.makeStartAt(selEnd); token = tempToken; x = painter.paint(token, g, x,y, host, this); } // This token is entirely selected else if (token.getOffset()>=selStart && token.getEndOffset()<=selEnd) { x = painter.paintSelected(token, g, x,y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x,y, host, this); } token = new TokenImpl(orig); ((TokenImpl)token).makeStartAt(p); } p0 = (p==p0) ? p1 : p; y += fontHeight; } // End of while (token!=null && token.isPaintable()). // NOTE: We should re-use code from Token (paintBackground()) here, // but don't because I'm just too lazy. if (host.getEOLMarkersVisible()) { g.setColor(host.getForegroundForTokenType(Token.WHITESPACE)); g.setFont(host.getFontForTokenType(Token.WHITESPACE)); g.drawString("\u00B6", x, y-fontHeight); } } /** * Fetches the allocation for the given child view.
* Overridden to account for code folding.
*
* @param index The index of the child, >= 0 && < getViewCount().
* @param a The allocation to this view
* @return The allocation to the child; or null
if
* a
is null
; or null
if the
* layout is invalid
*/
@Override
public Shape getChildAllocation(int index, Shape a) {
if (a != null) {
Shape ca = getChildAllocationImpl(index, a);
if ((ca != null) && (!isAllocationValid())) {
// The child allocation may not have been set yet.
Rectangle r = (ca instanceof Rectangle) ? (Rectangle) ca : ca
.getBounds();
if ((r.width == 0) && (r.height == 0)) {
return null;
}
}
return ca;
}
return null;
}
/**
* Fetches the allocation for the given child view to render into.
* Overridden to account for lines hidden by collapsed folded regions.
*
* @param line The index of the child, >= 0 && < getViewCount()
* @param a The allocation to this view
* @return The allocation to the child
*/
public Shape getChildAllocationImpl(int line, Shape a) {
Rectangle alloc = getInsideAllocation(a);
host = (RSyntaxTextArea)getContainer();
FoldManager fm = host.getFoldManager();
int y = alloc.y;
// TODO: Make cached getOffset() calls for Y_AXIS valid even for
// folding, to speed this up!
for (int i=0; i
*
* This is implemented to subtract the width of the second character, as
* this view's p0) {
alloc = RSyntaxUtilities.getLineWidthUpTo(
textArea, s, p0, pos,
WrappedSyntaxView.this,
alloc, alloc.x);
}
//System.err.println("--- end modelToView ---");
return alloc;
}
p0 = (p == p0) ? p1 : p;
//System.err.println("... ... Incrementing y");
alloc.y += alloc.height;
}
throw new BadLocationException(null, pos);
}
/**
* Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param fx the X coordinate
* @param fy the Y coordinate
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point in the view
* @see View#viewToModel
*/
@Override
public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
// PENDING(prinz) implement bias properly
bias[0] = Position.Bias.Forward;
Rectangle alloc = (Rectangle) a;
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
int x = (int) fx;
int y = (int) fy;
if (y < alloc.y) {
// above the area covered by this icon, so the the position
// is assumed to be the start of the coverage for this view.
return getStartOffset();
}
else if (y > alloc.y + alloc.height) {
// below the area covered by this icon, so the the position
// is assumed to be the end of the coverage for this view.
return getEndOffset() - 1;
}
else {
// positioned within the coverage of this view vertically,
// so we figure out which line the point corresponds to.
// if the line is greater than the number of lines
// contained, then simply use the last line as it represents
// the last possible place we can position to.
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
alloc.height = textArea.getLineHeight();
int p1 = getEndOffset();
// Get the token list for this line so we don't have to keep
// recomputing it if this logical line spans multiple
// physical lines.
Element map = doc.getDefaultRootElement();
int p0 = getStartOffset();
int line = map.getElementIndex(p0);
Token tlist = doc.getTokenListForLine(line);
// Look at each physical line-chunk of this logical line.
while (p0modelToView
actually returns the width of the
* character instead of "1" or "0" like the View implementations in
* javax.swing.text
. Thus, if we don't override this method,
* the View
implementation will return one character's width
* too much for its consumers (implementations of
* javax.swing.text.Highlighter
).
*
* @param p0 the position of the first character (>=0)
* @param b0 The bias of the first character position, toward the previous
* character or the next character represented by the offset, in
* case the position is a boundary of two views; b0
* will have one of these values:
*
*
* @param p1 the position of the last character (>=0)
* @param b1 the bias for the second character position, defined
* one of the legal values shown above
* @param a the area of the view, which encompasses the requested region
* @return the bounding box which is a union of the region specified
* by the first and last character positions
* @exception BadLocationException if the given position does
* not represent a valid location in the associated document
* @exception IllegalArgumentException if Position.Bias.Forward
* Position.Bias.Backward
* b0
or
* b1
are not one of the
* legal Position.Bias
values listed above
* @see View#viewToModel
*/
@Override
public Shape modelToView(int p0, Position.Bias b0,
int p1, Position.Bias b1,
Shape a) throws BadLocationException {
Shape s0 = modelToView(p0, a, b0);
Shape s1;
if (p1 ==getEndOffset()) {
try {
s1 = modelToView(p1, a, b1);
} catch (BadLocationException ble) {
s1 = null;
}
if (s1 == null) {
// Assume extends left to right.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
a.getBounds();
s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
1, alloc.height);
}
}
else {
s1 = modelToView(p1, a, b1);
}
Rectangle r0 = s0.getBounds();
Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 :
s1.getBounds();
if (r0.y != r1.y) {
// If it spans lines, force it to be the width of the view.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
a.getBounds();
r0.x = alloc.x;
r0.width = alloc.width;
}
r0.add(r1);
// The next line is the only difference between this method and
// View's implementation. We're subtracting the width of the second
// character. This is because this method is used by Highlighter
// implementations to get the area to "highlight", and if we don't do
// this, one character too many is highlighted thanks to our
// modelToView() implementation returning the actual width of the
// character requested!
if (p1>p0) r0.width -= r1.width;
return r0;
}
/**
* Returns the next tab stop position after a given reference position.
* This implementation does not support things like centering so it
* ignores the tabOffset argument.
*
* @param x the current position >= 0
* @param tabOffset the position within the text stream
* that the tab occurred at >= 0.
* @return the tab stop, measured in points >= 0
*/
public float nextTabStop(float x, int tabOffset) {
if (tabSize == 0)
return x;
int ntabs = ((int) x - tabBase) / tabSize;
return tabBase + ((ntabs + 1) * tabSize);
}
/**
* Paints the word-wrapped text.
*
* @param g The graphics context in which to paint.
* @param a The shape (usually a rectangle) in which to paint.
*/
@Override
public void paint(Graphics g, Shape a) {
Rectangle alloc = (a instanceof Rectangle) ?
(Rectangle)a : a.getBounds();
tabBase = alloc.x;
Graphics2D g2d = (Graphics2D)g;
host = (RSyntaxTextArea)getContainer();
int ascent = host.getMaxAscent();
int fontHeight = host.getLineHeight();
FoldManager fm = host.getFoldManager();
TokenPainter painter = host.getTokenPainter();
Element root = getElement();
// Whether token styles should always be painted, even in selections
int selStart = host.getSelectionStart();
int selEnd = host.getSelectionEnd();
boolean useSelectedTextColor = host.getUseSelectedTextColor();
int n = getViewCount(); // Number of lines.
int x = alloc.x + getLeftInset();
tempRect.y = alloc.y + getTopInset();
Rectangle clip = g.getClipBounds();
for (int i = 0; i < n; i++) {
tempRect.x = x + getOffset(X_AXIS, i);
//tempRect.y = y + getOffset(Y_AXIS, i);
tempRect.width = getSpan(X_AXIS, i);
tempRect.height = getSpan(Y_AXIS, i);
//System.err.println("For line " + i + ": tempRect==" + tempRect);
if (tempRect.intersects(clip)) {
Element lineElement = root.getElement(i);
int startOffset = lineElement.getStartOffset();
int endOffset = lineElement.getEndOffset()-1; // Why always "-1"?
View view = getView(i);
if (!useSelectedTextColor || selStart==selEnd ||
(startOffset>=selEnd || endOffset