This commit is contained in:
Deathmarine 2014-01-23 01:24:15 -05:00
parent 95ea527811
commit 9fcd1e4b6a
267 changed files with 213 additions and 151914 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/bin
/target

18
Assembly.xml Normal file
View File

@ -0,0 +1,18 @@
<assembly>
<id>${project.version}</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
</fileSet>
</fileSets>
</assembly>

100
build.xml
View File

@ -1,100 +0,0 @@
<project name="Luyten" default="package">
<property environment="env" />
<property name="env.BUILD_NUMBER" value="0" />
<property name="debuglevel" value="source,lines,vars" />
<property name="target" value="1.6" />
<property name="source" value="1.6" />
<property name="launch4j.dir" location="../../../launch4j" />
<path id="Model.classpath">
<pathelement location="bin" />
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="launch4j"
classname="net.sf.launch4j.ant.Launch4jTask"
classpath="${launch4j.dir}/launch4j.jar
:${launch4j.dir}/lib/xstream.jar" />
<target name="init" description="Initialize directories, etc.">
<mkdir dir="bin" />
<mkdir dir="dist" />
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java" />
</fileset>
</copy>
</target>
<target name="clean" depends="init"
description="Clean up all the temp stuff and previous builds">
<delete>
<fileset dir="bin" />
<fileset dir="dist" />
</delete>
</target>
<echo message="${ant.project.name}: ${ant.file}" />
<target name="compile" depends="clean, init" description="Compile all the code">
<replace file="src/com/modcrafting/luyten/Model.java" token="JENKINSBUILDNUMBER" value="${env.BUILD_NUMBER}"/>
<javac debug="true" debuglevel="${debuglevel}" destdir="bin"
includeantruntime="false" source="${source}" target="${target}">
<src path="src" />
<classpath refid="Model.classpath" />
<compilerarg value="-Xlint:none" />
</javac>
</target>
<target name="package" depends="compile" description="Make the distributable jar file">
<copy includeemptydirs="false" todir="bin/resources">
<fileset dir="src/resources" includes="*.png" />
</copy>
<copy includeemptydirs="false" todir="bin/themes">
<fileset dir="src/themes" includes="*.xml" />
</copy>
<copy includeemptydirs="false" todir="bin">
<fileset dir="src" includes="theme.dtd" />
</copy>
<copy includeemptydirs="false" todir="bin/org/fife/ui/rsyntaxtextarea">
<fileset dir="src/org/fife/ui/rsyntaxtextarea" includes="*.properties" />
</copy>
<copy includeemptydirs="false"
todir="bin/org/fife/ui/rsyntaxtextarea/focusabletip">
<fileset dir="src/org/fife/ui/rsyntaxtextarea/focusabletip"
includes="*.properties" />
</copy>
<copy includeemptydirs="false"
todir="bin/org/fife/ui/rsyntaxtextarea/focusabletip">
<fileset dir="src/org/fife/ui/rsyntaxtextarea/focusabletip"
includes="*.png" />
</copy>
<copy includeemptydirs="false" todir="bin/org/fife/ui/rsyntaxtextarea/modes">
<fileset dir="src/org/fife/ui/rsyntaxtextarea/modes"
includes="*.flex" />
</copy>
<copy includeemptydirs="false" todir="bin/org/fife/ui/rtextarea">
<fileset dir="src/org/fife/ui/rtextarea" includes="*.properties" />
</copy>
<copy includeemptydirs="false" todir="bin/distfiles">
<fileset dir="distfiles" includes="*.txt" />
</copy>
<jar basedir="bin" jarfile="dist/temp.jar" defaultexcludes="true">
<manifest>
<attribute name="Main-Class" value="com.modcrafting.luyten.Model" />
</manifest>
</jar>
<zip destfile="dist/${ant.project.name}.jar">
<zipgroupfileset dir="lib"
includes="*.jar" />
<zipgroupfileset dir="dist" includes="temp.jar" />
</zip>
<delete file="dist/temp.jar" />
<launch4j configFile="./l4j.xml"/>
</target>
</project>

22
l4j.xml
View File

@ -1,22 +0,0 @@
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>.\dist\Luyten.jar</jar>
<outfile>.\dist\Luyten.exe</outfile>
<errTitle></errTitle>
<cmdLine></cmdLine>
<chdir></chdir>
<priority>normal</priority>
<downloadUrl>http://java.com/download</downloadUrl>
<supportUrl></supportUrl>
<customProcName>false</customProcName>
<stayAlive>false</stayAlive>
<manifest></manifest>
<icon>.\Luyten.ico</icon>
<jre>
<path></path>
<minVersion>1.6.0_0</minVersion>
<maxVersion>1.8.0_0</maxVersion>
<jdkPreference>preferJre</jdkPreference>
</jre>
</launch4jConfig>

Binary file not shown.

148
pom.xml Normal file
View File

@ -0,0 +1,148 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>us.deathmarine</groupId>
<artifactId>luyten</artifactId>
<version>0.4.1</version>
<dependencies>
<dependency>
<groupId>com.fifesoft</groupId>
<artifactId>rsyntaxtextarea</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-core</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-expressions</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-reflection</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-compilertools</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>http://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<build>
<sourceDirectory>src</sourceDirectory>
<finalName>${project.artifactId}-${project.version}-lib</finalName>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>Assembly.xml</descriptor>
</descriptors>
<finalName>${project.artifactId}</finalName>
<archive>
<manifest>
<mainClass>com.modcrafting.luyten.Model</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.bluestemsoftware.open.maven.plugin</groupId>
<artifactId>launch4j-plugin</artifactId>
<version>1.5.0.0</version>
<executions>
<execution>
<id>l4j-gui</id>
<phase>package</phase>
<goals>
<goal>launch4j</goal>
</goals>
<configuration>
<headerType>gui</headerType>
<outfile>target/${project.artifactId}-${project.version}.exe</outfile>
<jar>target/${project.artifactId}-${project.version}.jar</jar>
<errTitle>App Err</errTitle>
<classPath>
<mainClass>com.modcrafting.luyten.Model</mainClass>
</classPath>
<icon>Luyten.ico</icon>
<jre>
<minVersion>1.6.0</minVersion>
<maxVersion>1.8.0</maxVersion>
<initialHeapSize>128</initialHeapSize>
<maxHeapSize>1024</maxHeapSize>
</jre>
<versionInfo>
<fileVersion>0.${project.version}</fileVersion>
<txtFileVersion>0.${project.version}</txtFileVersion>
<fileDescription>Java Decompiler</fileDescription>
<copyright>2014</copyright>
<productVersion>0.${project.version}</productVersion>
<txtProductVersion>0.${project.version}</txtProductVersion>
<productName>${project.artifactId}</productName>
<internalName>${project.artifactId}</internalName>
<originalFilename>Luyten.exe</originalFilename>
</versionInfo>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -21,6 +21,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -34,13 +35,50 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.net.URI;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipOutputStream;
import javax.swing.*;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.DefaultEditorKit;
@ -52,6 +90,7 @@ import javax.swing.tree.TreeSelectionModel;
import com.strobel.assembler.metadata.*;
import com.strobel.core.VerifyArgument;
import com.strobel.decompiler.languages.Language;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;
@ -59,7 +98,6 @@ import org.fife.ui.rtextarea.RTextScrollPane;
import com.strobel.assembler.InputTypeLoader;
import com.strobel.core.StringUtilities;
import com.strobel.decompiler.DecompilationOptions;
import com.strobel.decompiler.DecompilerDriver;
import com.strobel.decompiler.DecompilerSettings;
import com.strobel.decompiler.PlainTextOutput;
import com.strobel.decompiler.languages.Languages;
@ -70,17 +108,7 @@ public class Model extends JFrame implements WindowListener {
final LuytenTypeLoader typeLoader = new LuytenTypeLoader();
final Map<String, Language> languageLookup = new HashMap<String, Language>();
//
// I'm caching this for performance reasons. There is a pretty substantial cost associated
// with loading types from the disk. If you cache the metadata, decompilation should be much
// faster after the first few classes.
//
// Ideally, this should be purged if the user elects to 'refresh' the view. It'll retain
// metadata for types it has already seen, so if the user replaces the classes/jars they're
// viewing and wants to see changes, a refresh feature that purges the MetadataSystem would
// be useful.
//
static File base;
MetadataSystem metadataSystem = new MetadataSystem(typeLoader);
JTree tree;
@ -105,7 +133,6 @@ public class Model extends JFrame implements WindowListener {
JLabel label;
HashSet<OpenFile> hmap = new HashSet<OpenFile>();
boolean open = false;
public static final String JENKINS_BUILD = "JENKINSBUILDNUMBER";
private ButtonGroup languagesGroup;
private State state;
@ -385,7 +412,7 @@ public class Model extends JFrame implements WindowListener {
@Override
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(null,
"Luyten Gui Build#" + JENKINS_BUILD + "\n" +
"Luyten Gui \n" +
"by Deathmarine\n\n" +
"Powered By\nProcyon\n" +
"(c) 2013 Mike Strobel\n\n" +
@ -411,17 +438,7 @@ public class Model extends JFrame implements WindowListener {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (args.length > 0) {
if (Arrays.asList(args).contains("--nogui")) {
List<String> list = new LinkedList<String>(Arrays.asList(args));
list.remove("--nogui");
DecompilerDriver.main(list.toArray(new String[]{}));
} else {
new Model(args[0]);
}
} else {
new Model();
}
new Model();
}
});
}
@ -509,7 +526,7 @@ public class Model extends JFrame implements WindowListener {
settings.setFlattenSwitchBlocks(flattenSwitchBlocks.isSelected());
settings.setForceExplicitImports(forceExplicitImports.isSelected());
settings.setShowSyntheticMembers(showSyntheticMembers.isSelected());
settings.setShowNestedTypes(showNestedTypes.isSelected());
settings.setExcludeNestedTypes(showNestedTypes.isSelected());
settings.setForceExplicitTypeArguments(forceExplicitTypes.isSelected());
settings.setRetainRedundantCasts(retainRedundantCasts.isSelected());
settings.setIncludeErrorDiagnostics(showDebugInfo.isSelected());
@ -1111,4 +1128,5 @@ public class Model extends JFrame implements WindowListener {
}
}
}
}

View File

@ -1,209 +0,0 @@
/*
* 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 <code>Reader</code> for <code>javax.swing.text.Document</code> 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...
*/
public void close() {
}
/**
* Marks the present position in the stream. Subsequent calls to
* <code>reset()</code> will reposition the stream to this point.
*
* @param readAheadLimit Ignored.
*/
public void mark(int readAheadLimit) {
mark = position;
}
/**
* Tells whether this reader supports the <code>mark</code> operation.
* This always returns <code>true</code> for <code>DocumentReader</code>.
*/
public boolean markSupported() {
return true;
}
/**
* Reads the single character at the current position in the document.
*/
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 <code>array.length</code> characters from the beginning
* of the document into <code>array</code>.
*
* @param array The array to read characters into.
* @return The number of characters read.
*/
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 <code>-1</code> if the
* end of the stream (document) has been reached.
*/
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. <code>DocumentReader</code> will
* always return true.
*
* @return <code>true</code> if the next read operation will
* return without blocking.
*/
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.
*/
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.
*/
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 <code>pos</code>
* 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());
}
}

View File

@ -1,268 +0,0 @@
/*
* 09/23/2004
*
* UnicodeReader.java - A reader for Unicode input streams that is capable of
* discerning which particular encoding is being used via the 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.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.io.Reader;
/**
* A reader capable of identifying Unicode streams by their BOMs. This class
* will recognize the following encodings:
* <ul>
* <li>UTF-8
* <li>UTF-16LE
* <li>UTF-16BE
* <li>UTF-32LE
* <li>UTF-32BE
* </ul>
* If the stream is not found to be any of the above, then a default encoding
* is used for reading. The user can specify this default encoding, or a system
* default will be used.<p>
*
* For optimum performance, it is recommended that you wrap all instances of
* <code>UnicodeReader</code> with a <code>java.io.BufferedReader</code>.<p>
*
* 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 <code>java.io.InputStreamReader</code> 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
* <code>UnicodeReader</code> on files.<p>
* 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
* <code>UnicodeReader</code> on files.<p>
* 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
* <code>UnicodeReader</code> on files.<p>
* 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 <code>null</code>, 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 <code>defaultEncoding</code> 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 <code>null</code>, 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.
*/
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 <code>null</code>, 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 <code>-1</code> if the end
* of the stream has been reached.
*/
public int read(char[] cbuf, int off, int len) throws IOException {
return internalIn.read(cbuf, off, len);
}
}

View File

@ -1,253 +0,0 @@
/*
* 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 <code>OutputStreamWriter</code>.
* This class is here because Java's <code>OutputStreamWriter</code> apparently
* doesn't believe in writing BOMs.
* <p>
*
* For optimum performance, it is recommended that you wrap all instances of
* <code>UnicodeWriter</code> with a <code>java.io.BufferedWriter</code>.
*
* @author Robert Futrell
* @version 0.7
*/
public class UnicodeWriter extends Writer {
/**
* If this system property evaluates to "<code>false</code>", 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.
*/
public void close() throws IOException {
internalOut.close();
}
/**
* Flushes the stream.
*
* @throws IOException If an IO exception occurs.
*/
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.
*/
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.
*/
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.
*/
public void write(String str, int off, int len) throws IOException {
internalOut.write(str, off, len);
}
}

View File

@ -1,530 +0,0 @@
/*
* 11/14/2003
*
* RPrintUtilities.java - A collection of static methods useful for printing
* text from Swing text components.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.print;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.Segment;
import javax.swing.text.JTextComponent;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.print.*;
/**
* A collection of static methods useful for printing text from Swing text components.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class RPrintUtilities {
private static int currentDocLineNumber; // The line number in the document we are currently on.
private static int numDocLines; // The number of lines in the current document.
private static Element rootElement; // The first Element (line) in the current document.
// The characters at which to break a line if implementing word wrap.
private static final char [] breakChars = { ' ', '\t', ',', '.', ';', '?', '!' };
// These variables are 'global' because RPrintTabExpander uses them.
private static int xOffset; // The x-offset (for the page margin) when printing.
private static int tabSizeInSpaces; // The length of a tab, in spaces.
private static FontMetrics fm; // The metrics of the font currently being used to print.
/**
* Returns the position closest to, but before, position <code>maxCharsPerLine</code> in
* <code>line</code> of one of the chars in <code>breakChars</code>, or simply returns
* <code>maxCharsPerLine-1</code> if none of the <code>breakChars</code> comes before
* that position. This position represents the logical line break for this <code>java.lang.String</code>
* if it is being printed in a monospaced font when lines can only be <code>maxCharsPerLine</code>
* characters long.
*
* @param line The text being printed.
* @param maxCharsPerLine Only up-to this many characters from
* <code>line</code> can be printed on one line.
* @return The logical position at which to stop printing <code>line</code>
* to simulate word wrap.
*/
private static int getLineBreakPoint(String line, final int maxCharsPerLine) {
int breakPoint = -1;
for (int i=0; i<breakChars.length; i++) {
int breakCharPos = line.lastIndexOf(breakChars[i], maxCharsPerLine-1);
if (breakCharPos > breakPoint)
breakPoint = breakCharPos;
}
return (breakPoint==-1 ? maxCharsPerLine-1 : breakPoint);
}
/**
* Prints a <code>Document</code> using a monospaced font, and does no word wrapping (ie,
* words will wrap mid-word to the next line). This method is expected to be called from
* Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param doc The <code>javax.swing.text.Document</code> to print.
* @param fontSize the point size to use for the monospaced font.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to expand tabs to.
*
* @see #printDocumentMonospacedWordWrap
*/
public static int printDocumentMonospaced(Graphics g, Document doc, int fontSize, int pageIndex,
PageFormat pageFormat, int tabSize) {
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
// Create our tab expander.
//RPrintTabExpander tabExpander = new RPrintTabExpander();
// Get width and height of characters in this monospaced font.
int fontWidth = fm.charWidth('w'); // Any character will do as font is monospaced.
int fontHeight = fm.getHeight();
int MAX_CHARS_PER_LINE = (int)pageFormat.getImageableWidth() / fontWidth;
int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
rootElement = doc.getDefaultRootElement(); // To shorten accesses in our loop.
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
while (currentDocLineNumber<numDocLines) {
// Get the line we are going to print.
String curLineString;
Element currentLine = rootElement.getElement(currentDocLineNumber);
int startOffs = currentLine.getStartOffset();
try {
curLineString = doc.getText(startOffs, currentLine.getEndOffset()-startOffs);
} catch (BadLocationException ble) { // Never happens
ble.printStackTrace();
return Printable.NO_SUCH_PAGE;
}
// Get rid of newlines, because they end up as boxes if you don't; this is a monospaced font.
curLineString = curLineString.replaceAll("\n", "");
// Replace tabs with how many spaces they should be.
if (tabSizeInSpaces == 0) {
curLineString = curLineString.replaceAll("\t", "");
}
else {
int tabIndex = curLineString.indexOf('\t');
while (tabIndex > -1) {
int spacesNeeded = tabSizeInSpaces - (tabIndex % tabSizeInSpaces);
String replacementString = "";
for (int i=0; i<spacesNeeded; i++)
replacementString += ' ';
// Note that "\t" is actually a regex for this method.
curLineString = curLineString.replaceFirst("\t", replacementString);
tabIndex = curLineString.indexOf('\t');
}
}
// If this document line is too long to fit on one printed line on the page,
// break it up into multpile lines.
while (curLineString.length() > MAX_CHARS_PER_LINE) {
numPrintedLines++;
if (numPrintedLines > STARTING_LINE_NUMBER) {
g.drawString(curLineString.substring(0,MAX_CHARS_PER_LINE), xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
curLineString = curLineString.substring(MAX_CHARS_PER_LINE, curLineString.length());
}
currentDocLineNumber += 1; // We have printed one more line from the document.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
g.drawString(curLineString, xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Prints a <code>Document</code> using a monospaced font, word wrapping on
* the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
* expected to be called from Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param doc The <code>javax.swing.text.Document</code> to print.
* @param fontSize the point size to use for the monospaced font.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to expand tabs to.
*
* @see #printDocumentMonospaced
*/
public static int printDocumentMonospacedWordWrap(Graphics g, Document doc,
int fontSize, int pageIndex,
PageFormat pageFormat, int tabSize) {
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
// Create our tab expander.
//RPrintTabExpander tabExpander = new RPrintTabExpander();
// Get width and height of characters in this monospaced font.
int fontWidth = fm.charWidth('w'); // Any character will do here, since font is monospaced.
int fontHeight = fm.getHeight();
int MAX_CHARS_PER_LINE = (int)pageFormat.getImageableWidth() / fontWidth;
int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
rootElement = doc.getDefaultRootElement(); // To shorten accesses in our loop.
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
while (currentDocLineNumber<numDocLines) {
// Get the line we are going to print.
String curLineString;
Element currentLine = rootElement.getElement(currentDocLineNumber);
int startOffs = currentLine.getStartOffset();
try {
curLineString = doc.getText(startOffs, currentLine.getEndOffset()-startOffs);
} catch (BadLocationException ble) { // Never happens
ble.printStackTrace();
return Printable.NO_SUCH_PAGE;
}
// Remove newlines, because they end up as boxes if you don't; this is a monospaced font.
curLineString = curLineString.replaceAll("\n", "");
// Replace tabs with how many spaces they should be.
if (tabSizeInSpaces == 0) {
curLineString = curLineString.replaceAll("\t", "");
}
else {
int tabIndex = curLineString.indexOf('\t');
while (tabIndex > -1) {
int spacesNeeded = tabSizeInSpaces - (tabIndex % tabSizeInSpaces);
String replacementString = "";
for (int i=0; i<spacesNeeded; i++)
replacementString += ' ';
// Note that "\t" is actually a regex for this method.
curLineString = curLineString.replaceFirst("\t", replacementString);
tabIndex = curLineString.indexOf('\t');
}
}
// If this document line is too long to fit on one printed line on the page,
// break it up into multpile lines.
while (curLineString.length() > MAX_CHARS_PER_LINE) {
int breakPoint = getLineBreakPoint(curLineString, MAX_CHARS_PER_LINE) + 1;
numPrintedLines++;
if (numPrintedLines > STARTING_LINE_NUMBER) {
g.drawString(curLineString.substring(0,breakPoint), xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
curLineString = curLineString.substring(breakPoint, curLineString.length());
}
currentDocLineNumber += 1; // We have printed one more line from the document.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
g.drawString(curLineString, xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Prints a <code>Document</code> using the specified font, word wrapping
* on the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
* expected to be called from Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param textComponent The <code>javax.swing.text.JTextComponent</code>
* whose text you're printing.
* @param font The font to use for printing. If <code>null</code>, then
* <code>textComponent</code>'s font is used.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to convert tabs to.
*
*/
public static int printDocumentWordWrap(Graphics g, JTextComponent textComponent,
Font font, int pageIndex,
PageFormat pageFormat,
int tabSize) {
// Initialize our graphics object.
g.setColor(Color.BLACK);
g.setFont(font!=null ? font : textComponent.getFont());
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
int fontHeight = fm.getHeight();
final int LINE_LENGTH_IN_PIXELS = (int)pageFormat.getImageableWidth();
final int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// Create our tab expander.
RPrintTabExpander tabExpander = new RPrintTabExpander();
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
Document doc = textComponent.getDocument();
rootElement = doc.getDefaultRootElement();
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
int startingOffset = 0; // Used when a line is so long it has to be wrapped.
while (currentDocLineNumber<numDocLines) {
Segment currentLineSeg = new Segment();
// Get the current line (as an Element), and its starting and ending offset in doc.
Element currentLine = rootElement.getElement(currentDocLineNumber);
int currentLineStart = currentLine.getStartOffset();
int currentLineEnd = currentLine.getEndOffset();
// Put the chars of this line in currentLineSeg, but only starting at our desired offset
// (because this line may be the second part of a wrapped line, so we'd start after the part
// that has already been printed).
try {
doc.getText(currentLineStart+startingOffset, currentLineEnd-(currentLineStart+startingOffset),
currentLineSeg);
} catch (BadLocationException ble) {
System.err.println("BadLocationException in print (where there shouldn't be one!): " + ble);
return Printable.NO_SUCH_PAGE;
}
// Remove any spaces and/or tabs from the end of the segment (would cause problems if you left 'em).
currentLineSeg = removeEndingWhitespace(currentLineSeg);
// Figger out how long the line is, in pixels.
int currentLineLengthInPixels = Utilities.getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
//System.err.println("'" + currentLineSeg + "' - " + currentLineLengthInPixels + "/" + LINE_LENGTH_IN_PIXELS);
// If it'll fit by itself on a printed line, great.
if (currentLineLengthInPixels <= LINE_LENGTH_IN_PIXELS) {
currentDocLineNumber += 1; // We (will) have printed one more line from the document.
startingOffset = 0; // Start at the first character in the new document line.
}
// If it won't fit on a printed line by itself (i.e., it needs to be wrapped)...
else {
// Loop while the current line is too long to fit on a printed line.
int currentPos = -1;
while (currentLineLengthInPixels > LINE_LENGTH_IN_PIXELS) {
//System.err.println("'" + currentLineSeg + "' - " + currentLineLengthInPixels + "/" + LINE_LENGTH_IN_PIXELS);
// Remove any spaces and/or tabs from the end of the segment (would cause problems if you left 'em).
currentLineSeg = removeEndingWhitespace(currentLineSeg);
// currentPos will be the last position in the current text of a "line break character."
currentPos = -1;
String currentLineString = currentLineSeg.toString();
for (int i=0; i<breakChars.length; i++) {
// "+1" below so we include the character on the line.
int pos = currentLineString.lastIndexOf(breakChars[i]) + 1;
//if (pos>-1 && pos>currentPos)
// currentPos = pos;
if (pos>0 && pos>currentPos & pos!=currentLineString.length())
currentPos = pos;
}
// If we didn't find a line break character, we'll simply break the line at
// the last character that fits on a printed line.
// So here, we set currentPos to be the position of the last character that fits
// on the current printed line.
if (currentPos == -1) {
// Fix currentLineSeg so that it contains exactly enough text to fit in
// LINE_LENGTH_IN_PIXELS pixels...
currentPos = 0;
do {
currentPos++;
try {
doc.getText(currentLineStart+startingOffset, currentPos, currentLineSeg);
} catch (BadLocationException ble) {
System.err.println(ble);
return Printable.NO_SUCH_PAGE;
}
currentLineLengthInPixels = Utilities.
getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
} while (currentLineLengthInPixels <= LINE_LENGTH_IN_PIXELS);
currentPos--;
}
try {
doc.getText((currentLineStart+startingOffset), currentPos, currentLineSeg);
} catch (BadLocationException ble) {
System.err.println("BadLocationException in print (a):");
System.err.println("==> currentLineStart: " + currentLineStart +
"; startingOffset: " + startingOffset + "; currentPos: " + currentPos);
System.err.println("==> Range: " + (currentLineStart+startingOffset) + " - " +
(currentLineStart+startingOffset+currentPos));
ble.printStackTrace();
return Printable.NO_SUCH_PAGE;
}
currentLineLengthInPixels = Utilities.getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
} // End of while (currentLineLengthInPixels > LINE_LENGTH_IN_PIXELS).
startingOffset += currentPos; // Where to start (offset from line's start), since this line wraps.
} // End of else.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
//g.drawString(currentLineSeg.toString(), xOffset,y);
Utilities.drawTabbedText(currentLineSeg, xOffset,y, g, tabExpander, 0);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Removes any spaces or tabs from the end of the segment.
*
* @param segment The segment from which to remove tailing whitespace.
* @return <code>segment</code> with trailing whitespace removed.
*/
private static Segment removeEndingWhitespace(Segment segment) {
int toTrim = 0;
char currentChar = segment.setIndex(segment.getEndIndex()-1);
while ((currentChar==' ' || currentChar=='\t') && currentChar!=Segment.DONE) {
toTrim++;
currentChar = segment.previous();
}
String stringVal = segment.toString();
String newStringVal = stringVal.substring(0,stringVal.length()-toTrim);
return new Segment(newStringVal.toCharArray(), 0, newStringVal.length());
}
/**
* A tab expander for the document currently being printed with the
* font being used for the printing.
*/
private static class RPrintTabExpander implements TabExpander {
RPrintTabExpander() {
}
public float nextTabStop(float x, int tabOffset) {
if (tabSizeInSpaces == 0)
return x;
int tabSizeInPixels = tabSizeInSpaces * fm.charWidth(' ');
int ntabs = (((int) x) - xOffset) / tabSizeInPixels;
return xOffset + ((ntabs + 1) * tabSizeInPixels);
}
}
}

View File

@ -1,219 +0,0 @@
/*
* 01/25/2009
*
* AbstractJFlexCTokenMaker.java - Base class for token makers that use curly
* braces to denote code blocks, such as C, C++, Java, Perl, etc.
*
* 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.event.ActionEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Action;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import org.fife.ui.rtextarea.RTextArea;
/**
* Base class for JFlex-based token makers using C-style syntax. This class
* knows how to auto-indent after opening braces and parens.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
protected static final Action INSERT_BREAK_ACTION = new InsertBreakAction();
/**
* Returns <code>true</code> always as C-style languages use curly braces
* to denote code blocks.
*
* @return <code>true</code> always.
*/
public boolean getCurlyBracesDenoteCodeBlocks() {
return true;
}
/**
* Returns an action to handle "insert break" key presses (i.e. Enter).
* An action is returned that handles newlines differently in multi-line
* comments.
*
* @return The action.
*/
public Action getInsertBreakAction() {
return INSERT_BREAK_ACTION;
}
/**
* {@inheritDoc}
*/
public boolean getMarkOccurrencesOfTokenType(int type) {
return type==Token.IDENTIFIER || type==Token.FUNCTION;
}
/**
* {@inheritDoc}
*/
public boolean getShouldIndentNextLineAfter(Token t) {
if (t!=null && t.textCount==1) {
char ch = t.text[t.textOffset];
return ch=='{' || ch=='(';
}
return false;
}
/**
* Action that knows how to special-case inserting a newline in a
* multi-line comment for languages like C and Java.
*/
private static class InsertBreakAction extends
RSyntaxTextAreaEditorKit.InsertBreakAction {
private static final Pattern p =
Pattern.compile("([ \\t]*)(/?[\\*]+)([ \\t]*)");
public void actionPerformedImpl(ActionEvent e, RTextArea textArea) {
if (!textArea.isEditable() || !textArea.isEnabled()) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
return;
}
RSyntaxTextArea rsta = (RSyntaxTextArea)getTextComponent(e);
RSyntaxDocument doc = (RSyntaxDocument)rsta.getDocument();
int line = textArea.getCaretLineNumber();
int type = doc.getLastTokenTypeOnLine(line);
// Only in MLC's should we try this
if (type==Token.COMMENT_DOCUMENTATION ||
type==Token.COMMENT_MULTILINE) {
insertBreakInMLC(e, rsta, line);
}
else {
handleInsertBreak(rsta, true);
}
}
/**
* Returns whether the MLC token containing <code>offs</code> appears
* to have a "nested" comment (i.e., contains "<code>/*</code>"
* somewhere inside of it). This implies that it is likely a "new" MLC
* and needs to be closed. While not foolproof, this is usually good
* enough of a sign.
*
* @param textArea
* @param line
* @param offs
* @return Whether a comment appears to be nested inside this one.
*/
private boolean appearsNested(RSyntaxTextArea textArea,
int line, int offs) {
final int firstLine = line; // Remember the line we start at.
while (line<textArea.getLineCount()) {
Token t = textArea.getTokenListForLine(line);
int i = 0;
// If examining the first line, start at offs.
if (line++==firstLine) {
t = RSyntaxUtilities.getTokenAtOffset(t, offs);
if (t==null) { // offs was at end of the line
continue;
}
i = t.documentToToken(offs);
}
else {
i = t.textOffset;
}
while (i<t.textOffset+t.textCount-1) {
if (t.text[i]=='/' && t.text[i+1]=='*') {
return true;
}
i++;
}
// If tokens come after this one on this line, our MLC ended.
if (t.getNextToken()!=null) {
return false;
}
}
return true; // No match - MLC goes to the end of the file
}
private void insertBreakInMLC(ActionEvent e, RSyntaxTextArea textArea,
int line) {
Matcher m = null;
int start = -1;
int end = -1;
try {
start = textArea.getLineStartOffset(line);
end = textArea.getLineEndOffset(line);
String text = textArea.getText(start, end-start);
m = p.matcher(text);
} catch (BadLocationException ble) { // Never happens
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
ble.printStackTrace();
return;
}
if (m.lookingAt()) {
String leadingWS = m.group(1);
String mlcMarker = m.group(2);
// If the caret is "inside" any leading whitespace or MLC
// marker, move it to the end of the line.
int dot = textArea.getCaretPosition();
if (dot>=start &&
dot<start+leadingWS.length()+mlcMarker.length()) {
// If we're in the whitespace before the very start of the
// MLC though, just insert a normal newline
if (mlcMarker.charAt(0)=='/') {
handleInsertBreak(textArea, true);
return;
}
textArea.setCaretPosition(end-1);
}
boolean firstMlcLine = mlcMarker.charAt(0)=='/';
boolean nested = appearsNested(textArea, line,
start+leadingWS.length()+2);
String header = leadingWS +
(firstMlcLine ? " * " : "*") +
m.group(3);
textArea.replaceSelection("\n" + header);
if (nested) {
dot = textArea.getCaretPosition(); // Has changed
textArea.insert("\n" + leadingWS + " */", dot);
textArea.setCaretPosition(dot);
}
}
else {
handleInsertBreak(textArea, true);
}
}
}
}

View File

@ -1,52 +0,0 @@
/*
* 03/23/2005
*
* AbstractJFlexTokenMaker.java - Base class for token makers generated from
* programs such as JFlex.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.text.Segment;
/**
* Base class for JFlex-generated token makers. This class attempts to factor
* out all common code from these classes. Many methods <em>almost</em> could
* be factored out into this class, but cannot because they reference JFlex
* variables that we cannot access from this class.
*
* @author Robert Futrell
* @version 0.1
*/
public abstract class AbstractJFlexTokenMaker extends TokenMakerBase {
protected Segment s;
protected int start; // Just for states.
protected int offsetShift; // As parser always starts at 0, but our line doesn't.
/**
* Declared here so we can define overloads that refer to this method.
*
* @param newState The new JFlex state to enter.
*/
public abstract void yybegin(int newState);
/**
* Starts a new JFlex state and changes the current language index.
*
* @param state The new JFlex state to enter.
* @param languageIndex The new language index.
*/
protected void yybegin(int state, int languageIndex) {
yybegin(state);
setLanguageIndex(languageIndex);
}
}

View File

@ -1,67 +0,0 @@
/*
* 11/07/2004
*
* AbstractTokenMaker.java - An abstract implementation of TokenMaker.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* An abstract implementation of the
* {@link org.fife.ui.rsyntaxtextarea.TokenMaker} interface. It should
* be overridden for every language for which you want to provide
* syntax highlighting.<p>
*
* @see Token
*
* @author Robert Futrell
* @version 0.2
*/
public abstract class AbstractTokenMaker extends TokenMakerBase {
/**
* Hash table of words to highlight and what token type they are.
* The keys are the words to highlight, and their values are the
* token types, for example, <code>Token.RESERVED_WORD</code> or
* <code>Token.FUNCTION</code>.
*/
protected TokenMap wordsToHighlight;
/**
* Constructor.
*/
public AbstractTokenMaker() {
wordsToHighlight = getWordsToHighlight();
}
/**
* Returns the words to highlight for this programming language.
*
* @return A <code>TokenMap</code> containing the words to highlight for
* this programming language.
*/
public abstract TokenMap getWordsToHighlight();
/**
* Removes the token last added from the linked list of tokens. The
* programmer should never have to call this directly; it can be called
* by subclasses of <code>TokenMaker</code> if necessary.
*/
public void removeLastToken() {
if (previousToken==null) {
firstToken = currentToken = null;
}
else {
currentToken = previousToken;
currentToken.setNextToken(null);
}
}
}

View File

@ -1,132 +0,0 @@
/*
* 12/14/08
*
* AbstractTokenMakerFactory.java - Base class for TokenMaker implementations.
*
* 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.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Base class for {@link TokenMakerFactory} implementations. A mapping from
* language keys to the names of {@link TokenMaker} classes is stored.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
/**
* A mapping from keys to the names of {@link TokenMaker} implementation
* class names. When {@link #getTokenMaker(String)} is called with a key
* defined in this map, a <code>TokenMaker</code> of the corresponding type
* is returned.
*/
private Map tokenMakerMap;
/**
* Constructor.
*/
protected AbstractTokenMakerFactory() {
tokenMakerMap = new HashMap();
initTokenMakerMap();
}
/**
* Returns a {@link TokenMaker} for the specified key.
*
* @param key The key.
* @return The corresponding <code>TokenMaker</code>, or <code>null</code>
* if none matches the specified key.
*/
protected TokenMaker getTokenMakerImpl(String key) {
TokenMakerCreator tmc = (TokenMakerCreator)tokenMakerMap.get(key);
if (tmc!=null) {
try {
return tmc.create();
} catch (RuntimeException re) { // FindBugs
throw re;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* Populates the mapping from keys to instances of
* <code>TokenMakerCreator</code>s. Subclasses should override this method
* and call one of the <code>putMapping</code> overloads to register
* {@link TokenMaker}s for syntax constants.
*
* @see #putMapping(String, String)
* @see #putMapping(String, String, ClassLoader)
*/
protected abstract void initTokenMakerMap();
/**
* {@inheritDoc}
*/
public Set keySet() {
return tokenMakerMap.keySet();
}
/**
* Adds a mapping from a key to a <code>TokenMaker</code> implementation
* class name.
*
* @param key The key.
* @param className The <code>TokenMaker</code> class name.
* @see #putMapping(String, String, ClassLoader)
*/
public void putMapping(String key, String className) {
putMapping(key, className, null);
}
/**
* Adds a mapping from a key to a <code>TokenMaker</code> implementation
* class name.
*
* @param key The key.
* @param className The <code>TokenMaker</code> class name.
* @param cl The class loader to use when loading the class.
* @see #putMapping(String, String)
*/
public void putMapping(String key, String className, ClassLoader cl) {
tokenMakerMap.put(key, new TokenMakerCreator(className, cl));
}
/**
* Wrapper that handles the creation of TokenMaker instances.
*/
private static class TokenMakerCreator {
private String className;
private ClassLoader cl;
public TokenMakerCreator(String className, ClassLoader cl) {
this.className = className;
this.cl = cl!=null ? cl : getClass().getClassLoader();
}
public TokenMaker create() throws Exception {
return (TokenMaker)Class.forName(className, true, cl).newInstance();
}
}
}

View File

@ -1,68 +0,0 @@
/*
* 02/06/2011
*
* ActiveLineRangeEvent.java - Notifies listeners of an "active line range"
* change in an RSyntaxTextArea.
*
* 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.util.EventObject;
/**
* The event fired by {@link RSyntaxTextArea}s when the active line range
* changes.
*
* @author Robert Futrell
* @version 1.0
*/
public class ActiveLineRangeEvent extends EventObject {
private int min;
private int max;
/**
* Constructor.
*
* @param source The text area.
* @param min The first line in the active line range, or
* <code>-1</code> if the line range is being cleared.
* @param max The last line in the active line range, or
* <code>-1</code> if the line range is being cleared.
*/
public ActiveLineRangeEvent(RSyntaxTextArea source, int min, int max) {
super(source);
this.min = min;
this.max = max;
}
/**
* Returns the last line in the active line range.
*
* @return The last line, or <code>-1</code> if the range is being
* cleared.
* @see #getMin()
*/
public int getMax() {
return max;
}
/**
* Returns the first line in the active line range.
*
* @return The first line, or <code>-1</code> if the range is being
* cleared.
* @see #getMax()
*/
public int getMin() {
return min;
}
}

View File

@ -1,44 +0,0 @@
/*
* 02/06/2011
*
* ActiveLineRangeListener.java - Listens for "active line range" changes
* in an RSyntaxTextArea.
*
* 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.util.EventListener;
/**
* Listens for "active line range" events from an <code>RSyntaxTextArea</code>.
* If a text area contains some semantic knowledge of the programming language
* being edited, it may broadcast {@link ActiveLineRangeEvent}s whenever the
* caret moves into a new "block" of code. Listeners can listen for these
* events and respond accordingly.<p>
*
* See the <code>RSTALanguageSupport</code> project at
* <a href="http://fifesoft.com">http://fifesoft.com</a> for some
* <code>LanguageSupport</code> implementations that may broadcast these
* events. Note that if an RSTA/LanguageSupport does not support broadcasting
* these events, the listener will simply never receive any notifications.
*
* @author Robert Futrell
* @version 1.0
*/
public interface ActiveLineRangeListener extends EventListener {
/**
* Called whenever the "active line range" changes.
*
* @param e Information about the line range change. If there is no longer
* an "active line range," the "minimum" and "maximum" line values
* should both be <code>-1</code>.
*/
public void activeLineRangeChanged(ActiveLineRangeEvent e);
}

View File

@ -1,67 +0,0 @@
/*
* 07/23/2009
*
* ChangeableColorHighlightPainter.java - A highlighter whose color you can
* change.
*
* 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.Color;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
/**
* A highlighter whose color you can change.
*
* @author Robert Futrell
* @version 1.0
*/
class ChangeableColorHighlightPainter extends DefaultHighlightPainter {
/**
* DefaultHighlightPainter doesn't allow changing color, so we must cache
* ours here.
*/
private Color color;
/**
* Constructor.
*
* @param color The initial color to use. This cannot be <code>null</code>.
*/
public ChangeableColorHighlightPainter(Color color) {
super(color);
setColor(color);
}
/**
* Returns the color to paint with.
*
* @return The color.
* @see #setColor(Color)
*/
public Color getColor() {
return color;
}
/**
* Sets the color to paint the bounding boxes with.
*
* @param color The new color. This cannot be <code>null</code>.
* @see #getColor()
*/
public void setColor(Color color) {
if (color==null) {
throw new IllegalArgumentException("color cannot be null");
}
this.color = color;
}
}

View File

@ -1,470 +0,0 @@
/*
* 02/21/2005
*
* CodeTemplateManager.java - manages code templates.
*
* 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.event.InputEvent;
import java.awt.event.KeyEvent;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate;
/**
* Manages "code templates."<p>
*
* All methods in this class are synchronized for thread safety, but as a
* best practice, you should probably only modify the templates known to a
* <code>CodeTemplateManager</code> on the EDT. Modifying a
* <code>CodeTemplate</code> retrieved from a <code>CodeTemplateManager</code>
* while <em>not</em> on the EDT could cause problems.
*
* @author Robert Futrell
* @version 0.1
*/
public class CodeTemplateManager {
private int maxTemplateIDLength;
private List templates;
private KeyStroke insertTrigger;
private String insertTriggerString;
private Segment s;
private TemplateComparator comparator;
private File directory;
private static final int mask = InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK;
static final KeyStroke TEMPLATE_KEYSTROKE = KeyStroke.
getKeyStroke(KeyEvent.VK_SPACE, mask);
/**
* Constructor.
*/
public CodeTemplateManager() {
// Default insert trigger is a space.
// FIXME: See notes in RSyntaxTextAreaDefaultInputMap.
setInsertTrigger(TEMPLATE_KEYSTROKE);
s = new Segment();
comparator = new TemplateComparator();
templates = new ArrayList();
}
/**
* Registers the specified template with this template manager.
*
* @param template The template to register.
* @throws IllegalArgumentException If <code>template</code> is
* <code>null</code>.
* @see #removeTemplate(CodeTemplate)
* @see #removeTemplate(String)
*/
public synchronized void addTemplate(CodeTemplate template) {
if (template==null) {
throw new IllegalArgumentException("template cannot be null");
}
templates.add(template);
sortTemplates();
}
/**
* Returns the keystroke that is the "insert trigger" for templates;
* that is, the character that, when inserted into an instance of
* <code>RSyntaxTextArea</code>, triggers the search for
* a template matching the token ending at the caret position.
*
* @return The insert trigger.
* @see #getInsertTriggerString()
* @see #setInsertTrigger(KeyStroke)
*/
/*
* FIXME: This text IS what's inserted if the trigger character is pressed
* in a text area but no template matches, but it is NOT the trigger
* character used in the text areas. This is because space (" ") is
* hard-coded into RSyntaxTextAreaDefaultInputMap.java. We need to make
* this dynamic somehow. See RSyntaxTextAreaDefaultInputMap.java.
*/
public KeyStroke getInsertTrigger() {
return insertTrigger;
}
/**
* Returns the "insert trigger" for templates; that is, the character
* that, when inserted into an instance of <code>RSyntaxTextArea</code>,
* triggers the search for a template matching the token ending at the
* caret position.
*
* @return The insert trigger character.
* @see #getInsertTrigger()
* @see #setInsertTrigger(KeyStroke)
*/
/*
* FIXME: This text IS what's inserted if the trigger character is pressed
* in a text area but no template matches, but it is NOT the trigger
* character used in the text areas. This is because space (" ") is
* hard-coded into RSyntaxTextAreaDefaultInputMap.java. We need to make
* this dynamic somehow. See RSyntaxTextAreaDefaultInputMap.java.
*/
public String getInsertTriggerString() {
return insertTriggerString;
}
/**
* Returns the template that should be inserted at the current caret
* position, assuming the trigger character was pressed.
*
* @param textArea The text area that's getting text inserted into it.
* @return A template that should be inserted, if appropriate, or
* <code>null</code> if no template should be inserted.
*/
public synchronized CodeTemplate getTemplate(RSyntaxTextArea textArea) {
int caretPos = textArea.getCaretPosition();
int charsToGet = Math.min(caretPos, maxTemplateIDLength);
try {
Document doc = textArea.getDocument();
doc.getText(caretPos-charsToGet, charsToGet, s);
int index = Collections.binarySearch(templates, s, comparator);
return index>=0 ? (CodeTemplate)templates.get(index) : null;
} catch (BadLocationException ble) {
ble.printStackTrace();
throw new InternalError("Error in CodeTemplateManager");
}
}
/**
* Returns the number of templates this manager knows about.
*
* @return The template count.
*/
public synchronized int getTemplateCount() {
return templates.size();
}
/**
* Returns the templates currently available.
*
* @return The templates available.
*/
public synchronized CodeTemplate[] getTemplates() {
CodeTemplate[] temp = new CodeTemplate[templates.size()];
return (CodeTemplate[])templates.toArray(temp);
}
/**
* Returns whether the specified character is a valid character for a
* <code>CodeTemplate</code> id.
*
* @param ch The character to check.
* @return Whether the character is a valid template character.
*/
public static final boolean isValidChar(char ch) {
return RSyntaxUtilities.isLetterOrDigit(ch) || ch=='_';
}
/**
* Returns the specified code template.
*
* @param template The template to remove.
* @return <code>true</code> if the template was removed, <code>false</code>
* if the template was not in this template manager.
* @throws IllegalArgumentException If <code>template</code> is
* <code>null</code>.
* @see #removeTemplate(String)
* @see #addTemplate(CodeTemplate)
*/
public synchronized boolean removeTemplate(CodeTemplate template) {
if (template==null) {
throw new IllegalArgumentException("template cannot be null");
}
// TODO: Do a binary search
return templates.remove(template);
}
/**
* Returns the code template with the specified id.
*
* @param id The id to check for.
* @return The code template that was removed, or <code>null</code> if
* there was no template with the specified ID.
* @throws IllegalArgumentException If <code>id</code> is <code>null</code>.
* @see #removeTemplate(CodeTemplate)
* @see #addTemplate(CodeTemplate)
*/
public synchronized CodeTemplate removeTemplate(String id) {
if (id==null) {
throw new IllegalArgumentException("id cannot be null");
}
// TODO: Do a binary search
for (Iterator i=templates.iterator(); i.hasNext(); ) {
CodeTemplate template = (CodeTemplate)i.next();
if (id.equals(template.getID())) {
i.remove();
return template;
}
}
return null;
}
/**
* Replaces the current set of available templates with the ones
* specified.
*
* @param newTemplates The new set of templates. Note that we will
* be taking a shallow copy of these and sorting them.
*/
public synchronized void replaceTemplates(CodeTemplate[] newTemplates) {
templates.clear();
if (newTemplates!=null) {
for (int i=0; i<newTemplates.length; i++) {
templates.add(newTemplates[i]);
}
}
sortTemplates(); // Also recomputes maxTemplateIDLength.
}
/**
* Saves all templates as XML files in the current template directory.
*
* @return Whether or not the save was successful.
*/
public synchronized boolean saveTemplates() {
if (templates==null)
return true;
if (directory==null || !directory.isDirectory())
return false;
// Blow away all old XML files to start anew, as some might be from
// templates we're removed from the template manager.
File[] oldXMLFiles = directory.listFiles(new XMLFileFilter());
if (oldXMLFiles==null)
return false; // Either an IOException or it isn't a directory.
int count = oldXMLFiles.length;
for (int i=0; i<count; i++) {
/*boolean deleted = */oldXMLFiles[i].delete();
}
// Save all current templates as XML.
boolean wasSuccessful = true;
for (Iterator i=templates.iterator(); i.hasNext(); ) {
CodeTemplate template = (CodeTemplate)i.next();
File xmlFile = new File(directory, template.getID() + ".xml");
try {
XMLEncoder e = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream(xmlFile)));
e.writeObject(template);
e.close();
} catch (IOException ioe) {
ioe.printStackTrace();
wasSuccessful = false;
}
}
return wasSuccessful;
}
/**
* Sets the "trigger" character for templates.
*
* @param trigger The trigger character to set for templates. This means
* that when this character is pressed in an
* <code>RSyntaxTextArea</code>, the last-typed token is found,
* and is checked against all template ID's to see if a template
* should be inserted. If a template ID matches, that template is
* inserted; if not, the trigger character is inserted. If this
* parameter is <code>null</code>, no change is made to the trigger
* character.
* @see #getInsertTrigger()
* @see #getInsertTriggerString()
*/
/*
* FIXME: The trigger set here IS inserted when no matching template
* is found, but a space character (" ") is always used as the "trigger"
* to look for templates. This is because it is hard-coded in
* RSyntaxTextArea's input map this way. We need to change this.
* See RSyntaxTextAreaDefaultInputMap.java.
*/
public void setInsertTrigger(KeyStroke trigger) {
if (trigger!=null) {
insertTrigger = trigger;
insertTriggerString = Character.toString(trigger.getKeyChar());
}
}
/**
* Sets the directory in which to look for templates. Calling this
* method adds any new templates found in the specified directory to
* the templates already registered.
*
* @param dir The new directory in which to look for templates.
* @return The new number of templates in this template manager, or
* <code>-1</code> if the specified directory does not exist.
*/
public synchronized int setTemplateDirectory(File dir) {
if (dir!=null && dir.isDirectory()) {
this.directory = dir;
File[] files = dir.listFiles(new XMLFileFilter());
int newCount = files==null ? 0 : files.length;
int oldCount = templates.size();
List temp = new ArrayList(oldCount+newCount);
temp.addAll(templates);
for (int i=0; i<newCount; i++) {
try {
XMLDecoder d = new XMLDecoder(new BufferedInputStream(
new FileInputStream(files[i])));
Object obj = d.readObject();
if (!(obj instanceof CodeTemplate)) {
throw new IOException("Not a CodeTemplate: " +
files[i].getAbsolutePath());
}
temp.add(obj);
d.close();
} catch (/*IO, NoSuchElement*/Exception e) {
// NoSuchElementException can be thrown when reading
// an XML file not in the format expected by XMLDecoder.
// (e.g. CodeTemplates in an old format).
e.printStackTrace();
}
}
templates = temp;
sortTemplates();
return getTemplateCount();
}
return -1;
}
/**
* Removes any null entries in the current set of templates (if
* any), sorts the remaining templates, and computes the new
* maximum template ID length.
*/
private synchronized void sortTemplates() {
// Get the maximum length of a template ID.
maxTemplateIDLength = 0;
// Remove any null entries (should only happen because of
// IOExceptions, etc. when loading from files), and sort
// the remaining list.
for (Iterator i=templates.iterator(); i.hasNext(); ) {
CodeTemplate temp = (CodeTemplate)i.next();
if (temp==null || temp.getID()==null) {
i.remove();
}
else {
maxTemplateIDLength = Math.max(maxTemplateIDLength,
temp.getID().length());
}
}
Collections.sort(templates);
}
/**
* A comparator that takes a <code>CodeTemplate</code> as its first
* parameter and a <code>Segment</code> as its second, and knows
* to compare the template's ID to the segment's text.
*/
private static class TemplateComparator implements Comparator, Serializable{
public int compare(Object template, Object segment) {
// Get template start index (0) and length.
CodeTemplate t = (CodeTemplate)template;
final char[] templateArray = t.getID().toCharArray();
int i = 0;
int len1 = templateArray.length;
// Find "token" part of segment and get its offset and length.
Segment s = (Segment)segment;
char[] segArray = s.array;
int len2 = s.count;
int j = s.offset + len2 - 1;
while (j>=s.offset && isValidChar(segArray[j])) {
j--;
}
j++;
int segShift = j - s.offset;
len2 -= segShift;
int n = Math.min(len1, len2);
while (n-- != 0) {
char c1 = templateArray[i++];
char c2 = segArray[j++];
if (c1 != c2)
return c1 - c2;
}
return len1 - len2;
}
}
/**
* A file filter for File.listFiles() (NOT for JFileChoosers!) that
* accepts only XML files.
*/
private static class XMLFileFilter implements FileFilter {
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".xml");
}
}
}

View File

@ -1,379 +0,0 @@
/*
* 10/28/2004
*
* DefaultToken.java - The default token used in syntax highlighting.
*
* 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.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;
/**
* The default token used in the <code>org.fife.ui.rsyntaxtextarea</code> syntax
* package. This token type paints itself as you would expect, and properly
* accounts for rendering hints (anti-aliasing and fractional font metrics).<p>
*
* The current implementation paints as follows:
* <ul>
* <li>The first tab, if any, is found in the token.</li>
* <li>All characters up to that tab, if it exists, are painted as a
* group. If no tab was found, all characters in the token are
* painted.</li>
* <li>If a tab was found, its width is calculated and it is painted.</li>
* <li>Repeat until all characters are painted.</li>
* </ul>
* This method allows for rendering hints to be honored, since all possible
* characters are painted in a group. However, adjacent tokens will not have
* their "touching" characters rendered with rendering hints.<p>
*
* A problem with this implementation is that FontMetrics.charsWidth() is still
* used to calculate the width of a group of chars painted. Thus, the group of
* characters will be painted with the rendering hints specified, but the
* following tab (or group of characters if the current group was the end of a
* token) will not necessarily be painted at the proper x-coordinate (as
* FontMetrics.charsWidth() returns an <code>int</code> and not a
* <code>float</code>). The way around this would be to calculate the token's
* width in such a way that a float is returned (Font.getStringBounds()?).
*
* @author Robert Futrell
* @version 0.5
* @see Token
* @see VisibleWhitespaceToken
*/
public class DefaultToken extends Token {
/**
* Creates a "null token." The token itself is not null; rather, it
* signifies that it is the last token in a linked list of tokens and
* that it is not part of a "multi-line token."
*/
public DefaultToken() {
super();
}
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public DefaultToken(final Segment line, final int beg, final int end,
final int startOffset, final int type) {
this(line.array, beg,end, startOffset, type);
}
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public DefaultToken(final char[] line, final int beg, final int end,
final int startOffset, final int type) {
super(line, beg,end, startOffset, type);
}
/**
* Determines the offset into this token list (i.e., into the
* document) that covers pixel location <code>x</code> if the token list
* starts at pixel location <code>x0</code><p>.
* This method will return the document position "closest" to the
* x-coordinate (i.e., if they click on the "right-half" of the
* <code>w</code> in <code>awe</code>, the caret will be placed in
* between the <code>w</code> and <code>e</code>; similarly, clicking on
* the left-half places the caret between the <code>a</code> and
* <code>w</code>). This makes it useful for methods such as
* <code>viewToModel</code> found in <code>javax.swing.text.View</code>
* subclasses.
*
* @param textArea The text area from which the token list was derived.
* @param e How to expand tabs.
* @param x0 The pixel x-location that is the beginning of
* <code>tokenList</code>.
* @param x The pixel-position for which you want to get the corresponding
* offset.
* @return The position (in the document, NOT into the token list!) that
* covers the pixel location. If <code>tokenList</code> is
* <code>null</code> or has type <code>Token.NULL</code>, then
* <code>-1</code is returned; the caller should recognize this and
* return the actual end position of the (empty) line.
*/
public int getListOffset(RSyntaxTextArea textArea, TabExpander e,
float x0, float x) {
// If the coordinate in question is before this line's start, quit.
if (x0 >= x)
return offset;
float currX = x0; // x-coordinate of current char.
float nextX = x0; // x-coordinate of next char.
float stableX = x0; // Cached ending x-coord. of last tab or token.
Token token = this;
int last = offset;
FontMetrics fm = null;
while (token!=null && token.isPaintable()) {
fm = textArea.getFontMetricsForTokenType(token.type);
char[] text = token.text;
int start = token.textOffset;
int end = start + token.textCount;
for (int i=start; i<end; i++) {
currX = nextX;
if (text[i] == '\t') {
nextX = e.nextTabStop(nextX, 0);
stableX = nextX; // Cache ending x-coord. of tab.
start = i+1; // Do charsWidth() from next char.
}
else {
nextX = stableX + fm.charsWidth(text, start, i-start+1);
}
if (x>=currX && x<nextX) {
if ((x-currX) < (nextX-x)) {
return last + i-token.textOffset;
}
return last + i+1-token.textOffset;
}
}
stableX = nextX; // Cache ending x-coordinate of token.
last += token.textCount;
token = token.getNextToken();
}
// If we didn't find anything, return the end position of the text.
return last;
}
/**
* Returns the width of a specified number of characters in this token.
* For example, for the token "while", specifying a value of <code>3</code>
* here returns the width of the "whi" portion of the token.<p>
*
* @param numChars The number of characters for which to get the width.
* @param textArea The text area in which this token is being painted.
* @param e How to expand tabs. This value cannot be <code>null</code>.
* @param x0 The pixel-location at which this token begins. This is needed
* because of tabs.
* @return The width of the specified number of characters in this token.
* @see #getWidth
*/
public float getWidthUpTo(int numChars, RSyntaxTextArea textArea,
TabExpander e, float x0) {
float width = x0;
FontMetrics fm = textArea.getFontMetricsForTokenType(type);
if (fm!=null) {
int w;
int currentStart = textOffset;
int endBefore = textOffset + numChars;
for (int i=currentStart; i<endBefore; i++) {
if (text[i] == '\t') {
// Since TokenMaker implementations usually group all
// adjacent whitespace into a single token, there
// aren't usually any characters to compute a width
// for here, so we check before calling.
w = i-currentStart;
if (w>0)
width += fm.charsWidth(text, currentStart, w);
currentStart = i+1;
width = e.nextTabStop(width, 0);
}
}
// Most (non-whitespace) tokens will have characters at this
// point to get the widths for, so we don't check for w>0 (mini-
// optimization).
w = endBefore-currentStart;
width += fm.charsWidth(text, currentStart, w);
}
return width - x0;
}
/**
* Returns the bounding box for the specified document location. The
* location must be in the specified token list.
*
* @param textArea The text area from which the token list was derived.
* @param e How to expand tabs.
* @param pos The position in the document for which to get the bounding
* box in the view.
* @param x0 The pixel x-location that is the beginning of
* <code>tokenList</code>.
* @param rect The rectangle in which we'll be returning the results. This
* object is reused to keep from frequent memory allocations.
* @return The bounding box for the specified position in the model.
*/
public Rectangle listOffsetToView(RSyntaxTextArea textArea, TabExpander e,
int pos, int x0, Rectangle rect) {
int stableX = x0; // Cached ending x-coord. of last tab or token.
Token token = this;
FontMetrics fm = null;
Segment s = new Segment();
while (token!=null && token.isPaintable()) {
fm = textArea.getFontMetricsForTokenType(token.type);
if (fm==null) {
return rect; // Don't return null as things'll error.
}
char[] text = token.text;
int start = token.textOffset;
int end = start + token.textCount;
// If this token contains the position for which to get the
// bounding box...
if (token.containsPosition(pos)) {
s.array = token.text;
s.offset = token.textOffset;
s.count = pos-token.offset;
// Must use this (actually fm.charWidth()), and not
// fm.charsWidth() for returned value to match up with where
// text is actually painted on OS X!
int w = Utilities.getTabbedTextWidth(s, fm, stableX, e,
token.offset);
rect.x = stableX + w;
end = token.documentToToken(pos);
if (text[end]=='\t') {
rect.width = fm.charWidth(' ');
}
else {
rect.width = fm.charWidth(text[end]);
}
return rect;
}
// If this token does not contain the position for which to get
// the bounding box...
else {
s.array = token.text;
s.offset = token.textOffset;
s.count = token.textCount;
stableX += Utilities.getTabbedTextWidth(s, fm, stableX, e,
token.offset);
}
token = token.getNextToken();
}
// If we didn't find anything, we're at the end of the line. Return
// a width of 1 (so selection highlights don't extend way past line's
// text). A ConfigurableCaret will know to paint itself with a larger
// width.
rect.x = stableX;
rect.width = 1;
return rect;
}
/**
* Paints this token.
*
* @param g The graphics context in which to paint.
* @param x The x-coordinate at which to paint.
* @param y The y-coordinate at which to paint.
* @param host The text area this token is in.
* @param e How to expand tabs.
* @param clipStart The left boundary of the clip rectangle in which we're
* painting. This optimizes painting by allowing us to not paint
* when this token is "to the left" of the clip rectangle.
* @return The x-coordinate representing the end of the painted text.
*/
public float paint(Graphics2D g, float x, float y, RSyntaxTextArea host,
TabExpander e, float clipStart) {
int origX = (int)x;
int end = textOffset + textCount;
float nextX = x;
int flushLen = 0;
int flushIndex = textOffset;
Color fg = host.getForegroundForToken(this);
Color bg = host.getBackgroundForToken(this);
g.setFont(host.getFontForTokenType(type));
FontMetrics fm = host.getFontMetricsForTokenType(type);
for (int i=textOffset; i<end; i++) {
switch (text[i]) {
case '\t':
nextX = e.nextTabStop(
x+fm.charsWidth(text, flushIndex,flushLen), 0);
if (bg!=null) {
paintBackground(x,y, nextX-x,fm.getHeight(),
g, fm.getAscent(), host, bg);
}
if (flushLen > 0) {
g.setColor(fg);
g.drawChars(text, flushIndex, flushLen, (int)x,(int)y);
flushLen = 0;
}
flushIndex = i + 1;
x = nextX;
break;
default:
flushLen += 1;
break;
}
}
nextX = x+fm.charsWidth(text, flushIndex,flushLen);
if (flushLen>0 && nextX>=clipStart) {
if (bg!=null) {
paintBackground(x,y, nextX-x,fm.getHeight(),
g, fm.getAscent(), host, bg);
}
g.setColor(fg);
g.drawChars(text, flushIndex, flushLen, (int)x,(int)y);
}
if (host.getUnderlineForToken(this)) {
g.setColor(fg);
int y2 = (int)(y+1);
g.drawLine(origX,y2, (int)nextX,y2);
}
// Don't check if it's whitespace - some TokenMakers may return types
// other than Token.WHITESPACE for spaces (such as Token.IDENTIFIER).
// This also allows us to paint tab lines for MLC's.
if (host.getPaintTabLines() && origX==host.getMargin().left) {// && isWhitespace()) {
paintTabLines(origX, (int)y, (int)nextX, g, e, host);
}
return nextX;
}
}

View File

@ -1,167 +0,0 @@
/*
* 10/28/2004
*
* DefaultTokenFactory.java - Default token factory.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.text.Segment;
/**
* This class generates tokens for a {@link TokenMaker}. This class is here
* because it reuses tokens when they aren't needed anymore to prevent
* This class doesn't actually create new tokens every time
* <code>createToken</code> is called. Instead, it internally keeps a stack of
* available already-created tokens. When more tokens are needed to properly
* display a line, more tokens are added to the available stack. This saves
* from needless repetitive memory allocation. However, it makes it IMPERATIVE
* that users call <code>resetTokenList</code> when creating a new token list so
* that the token maker can keep an accurate list of available tokens.<p>
*
* NOTE: This class should only be used by {@link TokenMaker}; nobody else
* needs it!
*
* @author Robert Futrell
* @version 0.1
*/
class DefaultTokenFactory implements TokenFactory {
private int size;
private int increment;
private Token[] tokenList;
private int currentFreeToken;
protected static final int DEFAULT_START_SIZE = 30;
protected static final int DEFAULT_INCREMENT = 10;
/**
* Constructor.
*/
public DefaultTokenFactory() {
this(DEFAULT_START_SIZE, DEFAULT_INCREMENT);
}
/**
* Constructor.
*
* @param size The initial number of tokens in this factory.
* @param increment How many tokens to increment by when the stack gets
* empty.
*/
public DefaultTokenFactory(int size, int increment) {
this.size = size;
this.increment = increment;
this.currentFreeToken = 0;
// Give us some tokens to initially work with.
tokenList = new Token[size];
for (int i=0; i<size; i++)
tokenList[i] = createInternalUseOnlyToken();
}
/**
* Adds tokens to the internal token list. This is called whenever a
* request is made and no more tokens are available.
*/
private final void augmentTokenList() {
Token[] temp = new Token[size + increment];
System.arraycopy(tokenList,0, temp,0, size);
size += increment;
tokenList = temp;
for (int i=0; i<increment; i++) {
tokenList[size-i-1] = createInternalUseOnlyToken();
}
//System.err.println("... size up to: " + size);
}
/**
* Creates a token for use internally by this token factory. This method
* should NOT be called externally; only by this class and possibly
* subclasses.
*
* @return A token to add to this token factory's internal stack. If a
* subclass wants to produce a stack of a token other than
* {@link DefaultToken}, then this method can be overridden to
* return a new instance of the desired token type.
*/
protected Token createInternalUseOnlyToken() {
return new DefaultToken();
}
/**
* Returns a null token.
*
* @return A null token.
*/
public Token createToken() {
Token token = tokenList[currentFreeToken];
token.text = null;
token.type = Token.NULL;
token.offset = -1;
token.setNextToken(null);
currentFreeToken++;
if (currentFreeToken==size)
augmentTokenList();
return token;
}
/**
* Returns a token.
*
* @param line The segment from which to get the token's text.
* @param beg The starting offset of the token's text in the segment.
* @param end The ending offset of the token's text in the segment.
* @param startOffset The offset in the document of the token.
* @param type The type of token.
* @return The token.
*/
public Token createToken(final Segment line, final int beg,
final int end, final int startOffset, final int type) {
return createToken(line.array, beg,end, startOffset, type);
}
/**
* Returns a token.
*
* @param line The segment from which to get the token's text.
* @param beg The starting offset of the token's text in the segment.
* @param end The ending offset of the token's text in the segment.
* @param startOffset The offset in the document of the token.
* @param type The type of token.
* @return The token.
*/
public Token createToken(final char[] line, final int beg,
final int end, final int startOffset, final int type) {
Token token = tokenList[currentFreeToken];
token.set(line, beg,end, startOffset, type);
currentFreeToken++;
if (currentFreeToken==size)
augmentTokenList();
return token;
}
/**
* Resets the state of this token maker. This method should be called
* by the <code>TokenMaker</code> every time a token list is generated for
* a new line so the tokens can be reused.
*/
public void resetAllTokens() {
currentFreeToken = 0;
}
}

View File

@ -1,71 +0,0 @@
/*
* 12/14/2008
*
* DefaultTokenMakerFactory.java - The default TokenMaker factory.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* The default implementation of <code>TokenMakerFactory</code>. This factory
* can create {@link TokenMaker}s for all languages known to
* {@link RSyntaxTextArea}.
*
* @author Robert Futrell
* @version 1.0
*/
class DefaultTokenMakerFactory extends AbstractTokenMakerFactory
implements SyntaxConstants {
/**
* {@inheritDoc}
*/
protected void initTokenMakerMap() {
String pkg = "org.fife.ui.rsyntaxtextarea.modes.";
putMapping(SYNTAX_STYLE_NONE, pkg + "PlainTextTokenMaker");
putMapping(SYNTAX_STYLE_ACTIONSCRIPT, pkg + "ActionScriptTokenMaker");
putMapping(SYNTAX_STYLE_ASSEMBLER_X86, pkg + "AssemblerX86TokenMaker");
putMapping(SYNTAX_STYLE_BBCODE, pkg + "BBCodeTokenMaker");
putMapping(SYNTAX_STYLE_C, pkg + "CTokenMaker");
putMapping(SYNTAX_STYLE_CLOJURE, pkg + "ClojureTokenMaker");
putMapping(SYNTAX_STYLE_CPLUSPLUS, pkg + "CPlusPlusTokenMaker");
putMapping(SYNTAX_STYLE_CSHARP, pkg + "CSharpTokenMaker");
putMapping(SYNTAX_STYLE_CSS, pkg + "CSSTokenMaker");
putMapping(SYNTAX_STYLE_DELPHI, pkg + "DelphiTokenMaker");
putMapping(SYNTAX_STYLE_DTD, pkg + "DtdTokenMaker");
putMapping(SYNTAX_STYLE_FORTRAN, pkg + "FortranTokenMaker");
putMapping(SYNTAX_STYLE_GROOVY, pkg + "GroovyTokenMaker");
putMapping(SYNTAX_STYLE_HTML, pkg + "HTMLTokenMaker");
putMapping(SYNTAX_STYLE_JAVA, pkg + "JavaTokenMaker");
putMapping(SYNTAX_STYLE_JAVASCRIPT, pkg + "JavaScriptTokenMaker");
putMapping(SYNTAX_STYLE_JSON, pkg + "JsonTokenMaker");
putMapping(SYNTAX_STYLE_JSP, pkg + "JSPTokenMaker");
putMapping(SYNTAX_STYLE_LATEX, pkg + "LatexTokenMaker");
putMapping(SYNTAX_STYLE_LISP, pkg + "LispTokenMaker");
putMapping(SYNTAX_STYLE_LUA, pkg + "LuaTokenMaker");
putMapping(SYNTAX_STYLE_MAKEFILE, pkg + "MakefileTokenMaker");
putMapping(SYNTAX_STYLE_MXML, pkg + "MxmlTokenMaker");
putMapping(SYNTAX_STYLE_NSIS, pkg + "NSISTokenMaker");
putMapping(SYNTAX_STYLE_PERL, pkg + "PerlTokenMaker");
putMapping(SYNTAX_STYLE_PHP, pkg + "PHPTokenMaker");
putMapping(SYNTAX_STYLE_PROPERTIES_FILE,pkg + "PropertiesFileTokenMaker");
putMapping(SYNTAX_STYLE_PYTHON, pkg + "PythonTokenMaker");
putMapping(SYNTAX_STYLE_RUBY, pkg + "RubyTokenMaker");
putMapping(SYNTAX_STYLE_SAS, pkg + "SASTokenMaker");
putMapping(SYNTAX_STYLE_SCALA, pkg + "ScalaTokenMaker");
putMapping(SYNTAX_STYLE_SQL, pkg + "SQLTokenMaker");
putMapping(SYNTAX_STYLE_TCL, pkg + "TclTokenMaker");
putMapping(SYNTAX_STYLE_UNIX_SHELL, pkg + "UnixShellTokenMaker");
putMapping(SYNTAX_STYLE_WINDOWS_BATCH, pkg + "WindowsBatchTokenMaker");
putMapping(SYNTAX_STYLE_XML, pkg + "XMLTokenMaker");
}
}

View File

@ -1,62 +0,0 @@
/*
* 08/11/2009
*
* DocumentRange.java - A range of text in a document.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* A range of text in a document.
*
* @author Robert Futrell
* @version 1.0
*/
public class DocumentRange {
private int startOffs;
private int endOffs;
public DocumentRange(int startOffs, int endOffs) {
this.startOffs = startOffs;
this.endOffs = endOffs;
}
/**
* Gets the end offset of the range.
*
* @return The end offset.
* @see #getStartOffset()
*/
public int getEndOffset() {
return endOffs;
}
/**
* Gets the starting offset of the range.
*
* @return The starting offset.
* @see #getEndOffset()
*/
public int getStartOffset() {
return startOffs;
}
/**
* Returns a string representation of this object.
*
* @return A string representation of this object.
*/
public String toString() {
return "[DocumentRange: " + startOffs + "-" + endOffs + "]";
}
}

View File

@ -1,766 +0,0 @@
/*
* 08/10/2009
*
* ErrorStrip.java - A component that can visually show Parser messages (syntax
* errors, etc.) in an RSyntaxTextArea.
*
* 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.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.swing.JComponent;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import org.fife.ui.rsyntaxtextarea.parser.Parser;
import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
import org.fife.ui.rsyntaxtextarea.parser.TaskTagParser.TaskNotice;
/**
* A component to sit alongside an {@link RSyntaxTextArea} that displays
* colored markers for locations of interest (parser errors, marked
* occurrences, etc.).<p>
*
* <code>ErrorStrip</code>s display <code>ParserNotice</code>s from
* {@link Parser}s. Currently, the only way to get lines flagged in this
* component is to register a <code>Parser</code> on an RSyntaxTextArea and
* return <code>ParserNotice</code>s for each line to display an icon for.
* The severity of each notice must be at least the threshold set by
* {@link #setLevelThreshold(int)} to be displayed in this error strip. The
* default threshold is {@link ParserNotice#WARNING}.<p>
*
* An <code>ErrorStrip</code> can be added to a UI like so:
* <pre>
* textArea = createTextArea();
* textArea.addParser(new MyParser(textArea)); // Identifies lines to display
* scrollPane = new RTextScrollPane(textArea, true);
* ErrorStrip es = new ErrorStrip(textArea);
* JPanel temp = new JPanel(new BorderLayout());
* temp.add(scrollPane);
* temp.add(es, BorderLayout.LINE_END);
* </pre>
*
* @author Robert Futrell
* @version 0.5
*/
/*
* Possible improvements:
* 1. Handle marked occurrence changes separately from parser changes.
* For each property change, call a method that removes the notices
* being reloaded from the Markers (removing any Markers that are now
* "empty").
* 2. When 1.4 support is dropped, replace new Integer(int) with
* Integer.valueOf(int).
*/
public class ErrorStrip extends JComponent {
/**
* The text area.
*/
private RSyntaxTextArea textArea;
/**
* Listens for events in this component.
*/
private Listener listener;
/**
* Whether "marked occurrences" in the text area should be shown in this
* error strip.
*/
private boolean showMarkedOccurrences;
/**
* Mapping of colors to brighter colors. This is kept to prevent
* unnecessary creation of the same Colors over and over.
*/
private Map brighterColors;
/**
* Only notices of this severity (or worse) will be displayed in this
* error strip.
*/
private int levelThreshold;
/**
* Whether the caret marker's location should be rendered.
*/
private boolean followCaret;
/**
* The color to use for the caret marker.
*/
private Color caretMarkerColor;
/**
* Where we paint the caret marker.
*/
private int caretLineY;
/**
* The last location of the caret marker.
*/
private int lastLineY;
/**
* The preferred width of this component.
*/
private static final int PREFERRED_WIDTH = 14;
private static final String MSG = "org.fife.ui.rsyntaxtextarea.ErrorStrip";
private static final ResourceBundle msg = ResourceBundle.getBundle(MSG);
/**
* Constructor.
*
* @param textArea The text area we are examining.
*/
public ErrorStrip(RSyntaxTextArea textArea) {
this.textArea = textArea;
listener = new Listener();
ToolTipManager.sharedInstance().registerComponent(this);
setLayout(null); // Manually layout Markers as they can overlap
addMouseListener(listener);
setShowMarkedOccurrences(true);
setLevelThreshold(ParserNotice.WARNING);
setFollowCaret(true);
setCaretMarkerColor(Color.BLACK);
}
/**
* Overridden so we only start listening for parser notices when this
* component (and presumably the text area) are visible.
*/
public void addNotify() {
super.addNotify();
textArea.addCaretListener(listener);
textArea.addPropertyChangeListener(
RSyntaxTextArea.PARSER_NOTICES_PROPERTY, listener);
textArea.addPropertyChangeListener(
RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY, listener);
textArea.addPropertyChangeListener(
RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY, listener);
refreshMarkers();
}
/**
* Manually manages layout since this component uses no layout manager.
*/
public void doLayout() {
for (int i=0; i<getComponentCount(); i++) {
Marker m = (Marker)getComponent(i);
m.updateLocation();
}
listener.caretUpdate(null); // Force recalculation of caret line pos
}
/**
* Returns a "brighter" color.
*
* @param c The color.
* @return A brighter color.
*/
private Color getBrighterColor(Color c) {
if (brighterColors==null) {
brighterColors = new HashMap(5); // Usually small
}
Color brighter = (Color)brighterColors.get(c);
if (brighter==null) {
// Don't use c.brighter() as it doesn't work well for blue, and
// also doesn't return something brighter "enough."
int r = possiblyBrighter(c.getRed());
int g = possiblyBrighter(c.getGreen());
int b = possiblyBrighter(c.getBlue());
brighter = new Color(r, g, b);
brighterColors.put(c, brighter);
}
return brighter;
}
/**
* returns the color to use when painting the caret marker.
*
* @return The caret marker color.
* @see #setCaretMarkerColor(Color)
*/
public Color getCaretMarkerColor() {
return caretMarkerColor;
}
/**
* Returns whether the caret's position should be drawn.
*
* @return Whether the caret's position should be drawn.
* @see #setFollowCaret(boolean)
*/
public boolean getFollowCaret() {
return followCaret;
}
/**
* {@inheritDoc}
*/
public Dimension getPreferredSize() {
int height = textArea.getPreferredScrollableViewportSize().height;
return new Dimension(PREFERRED_WIDTH, height);
}
/**
* Returns the minimum severity a parser notice must be for it to be
* displayed in this error strip. This will be one of the constants
* defined in the <code>ParserNotice</code> class.
*
* @return The minimum severity.
* @see #setLevelThreshold(int)
*/
public int getLevelThreshold() {
return levelThreshold;
}
/**
* Returns whether marked occurrences are shown in this error strip.
*
* @return Whether marked occurrences are shown.
* @see #setShowMarkedOccurrences(boolean)
*/
public boolean getShowMarkedOccurrences() {
return showMarkedOccurrences;
}
/**
* {@inheritDoc}
*/
public String getToolTipText(MouseEvent e) {
String text = null;
int line = yToLine(e.getY());
if (line>-1) {
text = msg.getString("Line");
// TODO: 1.5: Use Integer.valueOf(line)
text = MessageFormat.format(text,
new Object[] { new Integer(line+1) });
}
return text;
}
/**
* Returns the y-offset in this component corresponding to a line in the
* text component.
*
* @param line The line.
* @return The y-offset.
* @see #yToLine(int)
*/
private int lineToY(int line) {
int h = textArea.getVisibleRect().height;
float lineCount = textArea.getLineCount();
return (int)((line/lineCount) * h) - 2;
}
/**
* Overridden to (possibly) draw the caret's position.
*
* @param g The graphics context.
*/
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (caretLineY>-1) {
g.setColor(getCaretMarkerColor());
g.fillRect(0, caretLineY, getWidth(), 2);
}
}
/**
* Returns a possibly brighter component for a color.
*
* @param i An RGB component for a color (0-255).
* @return A possibly brighter value for the component.
*/
private static final int possiblyBrighter(int i) {
if (i<255) {
i += (int)((255-i)*0.8f);
}
return i;
}
/**
* Refreshes the markers displayed in this error strip.
*/
private void refreshMarkers() {
removeAll(); // listener is removed in Marker.removeNotify()
Map markerMap = new HashMap();
List notices = textArea.getParserNotices();
for (Iterator i=notices.iterator(); i.hasNext(); ) {
ParserNotice notice = (ParserNotice)i.next();
if (notice.getLevel()<=levelThreshold ||
(notice instanceof TaskNotice)) {
// 1.5: Use Integer.valueOf(notice.getLine())
Integer key = new Integer(notice.getLine());
Marker m = (Marker)markerMap.get(key);
if (m==null) {
m = new Marker(notice);
m.addMouseListener(listener);
markerMap.put(key, m);
add(m);
}
else {
m.addNotice(notice);
}
}
}
if (getShowMarkedOccurrences() && textArea.getMarkOccurrences()) {
List occurrences = textArea.getMarkedOccurrences();
for (Iterator i=occurrences.iterator(); i.hasNext(); ) {
DocumentRange range = (DocumentRange)i.next();
int line = 0;
try {
line = textArea.getLineOfOffset(range.getStartOffset());
} catch (BadLocationException ble) { // Never happens
continue;
}
ParserNotice notice = new MarkedOccurrenceNotice(range);
// 1.5: Use Integer.valueOf(notice.getLine())
Integer key = new Integer(line);
Marker m = (Marker)markerMap.get(key);
if (m==null) {
m = new Marker(notice);
m.addMouseListener(listener);
markerMap.put(key, m);
add(m);
}
else {
if (!m.containsMarkedOccurence()) {
m.addNotice(notice);
}
}
}
}
revalidate();
repaint();
}
/**
* {@inheritDoc}
*/
public void removeNotify() {
super.removeNotify();
textArea.removeCaretListener(listener);
textArea.removePropertyChangeListener(
RSyntaxTextArea.PARSER_NOTICES_PROPERTY, listener);
textArea.removePropertyChangeListener(
RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY, listener);
textArea.removePropertyChangeListener(
RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY, listener);
}
/**
* Sets the color to use when painting the caret marker.
*
* @param color The new caret marker color.
* @see #getCaretMarkerColor()
*/
public void setCaretMarkerColor(Color color) {
if (color!=null) {
caretMarkerColor = color;
listener.caretUpdate(null); // Force repaint
}
}
/**
* Toggles whether the caret's current location should be drawn.
*
* @param follow Whether the caret's current location should be followed.
* @see #getFollowCaret()
*/
public void setFollowCaret(boolean follow) {
if (followCaret!=follow) {
if (followCaret) {
repaint(0,caretLineY, getWidth(),2); // Erase
}
caretLineY = -1;
lastLineY = -1;
followCaret = follow;
listener.caretUpdate(null); // Possibly repaint
}
}
/**
* Sets the minimum severity a parser notice must be for it to be displayed
* in this error strip. This should be one of the constants defined in
* the <code>ParserNotice</code> class. The default value is
* {@link ParserNotice#WARNING}.
*
* @param level The new severity threshold.
* @see #getLevelThreshold()
* @see ParserNotice
*/
public void setLevelThreshold(int level) {
levelThreshold = level;
if (isDisplayable()) {
refreshMarkers();
}
}
/**
* Sets whether marked occurrences are shown in this error strip.
*
* @param show Whether to show marked occurrences.
* @see #getShowMarkedOccurrences()
*/
public void setShowMarkedOccurrences(boolean show) {
if (show!=showMarkedOccurrences) {
showMarkedOccurrences = show;
if (isDisplayable()) { // Skip this when we're first created
refreshMarkers();
}
}
}
/**
* Returns the line in the text area corresponding to a y-offset in this
* component.
*
* @param y The y-offset.
* @return The line.
* @see #lineToY(int)
*/
private final int yToLine(int y) {
int line = -1;
int h = textArea.getVisibleRect().height;
if (y<h) {
float at = y/(float)h;
line = (int)(textArea.getLineCount()*at);
}
return line;
}
/**
* Listens for events in the error strip and its markers.
*/
private class Listener extends MouseAdapter
implements PropertyChangeListener, CaretListener {
private Rectangle visibleRect = new Rectangle();
public void caretUpdate(CaretEvent e) {
if (getFollowCaret()) {
int line = textArea.getCaretLineNumber();
float percent = line / ((float)textArea.getLineCount());
textArea.computeVisibleRect(visibleRect);
caretLineY = (int)(visibleRect.height*percent);
if (caretLineY!=lastLineY) {
repaint(0,lastLineY, getWidth(), 2); // Erase old position
repaint(0,caretLineY, getWidth(), 2);
lastLineY = caretLineY;
}
}
}
public void mouseClicked(MouseEvent e) {
Component source = (Component)e.getSource();
if (source instanceof Marker) {
((Marker)source).mouseClicked(e);
return;
}
int line = yToLine(e.getY());
if (line>-1) {
try {
int offs = textArea.getLineStartOffset(line);
textArea.setCaretPosition(offs);
} catch (BadLocationException ble) { // Never happens
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
}
}
}
public void propertyChange(PropertyChangeEvent e) {
String propName = e.getPropertyName();
// If they change whether marked occurrences are visible in editor
if (RSyntaxTextArea.MARK_OCCURRENCES_PROPERTY.equals(propName)) {
if (getShowMarkedOccurrences()) {
refreshMarkers();
}
}
// If parser notices changed.
else if (RSyntaxTextArea.PARSER_NOTICES_PROPERTY.equals(propName)) {
refreshMarkers();
}
// If marked occurrences changed.
else if (RSyntaxTextArea.MARKED_OCCURRENCES_CHANGED_PROPERTY.
equals(propName)) {
if (getShowMarkedOccurrences()) {
refreshMarkers();
}
}
}
}
private static final Color COLOR = new Color(220, 220, 220);
/**
* A notice that wraps a "marked occurrence."
*/
private class MarkedOccurrenceNotice implements ParserNotice {
private DocumentRange range;
public MarkedOccurrenceNotice(DocumentRange range) {
this.range = range;
}
public int compareTo(Object o) {
return 0; // Value doesn't matter
}
public boolean containsPosition(int pos) {
return pos>=range.getStartOffset() && pos<range.getEndOffset();
}
public boolean equals(Object o) {
// FindBugs - Define equals() when defining compareTo()
return compareTo(o)==0;
}
public Color getColor() {
return COLOR;
//return textArea.getMarkOccurrencesColor();
}
public int getLength() {
return range.getEndOffset() - range.getStartOffset();
}
public int getLevel() {
return INFO; // Won't matter
}
public int getLine() {
try {
return textArea.getLineOfOffset(range.getStartOffset());
} catch (BadLocationException ble) {
return 0;
}
}
public String getMessage() {
String text = null;
try {
String word = textArea.getText(range.getStartOffset(),
getLength());
text = msg.getString("OccurrenceOf");
text = MessageFormat.format(text, new String[] { word });
} catch (BadLocationException ble) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
}
return text;
}
public int getOffset() {
return range.getStartOffset();
}
public Parser getParser() {
return null;
}
public boolean getShowInEditor() {
return false; // Value doesn't matter
}
public String getToolTipText() {
return null;
}
public int hashCode() { // FindBugs, since we override equals()
return 0; // Value doesn't matter for us.
}
}
/**
* A "marker" in this error strip, representing one or more notices.
*/
private class Marker extends JComponent {
private List notices;
public Marker(ParserNotice notice) {
notices = new ArrayList(1); // Usually just 1
addNotice(notice);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setSize(getPreferredSize());
ToolTipManager.sharedInstance().registerComponent(this);
}
public void addNotice(ParserNotice notice) {
notices.add(notice);
}
public boolean containsMarkedOccurence() {
boolean result = false;
for (int i=0; i<notices.size(); i++) {
if (notices.get(i) instanceof MarkedOccurrenceNotice) {
result = true;
break;
}
}
return result;
}
public Color getColor() {
// Return the color for the highest-level parser.
Color c = null;
int lowestLevel = Integer.MAX_VALUE; // ERROR is 0
for (Iterator i=notices.iterator(); i.hasNext(); ) {
ParserNotice notice = (ParserNotice)i.next();
if (notice.getLevel()<lowestLevel) {
lowestLevel = notice.getLevel();
c = notice.getColor();
}
}
return c;
}
public Dimension getPreferredSize() {
int w = PREFERRED_WIDTH - 4; // 2-pixel empty border
return new Dimension(w, 5);
}
public String getToolTipText() {
String text = null;
if (notices.size()==1) {
text = ((ParserNotice)notices.get(0)).getMessage();
}
else { // > 1
StringBuffer sb = new StringBuffer("<html>");
sb.append(msg.getString("MultipleMarkers"));
sb.append("<br>");
for (int i=0; i<notices.size(); i++) {
ParserNotice pn = (ParserNotice)notices.get(i);
sb.append("&nbsp;&nbsp;&nbsp;- ");
sb.append(pn.getMessage());
sb.append("<br>");
}
text = sb.toString();
}
return text;
}
protected void mouseClicked(MouseEvent e) {
ParserNotice pn = (ParserNotice)notices.get(0);
int offs = pn.getOffset();
int len = pn.getLength();
if (offs>-1 && len>-1) { // These values are optional
textArea.setSelectionStart(offs);
textArea.setSelectionEnd(offs+len);
}
else {
int line = pn.getLine();
try {
offs = textArea.getLineStartOffset(line);
textArea.setCaretPosition(offs);
} catch (BadLocationException ble) { // Never happens
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
}
}
}
protected void paintComponent(Graphics g) {
// TODO: Give "priorities" and always pick color of a notice with
// highest priority (e.g. parsing errors will usually be red).
Color borderColor = getColor();
if (borderColor==null) {
borderColor = Color.DARK_GRAY;
}
Color fillColor = getBrighterColor(borderColor);
int w = getWidth();
int h = getHeight();
g.setColor(fillColor);
g.fillRect(0,0, w,h);
g.setColor(borderColor);
g.drawRect(0,0, w-1,h-1);
}
public void removeNotify() {
super.removeNotify();
ToolTipManager.sharedInstance().unregisterComponent(this);
removeMouseListener(listener);
}
public void updateLocation() {
int line = ((ParserNotice)notices.get(0)).getLine();
int y = lineToY(line);
setLocation(2, y);
}
}
}

View File

@ -1,3 +0,0 @@
Line=Line: {0}
MultipleMarkers=Multiple markers at this line:
OccurrenceOf=Occurrence of "{0}"

View File

@ -1,3 +0,0 @@
Line=Line: {0}
MultipleMarkers=\u0647\u0646\u0627\u0643 \u0639\u062f\u0629 \u062a\u062d\u062f\u064a\u062f\u0627\u062a \u0641\u064a \u0647\u0630\u0627 \u0627\u0644\u0633\u0637\u0631:
OccurrenceOf=\u0639\u062f\u062f \u0645\u0631\u0627\u062a \u062d\u062f\u0648\u062b"{0}"

View File

@ -1,3 +0,0 @@
Line=Zeile: {0}
MultipleMarkers=Mehrfache Markierungen in dieser Zeile:
OccurrenceOf=Auftreten von "{0}"

View File

@ -1,3 +0,0 @@
Line=Linea: {0}
MultipleMarkers=M\u00faltiples marcadores en esta linea:
OccurrenceOf=Ocurrencia de "{0}"

View File

@ -1,3 +0,0 @@
Line=Ligne: {0}
MultipleMarkers=Plusieurs rep\u00e8res sur cette ligne:
OccurrenceOf=Pr\u00e9sence de "{0}"

View File

@ -1,3 +0,0 @@
Line=Sor: {0}
MultipleMarkers=T\u00f6bb jel\u00f6l\u0151 ebben a sorban:
OccurrenceOf=A(z) "{0}" el\u0151fordul\u00e1sa

View File

@ -1,3 +0,0 @@
Line=Line: {0}
MultipleMarkers=Multiple markers at this line:
OccurrenceOf=Occurrence of "{0}"

View File

@ -1,3 +0,0 @@
Line=Linea: {0}
MultipleMarkers=Multipli punti a questa linea:
OccurrenceOf=Occorrenze di "{0}"

View File

@ -1,3 +0,0 @@
Line=\u884c: {0}
MultipleMarkers=\u3053\u306e\u884c\u306e\u4e2d\u306b\u3044\u304f\u3064\u306e\u30de\u30fc\u30ab\u30fc\u306f\u3042\u308a\u307e\u3059:
OccurrenceOf=\u51fa\u73fe\u56de\u6570 "{0}"

View File

@ -1,3 +0,0 @@
Line=\ud589: {0}
MultipleMarkers=\uc774 \ud589\uc5d0 \ubcf5\uc218\uc758 \ub9c8\ucee4 \uc874\uc7ac:
OccurrenceOf="{0}" \ubc1c\uc0dd

View File

@ -1,3 +0,0 @@
Line=Line: {0}
MultipleMarkers=Multiple markers at this line:
OccurrenceOf=Occurrence of "{0}"

View File

@ -1,3 +0,0 @@
Line=Linia: {0}
MultipleMarkers=Wiele znacznik w tej linii:
OccurrenceOf=Wyst\u0119powanie "{0}"

View File

@ -1,3 +0,0 @@
Line=Linha: {0}
MultipleMarkers=M\u00faltiplos marcadores nesta linha:
OccurrenceOf=Ocorr\u00eancia de: "{0}"

View File

@ -1,3 +0,0 @@
Line=\u0421\u0442\u0440\u043e\u043a\u0430: {0}
MultipleMarkers=\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435:
OccurrenceOf=\u0412\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0435 "{0}"

View File

@ -1,3 +0,0 @@
Line=Sat\u0131r: {0}
MultipleMarkers=Bu sat\u0131rda birden fazla i\u015faret\u00e7i:
OccurrenceOf="{0}"\u0131n bulunmas\u0131

View File

@ -1,3 +0,0 @@
Line=\u884c: {0}
MultipleMarkers=\u6b64\u884c\u6709\u591a\u6807\u8bb0
OccurrenceOf=\u6709"{0}"\u51fa\u73b0

View File

@ -1,3 +0,0 @@
Line=Line: {0}
MultipleMarkers=Multiple markers at this line:
OccurrenceOf=Occurrence of "{0}"

View File

@ -1,114 +0,0 @@
/*
* 11/13/2008
*
* FileFileLocation.java - The location of a local file.
*
* 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.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* The location of a local file.
*
* @author Robert Futrell
* @version 1.0
*/
class FileFileLocation extends FileLocation {
/**
* The file. This may or may not actually exist.
*/
private File file;
/**
* Constructor.
*
* @param file The local file.
*/
public FileFileLocation(File file) {
try {
// Useful on Windows and OS X.
this.file = file.getCanonicalFile();
} catch (IOException ioe) {
this.file = file;
}
}
/**
* {@inheritDoc}
*/
protected long getActualLastModified() {
return file.lastModified();
}
/**
* Returns the full path to the file.
*
* @return The full path to the file.
* @see #getFileName()
*/
public String getFileFullPath() {
return file.getAbsolutePath();
}
/**
* {@inheritDoc}
*/
public String getFileName() {
return file.getName();
}
/**
* {@inheritDoc}
*/
protected InputStream getInputStream() throws IOException {
return new FileInputStream(file);
}
/**
* {@inheritDoc}
*/
protected OutputStream getOutputStream() throws IOException {
return new FileOutputStream(file);
}
/**
* Always returns <code>true</code>.
*
* @return <code>true</code> always.
* @see #isLocalAndExists()
*/
public boolean isLocal() {
return true;
}
/**
* Since file locations of this type are guaranteed to be local, this
* method returns whether the file exists.
*
* @return Whether this local file actually exists.
* @see #isLocal()
*/
public boolean isLocalAndExists() {
return file.exists();
}
}

View File

@ -1,141 +0,0 @@
/*
* 11/13/2008
*
* FileLocation.java - Holds the location of a local or remote file.
*
* 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.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
/**
* Holds the location of a local or remote file. This provides a common way
* to read, write, and check properties of both local and remote files.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class FileLocation {
/**
* Creates a {@link FileLocation} instance for the specified local file.
*
* @param fileFullPath The full path to a local file.
* @return The file's location.
*/
public static FileLocation create(String fileFullPath) {
return new FileFileLocation(new File(fileFullPath));
}
/**
* Creates a {@link FileLocation} instance for the specified local file.
*
* @param file A local file.
* @return The file's location.
*/
public static FileLocation create(File file) {
return new FileFileLocation(file);
}
/**
* Creates a {@link FileLocation} instance for the specified file.
*
* @param url The URL of a file.
* @return The file's location.
*/
public static FileLocation create(URL url) {
if ("file".equalsIgnoreCase(url.getProtocol())) {
return new FileFileLocation(new File(url.getPath()));
}
return new URLFileLocation(url);
}
/**
* Returns the last time this file was modified, or
* {@link TextEditorPane#LAST_MODIFIED_UNKNOWN} if this value cannot be
* computed (such as for a remote file).
*
* @return The last time this file was modified.
*/
protected abstract long getActualLastModified();
/**
* Returns the full path to the file. This will be stripped of
* sensitive information such as passwords for remote files.
*
* @return The full path to the file.
* @see #getFileName()
*/
public abstract String getFileFullPath();
/**
* Returns the name of the file.
*
* @return The name of the file.
* @see #getFileFullPath()
*/
public abstract String getFileName();
/**
* Opens an input stream for reading from this file.
*
* @return The input stream.
* @throws IOException If the file does not exist, or some other IO error
* occurs.
*/
protected abstract InputStream getInputStream() throws IOException;
/**
* Opens an output stream for writing this file.
*
* @return An output stream.
* @throws IOException If an IO error occurs.
*/
protected abstract OutputStream getOutputStream() throws IOException;
/**
* Returns whether this file location is a local file.
*
* @return Whether this is a local file.
* @see #isLocalAndExists()
*/
public abstract boolean isLocal();
/**
* Returns whether this file location is a local file that already
* exists.
*
* @return Whether this file is local and actually exists.
* @see #isLocal()
*/
public abstract boolean isLocalAndExists();
/**
* Returns whether this file location is a remote location.
*
* @return Whether this is a remote file location.
*/
public boolean isRemote() {
return !isLocal();
}
}

View File

@ -1,237 +0,0 @@
/*
* 03/07/2012
*
* FoldingAwareIconRowHeader - Icon row header that paints itself correctly
* even when code folding is enabled.
*
* 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.Color;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.Icon;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
import org.fife.ui.rtextarea.GutterIconInfo;
import org.fife.ui.rtextarea.IconRowHeader;
/**
* A row header component that takes code folding into account when painting
* itself.
*
* @author Robert Futrell
* @version 1.0
*/
public class FoldingAwareIconRowHeader extends IconRowHeader {
/**
* Constructor.
*
* @param textArea The parent text area.
*/
public FoldingAwareIconRowHeader(RSyntaxTextArea textArea) {
super(textArea);
}
/**
* {@inheritDoc}
*/
protected void paintComponent(Graphics g) {
// When line wrap is not enabled, take the faster code path.
if (textArea==null) {
return;
}
RSyntaxTextArea rsta = (RSyntaxTextArea)textArea;
FoldManager fm = rsta.getFoldManager();
if (!fm.isCodeFoldingSupportedAndEnabled()) {
super.paintComponent(g);
return;
}
visibleRect = g.getClipBounds(visibleRect);
if (visibleRect==null) { // ???
visibleRect = getVisibleRect();
}
//System.out.println("IconRowHeader repainting: " + visibleRect);
if (visibleRect==null) {
return;
}
g.setColor(getBackground());
g.fillRect(0,visibleRect.y, width,visibleRect.height);
if (textArea.getLineWrap()) {
paintComponentWrapped(g);
return;
}
Document doc = textArea.getDocument();
Element root = doc.getDefaultRootElement();
textAreaInsets = textArea.getInsets(textAreaInsets);
// Get the first line to paint.
int cellHeight = textArea.getLineHeight();
int topLine = (visibleRect.y-textAreaInsets.top)/cellHeight;
// Get where to start painting (top of the row).
// We need to be "scrolled up" up just enough for the missing part of
// the first line.
int y = topLine*cellHeight + textAreaInsets.top;
// AFTER calculating visual offset to paint at, account for folding.
topLine += fm.getHiddenLineCountAbove(topLine, true);
// Paint the active line range.
if (activeLineRangeStart>-1 && activeLineRangeEnd>-1) {
Color activeLineRangeColor = getActiveLineRangeColor();
g.setColor(activeLineRangeColor);
try {
int y1 = rsta.yForLine(activeLineRangeStart);
if (y1>-1) { // Not in a collapsed fold...
int y2 = rsta.yForLine(activeLineRangeEnd);
if (y2==-1) { // In a collapsed fold
y2 = y1;
}
y2 += cellHeight - 1;
int j = y1;
while (j<=y2) {
int yEnd = Math.min(y2, j+getWidth());
int xEnd = yEnd-j;
g.drawLine(0,j, xEnd,yEnd);
j += 2;
}
int i = 2;
while (i<getWidth()) {
int yEnd = y1 + getWidth() - i;
g.drawLine(i,y1, getWidth(),yEnd);
i += 2;
}
if (y1>=y && y1<y+visibleRect.height) {
g.drawLine(0,y1, getWidth(),y1);
}
if (y2>=y && y2<y+visibleRect.height) {
g.drawLine(0,y2, getWidth(),y2);
}
}
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
}
// Paint icons
if (trackingIcons!=null) {
int lastLine = textArea.getLineCount() - 1;
for (int i=trackingIcons.size()-1; i>=0; i--) { // Last to first
GutterIconInfo ti = getTrackingIcon(i);
int offs = ti.getMarkedOffset();
if (offs>=0 && offs<=doc.getLength()) {
int line = root.getElementIndex(offs);
if (line<=lastLine && line>=topLine) {
try {
Icon icon = ti.getIcon();
if (icon!=null) {
int lineY = rsta.yForLine(line);
if (lineY>=y && lineY<=visibleRect.y+visibleRect.height) {
int y2 = lineY + (cellHeight-icon.getIconHeight())/2;
icon.paintIcon(this, g, 0, y2);
lastLine = line-1; // Paint only 1 icon per line
}
}
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
}
else if (line<topLine) {
break; // All other lines are above us, so quit now
}
}
}
}
}
/**
* Paints icons when line wrapping is enabled. Note that this does not
* override the parent class's implementation to avoid this version being
* called when line wrapping is disabled.
*/
private void paintComponentWrapped(Graphics g) {
// The variables we use are as follows:
// - visibleRect is the "visible" area of the text area; e.g.
// [0,100, 300,100+(lineCount*cellHeight)-1].
// actualTop.y is the topmost-pixel in the first logical line we
// paint. Note that we may well not paint this part of the logical
// line, as it may be broken into many physical lines, with the first
// few physical lines scrolled past. Note also that this is NOT the
// visible rect of this line number list; this line number list has
// visible rect == [0,0, insets.left-1,visibleRect.height-1].
// We avoid using modelToView/viewToModel where possible, as these
// methods trigger a parsing of the line into syntax tokens, which is
// costly. It's cheaper to just grab the child views' bounds.
RSyntaxTextArea rsta = (RSyntaxTextArea)textArea;
// boolean currentLineHighlighted = textArea.getHighlightCurrentLine();
Document doc = textArea.getDocument();
Element root = doc.getDefaultRootElement();
int topPosition = textArea.viewToModel(
new Point(visibleRect.x,visibleRect.y));
int topLine = root.getElementIndex(topPosition);
int topY = visibleRect.y;
int bottomY = visibleRect.y + visibleRect.height;
int cellHeight = textArea.getLineHeight();
// Paint icons
if (trackingIcons!=null) {
int lastLine = textArea.getLineCount() - 1;
for (int i=trackingIcons.size()-1; i>=0; i--) { // Last to first
GutterIconInfo ti = getTrackingIcon(i);
int offs = ti.getMarkedOffset();
if (offs>=0 && offs<=doc.getLength()) {
int line = root.getElementIndex(offs);
if (line<=lastLine && line>=topLine) {
try {
int lineY = rsta.yForLine(line);
if (lineY>=topY && lineY<bottomY) {
Icon icon = ti.getIcon();
if (icon!=null) {
int y2 = lineY + (cellHeight-icon.getIconHeight())/2;
ti.getIcon().paintIcon(this, g, 0, y2);
lastLine = line-1; // Paint only 1 icon per line
}
}
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
}
else if (line<topLine) {
break; // All other lines are above us, so quit now
}
}
}
}
}
}

View File

@ -1,139 +0,0 @@
/*
* 10/01/2009
*
* MarkOccurrencesHighlightPainter.java - Renders "marked occurrences."
*
* 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.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import javax.swing.text.View;
/**
* Highlight painter that renders "mark occurrences."
*
* @author Robert Futrell
* @version 1.0
*/
/*
* NOTE: This implementation is a "hack" so typing at the "end" of the highlight
* does not extend it to include the newly-typed chars, which is the standard
* behavior of Swing Highlights.
*/
class MarkOccurrencesHighlightPainter extends ChangeableColorHighlightPainter {
private Color borderColor;
private boolean paintBorder;
/**
* Creates a highlight painter that defaults to blue.
*/
public MarkOccurrencesHighlightPainter() {
super(Color.BLUE);
}
/**
* Returns whether a border is painted around marked occurrences.
*
* @return Whether a border is painted.
* @see #setPaintBorder(boolean)
* @see #getColor()
*/
public boolean getPaintBorder() {
return paintBorder;
}
/**
* {@inheritDoc}
*/
public Shape paintLayer(Graphics g, int p0, int p1, Shape viewBounds,
JTextComponent c, View view) {
g.setColor(getColor());
p1++; // Workaround for Java Highlight issues.
// This special case isn't needed for most standard Swing Views (which
// always return a width of 1 for modelToView() calls), but it is
// needed for RSTA views, which actually return the width of chars for
// modelToView calls. But this should be faster anyway, as we
// short-circuit and do only one modelToView() for one offset.
if (p0==p1) {
try {
Shape s = view.modelToView(p0, viewBounds,
Position.Bias.Forward);
Rectangle r = s.getBounds();
g.drawLine(r.x, r.y, r.x, r.y+r.height);
return r;
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
return null;
}
}
if (p0 == view.getStartOffset() && p1 == view.getEndOffset()) {
// Contained in view, can just use bounds.
Rectangle alloc;
if (viewBounds instanceof Rectangle) {
alloc = (Rectangle) viewBounds;
} else {
alloc = viewBounds.getBounds();
}
g.fillRect(alloc.x, alloc.y, alloc.width, alloc.height);
return alloc;
}
// Should only render part of View.
try {
// --- determine locations ---
Shape shape = view.modelToView(p0, Position.Bias.Forward, p1,
Position.Bias.Backward, viewBounds);
Rectangle r = (shape instanceof Rectangle) ? (Rectangle) shape
: shape.getBounds();
g.fillRect(r.x, r.y, r.width, r.height);
if (paintBorder) {
g.setColor(borderColor);
g.drawRect(r.x,r.y, r.width-1,r.height-1);
}
return r;
} catch (BadLocationException e) { // Never happens
e.printStackTrace();
return null;
}
}
/**
* {@inheritDoc}
*/
public void setColor(Color c) {
super.setColor(c);
borderColor = c.darker();
}
/**
* Toggles whether a border is painted around highlights.
*
* @param paint Whether to paint a border.
* @see #getPaintBorder()
* @see #setColor(Color)
*/
public void setPaintBorder(boolean paint) {
this.paintBorder = paint;
}
}

View File

@ -1,320 +0,0 @@
/*
* 01/06/2009
*
* MarkOccurrencesSupport.java - Handles marking all occurrences of the
* currently selected identifier in a text area.
*
* 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.Color;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
/**
* Marks all occurrences of the token at the current caret position, if it is
* an identifier.
*
* @author Robert Futrell
* @version 1.0
*/
class MarkOccurrencesSupport implements CaretListener, ActionListener {
private RSyntaxTextArea textArea;
private Timer timer;
private MarkOccurrencesHighlightPainter p;
/**
* The default color used to mark occurrences.
*/
public static final Color DEFAULT_COLOR = new Color(224, 224, 224);
/**
* The default delay.
*/
private static final int DEFAULT_DELAY_MS = 1000;
/**
* Constructor. Creates a listener with a 1 second delay.
*/
public MarkOccurrencesSupport() {
this(DEFAULT_DELAY_MS);
}
/**
* Constructor.
*
* @param delay The delay between when the caret last moves and when the
* text should be scanned for matching occurrences. This should
* be in milliseconds.
*/
public MarkOccurrencesSupport(int delay) {
this(delay, DEFAULT_COLOR);
}
/**
* Constructor.
*
* @param delay The delay between when the caret last moves and when the
* text should be scanned for matching occurrences. This should
* be in milliseconds.
* @param color The color to use to mark the occurrences. This cannot be
* <code>null</code>.
*/
public MarkOccurrencesSupport(int delay, Color color) {
timer = new Timer(delay, this);
timer.setRepeats(false);
p = new MarkOccurrencesHighlightPainter();
setColor(color);
}
/**
* Called after the caret has been moved and a fixed time delay has
* elapsed. This locates and highlights all occurrences of the identifier
* at the caret position, if any.
*
* @param e The event.
*/
public void actionPerformed(ActionEvent e) {
// Don't do anything if they are selecting text.
Caret c = textArea.getCaret();
if (c.getDot()!=c.getMark()) {
return;
}
RSyntaxDocument doc = (RSyntaxDocument)textArea.getDocument();
//long time = System.currentTimeMillis();
doc.readLock();
try {
// Get the token at the caret position.
int line = textArea.getCaretLineNumber();
Token tokenList = textArea.getTokenListForLine(line);
int dot = c.getDot();
Token t = RSyntaxUtilities.getTokenAtOffset(tokenList, dot);
if (t==null /* EOL */ || !isValidType(t) || isNonWordChar(t)) {
// Try to the "left" of the caret.
dot--;
try {
if (dot>=textArea.getLineStartOffset(line)) {
t = RSyntaxUtilities.getTokenAtOffset(tokenList, dot);
}
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
}
// Add new highlights if an identifier is selected.
if (t!=null && isValidType(t) && !isNonWordChar(t)) {
removeHighlights();
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
char[] lexeme = t.getLexeme().toCharArray();
int type = t.type;
for (int i=0; i<textArea.getLineCount(); i++) {
Token temp = textArea.getTokenListForLine(i);
while (temp!=null && temp.isPaintable()) {
if (temp.is(type, lexeme)) {
try {
int end = temp.offset + temp.textCount;
h.addMarkedOccurrenceHighlight(temp.offset, end, p);
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
}
temp = temp.getNextToken();
}
}
//textArea.repaint();
// TODO: Do a textArea.repaint() instead of repainting each marker as it's added if count is huge
}
} finally {
doc.readUnlock();
//time = System.currentTimeMillis() - time;
//System.out.println("MarkOccurrencesSupport took: " + time + " ms");
}
textArea.fireMarkedOccurrencesChanged();
}
/**
* Called when the caret moves in the text area.
*
* @param e The event.
*/
public void caretUpdate(CaretEvent e) {
timer.restart();
}
/**
* Returns the color being used to mark occurrences.
*
* @return The color being used.
* @see #setColor(Paint)
*/
public Color getColor() {
return p.getColor();
}
/**
* Returns the delay, in milliseconds.
*
* @return The delay.
* @see #setDelay(int)
*/
public int getDelay() {
return timer.getDelay();
}
/**
* Returns whether a border is painted around marked occurrences.
*
* @return Whether a border is painted.
* @see #setPaintBorder(boolean)
* @see #getColor()
*/
public boolean getPaintBorder() {
return p.getPaintBorder();
}
/**
* Installs this listener on a text area. If it is already installed on
* another text area, it is uninstalled first.
*
* @param textArea The text area to install on.
*/
public void install(RSyntaxTextArea textArea) {
if (this.textArea!=null) {
uninstall();
}
this.textArea = textArea;
textArea.addCaretListener(this);
if (textArea.getMarkOccurrencesColor()!=null) {
setColor(textArea.getMarkOccurrencesColor());
}
}
/**
* Returns whether the specified token is a single non-word char (e.g. not
* in <tt>[A-Za-z]</tt>. This is a HACK to work around the fact that many
* standard token makers return things like semicolons and periods as
* {@link Token#IDENTIFIER}s just to make the syntax highlighting coloring
* look a little better.
*
* @param t The token to check. This cannot be <tt>null</tt>.
* @return Whether the token is a single non-word char.
*/
private static final boolean isNonWordChar(Token t) {
return t.textCount==1 &&
!RSyntaxUtilities.isLetter(t.text[t.textOffset]);
}
/**
* Returns whether the specified token is a type that we can do a
* "mark occurrences" on.
*
* @param t The token.
* @return Whether we should mark all occurrences of this token.
*/
private boolean isValidType(Token t) {
return textArea.getMarkOccurrencesOfTokenType(t.type);
}
/**
* Removes all highlights added to the text area by this listener.
*/
private void removeHighlights() {
if (textArea!=null) {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
h.clearMarkOccurrencesHighlights();
}
}
/**
* Sets the color to use when marking occurrences.
*
* @param color The color to use.
* @see #getColor()
* @see #setPaintBorder(boolean)
*/
public void setColor(Color color) {
p.setColor(color);
if (textArea!=null) {
removeHighlights();
caretUpdate(null); // Force a highlight repaint.
}
}
/**
* Sets the delay between the last caret position change and when the
* text is scanned for matching identifiers. A delay is needed to prevent
* repeated scanning while the user is typing.
*
* @param delay The new delay.
* @see #getDelay()
*/
public void setDelay(int delay) {
timer.setDelay(delay);
}
/**
* Toggles whether a border is painted around marked highlights.
*
* @param paint Whether to paint a border.
* @see #getPaintBorder()
* @see #setColor(Color)
*/
public void setPaintBorder(boolean paint) {
if (paint!=p.getPaintBorder()) {
p.setPaintBorder(paint);
if (textArea!=null) {
textArea.repaint();
}
}
}
/**
* Uninstalls this listener from the current text area. Does nothing if
* it not currently installed on any text area.
*
* @see #install(RSyntaxTextArea)
*/
public void uninstall() {
if (textArea!=null) {
removeHighlights();
textArea.removeCaretListener(this);
}
}
}

View File

@ -1,707 +0,0 @@
/*
* 09/26/2005
*
* ParserManager.java - Manages the parsing of an RSyntaxTextArea's document,
* if necessary.
*
* 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.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.Timer;
import javax.swing.ToolTipManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Position;
import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip;
import org.fife.ui.rsyntaxtextarea.parser.ParseResult;
import org.fife.ui.rsyntaxtextarea.parser.Parser;
import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
import org.fife.ui.rsyntaxtextarea.parser.ToolTipInfo;
/**
* Manages running a parser object for an <code>RSyntaxTextArea</code>.
*
* @author Robert Futrell
* @version 0.9
*/
class ParserManager implements DocumentListener, ActionListener,
HyperlinkListener {
private RSyntaxTextArea textArea;
private List parsers;
private Timer timer;
private boolean running;
private Parser parserForTip;
private Position firstOffsetModded;
private Position lastOffsetModded;
/**
* Mapping of notices to their highlights in the editor. Can't use a Map
* since parsers could return two <code>ParserNotice</code>s that compare
* equally via <code>equals()</code>. Real-world example: The Perl
* compiler will return 2+ identical error messages if the same error is
* committed in a single line more than once.
*/
private List noticeHighlightPairs;
/**
* Painter used to underline errors.
*/
private SquiggleUnderlineHighlightPainter parserErrorHighlightPainter =
new SquiggleUnderlineHighlightPainter(Color.RED);
/**
* If this system property is set to <code>true</code>, debug messages
* will be printed to stdout to help diagnose parsing issues.
*/
private static final String PROPERTY_DEBUG_PARSING = "rsta.debugParsing";
/**
* Whether to print debug messages while running parsers.
*/
private static final boolean DEBUG_PARSING;
/**
* The default delay between the last key press and when the document
* is parsed, in milliseconds.
*/
private static final int DEFAULT_DELAY_MS = 1250;
/**
* Constructor.
*
* @param textArea The text area whose document the parser will be
* parsing.
*/
public ParserManager(RSyntaxTextArea textArea) {
this(DEFAULT_DELAY_MS, textArea);
}
/**
* Constructor.
*
* @param delay The delay between the last key press and when the document
* is parsed.
* @param textArea The text area whose document the parser will be
* parsing.
*/
public ParserManager(int delay, RSyntaxTextArea textArea) {
this.textArea = textArea;
textArea.getDocument().addDocumentListener(this);
parsers = new ArrayList(1); // Usually small
timer = new Timer(delay, this);
timer.setRepeats(false);
running = true;
}
/**
* Called when the timer fires (e.g. it's time to parse the document).
*
* @param e The event.
*/
public void actionPerformed(ActionEvent e) {
// Sanity check - should have >1 parser if event is fired.
int parserCount = getParserCount();
if (parserCount==0) {
return;
}
long begin = 0;
if (DEBUG_PARSING) {
begin = System.currentTimeMillis();
}
RSyntaxDocument doc = (RSyntaxDocument)textArea.getDocument();
Element root = doc.getDefaultRootElement();
int firstLine = firstOffsetModded==null ? 0 : root.getElementIndex(firstOffsetModded.getOffset());
int lastLine = lastOffsetModded==null ? root.getElementCount()-1 : root.getElementIndex(lastOffsetModded.getOffset());
firstOffsetModded = lastOffsetModded = null;
if (DEBUG_PARSING) {
System.out.println("[DEBUG]: Minimum lines to parse: " + firstLine + "-" + lastLine);
}
String style = textArea.getSyntaxEditingStyle();
doc.readLock();
try {
for (int i=0; i<parserCount; i++) {
Parser parser = getParser(i);
if (parser.isEnabled()) {
ParseResult res = parser.parse(doc, style);
addParserNoticeHighlights(res);
}
else {
clearParserNoticeHighlights(parser);
}
}
textArea.fireParserNoticesChange();
} finally {
doc.readUnlock();
}
if (DEBUG_PARSING) {
float time = (System.currentTimeMillis()-begin)/1000f;
System.out.println("Total parsing time: " + time + " seconds");
}
}
/**
* Adds a parser for the text area.
*
* @param parser The new parser. If this is <code>null</code>, nothing
* happens.
* @see #getParser(int)
* @see #removeParser(Parser)
*/
public void addParser(Parser parser) {
if (parser!=null && !parsers.contains(parser)) {
if (running) {
timer.stop();
}
parsers.add(parser);
if (parsers.size()==1) {
// Okay to call more than once.
ToolTipManager.sharedInstance().registerComponent(textArea);
}
if (running) {
timer.restart();
}
}
}
/**
* Adds highlights for a list of parser notices. Any current notices
* from the same Parser, in the same parsed range, are removed.
*
* @param res The result of a parsing.
* @see #clearParserNoticeHighlights()
*/
private void addParserNoticeHighlights(ParseResult res) {
// Parsers are supposed to return at least empty ParseResults, but
// we'll be defensive here.
if (res==null) {
return;
}
if (DEBUG_PARSING) {
System.out.println("[DEBUG]: Adding parser notices from " +
res.getParser());
}
if (noticeHighlightPairs==null) {
noticeHighlightPairs = new ArrayList();
}
removeParserNotices(res);
List notices = res.getNotices();
if (notices.size()>0) { // Guaranteed non-null
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
for (Iterator i=notices.iterator(); i.hasNext(); ) {
ParserNotice notice = (ParserNotice)i.next();
if (DEBUG_PARSING) {
System.out.println("[DEBUG]: ... adding: " + notice);
}
try {
Object highlight = null;
if (notice.getShowInEditor()) {
highlight = h.addParserHighlight(notice,
parserErrorHighlightPainter);
}
noticeHighlightPairs.add(new NoticeHighlightPair(notice, highlight));
} catch (BadLocationException ble) { // Never happens
ble.printStackTrace();
}
}
}
if (DEBUG_PARSING) {
System.out.println("[DEBUG]: Done adding parser notices from " +
res.getParser());
}
}
/**
* Called when the document is modified.
*
* @param e The document event.
*/
public void changedUpdate(DocumentEvent e) {
}
private void clearParserNoticeHighlights() {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
if (h!=null) {
h.clearParserHighlights();
}
if (noticeHighlightPairs!=null) {
noticeHighlightPairs.clear();
}
}
/**
* Removes all parser notice highlights for a specific parser.
*
* @param parser The parser whose highlights to remove.
*/
private void clearParserNoticeHighlights(Parser parser) {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
if (h!=null) {
h.clearParserHighlights(parser);
}
if (noticeHighlightPairs!=null) {
for (Iterator i=noticeHighlightPairs.iterator(); i.hasNext(); ) {
NoticeHighlightPair pair = (NoticeHighlightPair)i.next();
if (pair.notice.getParser()==parser) {
i.remove();
}
}
}
}
/**
* Removes all parsers and any highlights they have created.
*
* @see #addParser(Parser)
*/
public void clearParsers() {
timer.stop();
clearParserNoticeHighlights();
parsers.clear();
textArea.fireParserNoticesChange();
}
/**
* Forces the given {@link Parser} to re-parse the content of this text
* area.<p>
*
* This method can be useful when a <code>Parser</code> can be configured
* as to what notices it returns. For example, if a Java language parser
* can be configured to set whether no serialVersionUID is a warning,
* error, or ignored, this method can be called after changing the expected
* notice type to have the document re-parsed.
*
* @param parser The index of the <code>Parser</code> to re-run.
* @see #getParser(int)
*/
public void forceReparsing(int parser) {
Parser p = getParser(parser);
RSyntaxDocument doc = (RSyntaxDocument)textArea.getDocument();
String style = textArea.getSyntaxEditingStyle();
doc.readLock();
try {
if (p.isEnabled()) {
ParseResult res = p.parse(doc, style);
addParserNoticeHighlights(res);
}
else {
clearParserNoticeHighlights(p);
}
textArea.fireParserNoticesChange();
} finally {
doc.readUnlock();
}
}
/**
* Returns the delay between the last "concurrent" edit and when the
* document is re-parsed.
*
* @return The delay, in milliseconds.
* @see #setDelay(int)
*/
public int getDelay() {
return timer.getDelay();
}
/**
* Returns the specified parser.
*
* @param index The index of the parser.
* @return The parser.
* @see #getParserCount()
* @see #addParser(Parser)
* @see #removeParser(Parser)
*/
public Parser getParser(int index) {
return (Parser)parsers.get(index);
}
/**
* Returns the number of registered parsers.
*
* @return The number of registered parsers.
*/
public int getParserCount() {
return parsers.size();
}
/**
* Returns a list of the current parser notices for this text area.
* This method (like most Swing methods) should only be called on the
* EDT.
*
* @return The list of notices. This will be an empty list if there are
* none.
*/
public List getParserNotices() {
List notices = new ArrayList();
if (noticeHighlightPairs!=null) {
for (Iterator i=noticeHighlightPairs.iterator(); i.hasNext(); ) {
NoticeHighlightPair pair = (NoticeHighlightPair)i.next();
notices.add(pair.notice);
}
}
return notices;
}
/**
* Returns the tool tip to display for a mouse event at the given
* location. This method is overridden to give a registered parser a
* chance to display a tool tip (such as an error description when the
* mouse is over an error highlight).
*
* @param e The mouse event.
* @return The tool tip to display, and possibly a hyperlink event handler.
*/
public ToolTipInfo getToolTipText(MouseEvent e) {
String tip = null;
HyperlinkListener listener = null;
parserForTip = null;
// try {
int pos = textArea.viewToModel(e.getPoint());
/*
Highlighter.Highlight[] highlights = textArea.getHighlighter().
getHighlights();
for (int i=0; i<highlights.length; i++) {
Highlighter.Highlight h = highlights[i];
//if (h instanceof ParserNoticeHighlight) {
// ParserNoticeHighlight pnh = (ParserNoticeHighlight)h;
int start = h.getStartOffset();
int end = h.getEndOffset();
if (start<=pos && end>=pos) {
//return pnh.getMessage();
return textArea.getText(start, end-start);
}
//}
}
*/
if (noticeHighlightPairs!=null) {
for (int j=0; j<noticeHighlightPairs.size(); j++) {
NoticeHighlightPair pair =
(NoticeHighlightPair)noticeHighlightPairs.get(j);
ParserNotice notice = pair.notice;
if (notice.containsPosition(pos)) {
tip = notice.getToolTipText();
parserForTip = notice.getParser();
if (parserForTip instanceof HyperlinkListener) {
listener = (HyperlinkListener)parserForTip;
}
break;
}
}
}
// } catch (BadLocationException ble) {
// ble.printStackTrace(); // Should never happen.
// }
URL imageBase = parserForTip==null ? null : parserForTip.getImageBase();
return new ToolTipInfo(tip, listener, imageBase);
}
/**
* Called when the document is modified.
*
* @param e The document event.
*/
public void handleDocumentEvent(DocumentEvent e) {
if (running && parsers.size()>0) {
timer.restart();
}
}
/**
* Called when the user clicks a hyperlink in a {@link FocusableTip}.
*
* @param e The event.
*/
public void hyperlinkUpdate(HyperlinkEvent e) {
if (parserForTip!=null && parserForTip.getHyperlinkListener()!=null) {
parserForTip.getHyperlinkListener().linkClicked(textArea, e);
}
}
/**
* Called when the document is modified.
*
* @param e The document event.
*/
public void insertUpdate(DocumentEvent e) {
// Keep track of the first and last offset modified. Some parsers are
// smart and will only re-parse this section of the file.
try {
int offs = e.getOffset();
if (firstOffsetModded==null || offs<firstOffsetModded.getOffset()) {
firstOffsetModded = e.getDocument().createPosition(offs);
}
offs = e.getOffset() + e.getLength();
if (lastOffsetModded==null || offs>lastOffsetModded.getOffset()) {
lastOffsetModded = e.getDocument().createPosition(offs);
}
} catch (BadLocationException ble) {
ble.printStackTrace(); // Shouldn't happen
}
handleDocumentEvent(e);
}
/**
* Removes a parser.
*
* @param parser The parser to remove.
* @return Whether the parser was found.
* @see #addParser(Parser)
* @see #getParser(int)
*/
public boolean removeParser(Parser parser) {
removeParserNotices(parser);
boolean removed = parsers.remove(parser);
if (removed) {
textArea.fireParserNoticesChange();
}
return removed;
}
/**
* Removes all parser notices (and clears highlights in the editor) from
* a particular parser.
*
* @param parser The parser.
*/
private void removeParserNotices(Parser parser) {
if (noticeHighlightPairs!=null) {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
for (Iterator i=noticeHighlightPairs.iterator(); i.hasNext(); ) {
NoticeHighlightPair pair = (NoticeHighlightPair)i.next();
if (pair.notice.getParser()==parser && pair.highlight!=null) {
h.removeParserHighlight(pair.highlight);
i.remove();
}
}
}
}
/**
* Removes any currently stored notices (and the corresponding highlights
* from the editor) from the same Parser, and in the given line range,
* as in the results.
*
* @param res The results.
*/
private void removeParserNotices(ParseResult res) {
if (noticeHighlightPairs!=null) {
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter)
textArea.getHighlighter();
for (Iterator i=noticeHighlightPairs.iterator(); i.hasNext(); ) {
NoticeHighlightPair pair = (NoticeHighlightPair)i.next();
boolean removed = false;
if (shouldRemoveNotice(pair.notice, res)) {
if (pair.highlight!=null) {
h.removeParserHighlight(pair.highlight);
}
i.remove();
removed = true;
}
if (DEBUG_PARSING) {
String text = removed ? "[DEBUG]: ... notice removed: " :
"[DEBUG]: ... notice not removed: ";
System.out.println(text + pair.notice);
}
}
}
}
/**
* Called when the document is modified.
*
* @param e The document event.
*/
public void removeUpdate(DocumentEvent e) {
// Keep track of the first and last offset modified. Some parsers are
// smart and will only re-parse this section of the file. Note that
// for removals, only the line at the removal start needs to be
// re-parsed.
try {
int offs = e.getOffset();
if (firstOffsetModded==null || offs<firstOffsetModded.getOffset()) {
firstOffsetModded = e.getDocument().createPosition(offs);
}
if (lastOffsetModded==null || offs>lastOffsetModded.getOffset()) {
lastOffsetModded = e.getDocument().createPosition(offs);
}
} catch (BadLocationException ble) { // Never happens
ble.printStackTrace();
}
handleDocumentEvent(e);
}
/**
* Restarts parsing the document.
*
* @see #stopParsing()
*/
public void restartParsing() {
timer.restart();
running = true;
}
/**
* Sets the delay between the last "concurrent" edit and when the document
* is re-parsed.
*
* @param millis The new delay, in milliseconds. This must be greater
* than <code>0</code>.
* @see #getDelay()
*/
public void setDelay(int millis) {
if (running) {
timer.stop();
}
timer.setDelay(millis);
if (running) {
timer.start();
}
}
/**
* Returns whether a parser notice should be removed, based on a parse
* result.
*
* @param notice The notice in question.
* @param res The result.
* @return Whether the notice should be removed.
*/
private final boolean shouldRemoveNotice(ParserNotice notice,
ParseResult res) {
if (DEBUG_PARSING) {
System.out.println("[DEBUG]: ... ... shouldRemoveNotice " +
notice + ": " + (notice.getParser()==res.getParser()));
}
// NOTE: We must currently remove all notices for the parser. Parser
// implementors are required to parse the entire document each parsing
// request, as RSTA is not yet sophisticated enough to determine the
// minimum range of text to parse (and ParserNotices' locations aren't
// updated when the Document is mutated, which would be a requirement
// for this as well).
// return same_parser && (in_reparsed_range || in_deleted_end_of_doc)
return notice.getParser()==res.getParser();
}
/**
* Stops parsing the document.
*
* @see #restartParsing()
*/
public void stopParsing() {
timer.stop();
running = false;
}
/**
* Mapping of a parser notice to its highlight in the editor.
*/
private static class NoticeHighlightPair {
public ParserNotice notice;
public Object highlight;
public NoticeHighlightPair(ParserNotice notice, Object highlight) {
this.notice = notice;
this.highlight = highlight;
}
}
static {
boolean debugParsing = false;
try {
debugParsing = Boolean.getBoolean(PROPERTY_DEBUG_PARSING);
} catch (AccessControlException ace) {
// Likely an applet's security manager.
debugParsing = false; // FindBugs
}
DEBUG_PARSING = debugParsing;
}
}

View File

@ -1,68 +0,0 @@
/*
* 01/11/2011
*
* PopupWindowDecorator.java - Hook allowing hosting applications to decorate
* JWindows created by the AutoComplete library.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.JWindow;
/**
* A hook allowing hosting applications to decorate JWindows created by the
* AutoComplete library. For example, you could use the
* <a href="http://jgoodies.com/">JGoodies</a> library to add drop shadows
* to the windows.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class PopupWindowDecorator {
/**
* The singleton instance of this class.
*/
private static PopupWindowDecorator decorator;
/**
* Callback called whenever an appropriate JWindow is created by the
* AutoComplete library. Implementations can decorate the window however
* they see fit.
*
* @param window The newly-created window.
*/
public abstract void decorate(JWindow window);
/**
* Returns the singleton instance of this class. This should only be
* called on the EDT.
*
* @return The singleton instance of this class, or <code>null</code>
* for none.
* @see #set(PopupWindowDecorator)
*/
public static PopupWindowDecorator get() {
return decorator;
}
/**
* Sets the singleton instance of this class. This should only be called
* on the EDT.
*
* @param decorator The new instance of this class. This may be
* <code>null</code>.
* @see #get()
*/
public static void set(PopupWindowDecorator decorator) {
PopupWindowDecorator.decorator = decorator;
}
}

View File

@ -1,62 +0,0 @@
/*
* 02/10/2009
*
* RSTAView.java - An <code>RSyntaxTextArea</code> view.
*
* 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.Rectangle;
import javax.swing.text.BadLocationException;
/**
* Utility methods for RSyntaxTextArea's views.
*
* @author Robert Futrell
* @version 1.0
*/
interface RSTAView {
/**
* Returns the y-coordinate of the specified line.<p>
*
* This method is quicker than using traditional
* <code>modelToView(int)</code> calls, as the entire bounding box isn't
* computed.
*
* @param alloc The area the text area can render into.
* @param line The line number.
* @return The y-coordinate of the top of the line, or <code>-1</code> if
* this text area doesn't yet have a positive size or the line is
* hidden (i.e. from folding).
* @throws BadLocationException If <code>line</code> isn't a valid line
* number for this document.
*/
public int yForLine(Rectangle alloc, int line) throws BadLocationException;
/**
* Returns the y-coordinate of the line containing a specified offset.<p>
*
* This method is quicker than using traditional
* <code>modelToView(int)</code> calls, as the entire bounding box isn't
* computed.
*
* @param alloc The area the text area can render into.
* @param offs The offset info the document.
* @return The y-coordinate of the top of the offset, or <code>-1</code> if
* this text area doesn't yet have a positive size or the line is
* hidden (i.e. from folding).
* @throws BadLocationException If <code>offs</code> isn't a valid offset
* into the document.
*/
public int yForLineContaining(Rectangle alloc, int offs)
throws BadLocationException;
}

View File

@ -1,605 +0,0 @@
/*
* 10/16/2004
*
* RSyntaxDocument.java - A document capable of syntax highlighting, used by
* RSyntaxTextArea.
*
* 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.event.ActionEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.swing.Action;
import javax.swing.event.*;
import javax.swing.text.*;
import org.fife.ui.rsyntaxtextarea.modes.AbstractMarkupTokenMaker;
import org.fife.ui.rtextarea.RDocument;
import org.fife.util.DynamicIntArray;
/**
* The document used by {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}.
* This document is like <code>javax.swing.text.PlainDocument</code> except that
* it also keeps track of syntax highlighting in the document. It has a "style"
* attribute associated with it that determines how syntax highlighting is done
* (i.e., what language is being highlighted).<p>
*
* Instances of <code>RSyntaxTextArea</code> will only accept instances of
* <code>RSyntaxDocument</code>, since it is this document that keeps
* track of syntax highlighting. All others will cause an exception to be
* thrown.<p>
*
* To change the language being syntax highlighted at any time, you merely have
* to call {@link #setSyntaxStyle}. Other than that, this document can be
* treated like any other save one caveat: all <code>DocumentEvent</code>s of
* type <code>CHANGE</code> use their offset and length values to represent the
* first and last lines, respectively, that have had their syntax coloring
* change. This is really a hack to increase the speed of the painting code
* and should really be corrected, but oh well.
*
* @author Robert Futrell
* @version 0.1
*/
public class RSyntaxDocument extends RDocument implements SyntaxConstants {
/**
* Creates a {@link TokenMaker} appropriate for a given programming
* language.
*/
private transient TokenMakerFactory tokenMakerFactory;
/**
* Splits text into tokens for the current programming language.
*/
private transient TokenMaker tokenMaker;
/**
* The current syntax style. Only cached to keep this class serializable.
*/
private String syntaxStyle;
/**
* Array of values representing the "last token type" on each line. This
* is used in cases such as multi-line comments: if the previous line
* ended with an (unclosed) multi-line comment, we can use this knowledge
* and start the current line's syntax highlighting in multi-line comment
* state.
*/
protected transient DynamicIntArray lastTokensOnLines;
private transient Segment s;
/**
* Constructs a plain text document. A default root element is created,
* and the tab size set to 5.
*
* @param syntaxStyle The syntax highlighting scheme to use.
*/
public RSyntaxDocument(String syntaxStyle) {
this(null, syntaxStyle);
}
/**
* Constructs a plain text document. A default root element is created,
* and the tab size set to 5.
*
* @param tmf The <code>TokenMakerFactory</code> for this document. If
* this is <code>null</code>, a default factory is used.
* @param syntaxStyle The syntax highlighting scheme to use.
*/
public RSyntaxDocument(TokenMakerFactory tmf, String syntaxStyle) {
putProperty(tabSizeAttribute, new Integer(5));
lastTokensOnLines = new DynamicIntArray(400);
lastTokensOnLines.add(Token.NULL); // Initial (empty) line.
s = new Segment();
setTokenMakerFactory(tmf);
setSyntaxStyle(syntaxStyle);
}
/**
* Alerts all listeners to this document of an insertion. This is
* overridden so we can update our syntax highlighting stuff.<p>
* The syntax highlighting stuff has to be here instead of in
* <code>insertUpdate</code> because <code>insertUpdate</code> is not
* called by the undo/redo actions, but this method is.
*
* @param e The change.
*/
protected void fireInsertUpdate(DocumentEvent e) {
/*
* Now that the text is actually inserted into the content and
* element structure, we can update our token elements and "last
* tokens on lines" structure.
*/
Element lineMap = getDefaultRootElement();
DocumentEvent.ElementChange change = e.getChange(lineMap);
Element[] added = change==null ? null : change.getChildrenAdded();
int numLines = lineMap.getElementCount();
int line = lineMap.getElementIndex(e.getOffset());
int previousLine = line - 1;
int previousTokenType = (previousLine>-1 ?
lastTokensOnLines.get(previousLine) : Token.NULL);
// If entire lines were added...
if (added!=null && added.length>0) {
Element[] removed = change.getChildrenRemoved();
int numRemoved = removed!=null ? removed.length : 0;
int endBefore = line + added.length - numRemoved;
//System.err.println("... adding lines: " + line + " - " + (endBefore-1));
//System.err.println("... ... added: " + added.length + ", removed:" + numRemoved);
for (int i=line; i<endBefore; i++) {
setSharedSegment(i); // Loads line i's text into s.
int tokenType = tokenMaker.getLastTokenTypeOnLine(s, previousTokenType);
lastTokensOnLines.add(i, tokenType);
//System.err.println("--------- lastTokensOnLines.size() == " + lastTokensOnLines.getSize());
previousTokenType = tokenType;
} // End of for (int i=line; i<endBefore; i++).
// Update last tokens for lines below until they stop changing.
updateLastTokensBelow(endBefore, numLines, previousTokenType);
} // End of if (added!=null && added.length>0).
// Otherwise, text was inserted on a single line...
else {
// Update last tokens for lines below until they stop changing.
updateLastTokensBelow(line, numLines, previousTokenType);
} // End of else.
// Let all listeners know about the insertion.
super.fireInsertUpdate(e);
}
/**
* This method is called AFTER the content has been inserted into the
* document and the element structure has been updated.<p>
* The syntax-highlighting updates need to be done here (as opposed to
* an override of <code>postRemoveUpdate</code>) as this method is called
* in response to undo/redo events, whereas <code>postRemoveUpdate</code>
* is not.<p>
* Now that the text is actually inserted into the content and element
* structure, we can update our token elements and "last tokens on
* lines" structure.
*
* @param chng The change that occurred.
* @see #removeUpdate
*/
protected void fireRemoveUpdate(DocumentEvent chng) {
Element lineMap = getDefaultRootElement();
int numLines = lineMap.getElementCount();
DocumentEvent.ElementChange change = chng.getChange(lineMap);
Element[] removed = change==null ? null : change.getChildrenRemoved();
// If entire lines were removed...
if (removed!=null && removed.length>0) {
int line = change.getIndex(); // First line entirely removed.
int previousLine = line - 1; // Line before that.
int previousTokenType = (previousLine>-1 ?
lastTokensOnLines.get(previousLine) : Token.NULL);
Element[] added = change.getChildrenAdded();
int numAdded = added==null ? 0 : added.length;
// Remove the cached last-token values for the removed lines.
int endBefore = line + removed.length - numAdded;
//System.err.println("... removing lines: " + line + " - " + (endBefore-1));
//System.err.println("... added: " + numAdded + ", removed: " + removed.length);
lastTokensOnLines.removeRange(line, endBefore); // Removing values for lines [line-(endBefore-1)].
//System.err.println("--------- lastTokensOnLines.size() == " + lastTokensOnLines.getSize());
// Update last tokens for lines below until they've stopped changing.
updateLastTokensBelow(line, numLines, previousTokenType);
} // End of if (removed!=null && removed.size()>0).
// Otherwise, text was removed from just one line...
else {
int line = lineMap.getElementIndex(chng.getOffset());
if (line>=lastTokensOnLines.getSize())
return; // If we're editing the last line in a document...
int previousLine = line - 1;
int previousTokenType = (previousLine>-1 ?
lastTokensOnLines.get(previousLine) : Token.NULL);
//System.err.println("previousTokenType for line : " + previousLine + " is " + previousTokenType);
// Update last tokens for lines below until they've stopped changing.
updateLastTokensBelow(line, numLines, previousTokenType);
}
// Let all of our listeners know about the removal.
super.fireRemoveUpdate(chng);
}
/**
* Returns whether closing markup tags should be automatically completed.
* This method only returns <code>true</code> if
* {@link #getLanguageIsMarkup()} also returns <code>true</code>.
*
* @return Whether markup closing tags should be automatically completed.
* @see #getLanguageIsMarkup()
*/
public boolean getCompleteMarkupCloseTags() {
// TODO: Remove terrible dependency on AbstractMarkupTokenMaker
return getLanguageIsMarkup() &&
((AbstractMarkupTokenMaker)tokenMaker).getCompleteCloseTags();
}
/**
* Returns whether the current programming language uses curly braces
* ('<tt>{</tt>' and '<tt>}</tt>') to denote code blocks.
*
* @return Whether curly braces denote code blocks.
*/
public boolean getCurlyBracesDenoteCodeBlocks() {
return tokenMaker.getCurlyBracesDenoteCodeBlocks();
}
/**
* Returns whether the current language is a markup language, such as
* HTML, XML or PHP.
*
* @return Whether the current language is a markup language.
*/
public boolean getLanguageIsMarkup() {
return tokenMaker.isMarkupLanguage();
}
/**
* Returns the token type of the last token on the given line.
*
* @param line The line to inspect.
* @return The token type of the last token on the specified line. If
* the line is invalid, an exception is thrown.
*/
public int getLastTokenTypeOnLine(int line) {
return lastTokensOnLines.get(line);
}
/**
* Returns the text to place at the beginning and end of a
* line to "comment" it in the current programming language.
*
* @return The start and end strings to add to a line to "comment"
* it out. A <code>null</code> value for either means there
* is no string to add for that part. A value of
* <code>null</code> for the array means this language
* does not support commenting/uncommenting lines.
*/
public String[] getLineCommentStartAndEnd() {
return tokenMaker.getLineCommentStartAndEnd();
}
/**
* Returns whether tokens of the specified type should have "mark
* occurrences" enabled for the current programming language.
*
* @param type The token type.
* @return Whether tokens of this type should have "mark occurrences"
* enabled.
*/
boolean getMarkOccurrencesOfTokenType(int type) {
return tokenMaker.getMarkOccurrencesOfTokenType(type);
}
/**
* This method returns whether auto indentation should be done if Enter
* is pressed at the end of the specified line.
*
* @param line The line to check.
* @return Whether an extra indentation should be done.
*/
public boolean getShouldIndentNextLine(int line) {
Token t = getTokenListForLine(line);
t = t.getLastNonCommentNonWhitespaceToken();
return tokenMaker.getShouldIndentNextLineAfter(t);
}
/**
* Returns a token list for the specified segment of text representing
* the specified line number. This method is basically a wrapper for
* <code>tokenMaker.getTokenList</code> that takes into account the last
* token on the previous line to assure token accuracy.
*
* @param line The line number of <code>text</code> in the document, >= 0.
* @return A token list representing the specified line.
*/
public final Token getTokenListForLine(int line) {
Element map = getDefaultRootElement();
Element elem = map.getElement(line);
int startOffset = elem.getStartOffset();
//int endOffset = (line==map.getElementCount()-1 ? elem.getEndOffset() - 1:
// elem.getEndOffset() - 1);
int endOffset = elem.getEndOffset() - 1; // Why always "-1"?
try {
getText(startOffset,endOffset-startOffset, s);
} catch (BadLocationException ble) {
ble.printStackTrace();
return null;
}
int initialTokenType = line==0 ? Token.NULL :
getLastTokenTypeOnLine(line-1);
return tokenMaker.getTokenList(s, initialTokenType, startOffset);
}
boolean insertBreakSpecialHandling(ActionEvent e) {
Action a = tokenMaker.getInsertBreakAction();
if (a!=null) {
a.actionPerformed(e);
return true;
}
return false;
}
/**
* Returns whether whitespace is visible.
*
* @return Whether whitespace is visible.
* @see #setWhitespaceVisible(boolean)
*/
public boolean isWhitespaceVisible() {
return tokenMaker==null ? false : tokenMaker.isWhitespaceVisible();
}
/**
* Deserializes a document.
*
* @param in The stream to read from.
* @throws ClassNotFoundException
* @throws IOException
*/
private void readObject(ObjectInputStream in)
throws ClassNotFoundException, IOException {
in.defaultReadObject();
// Install default TokenMakerFactory. To support custom TokenMakers,
// both JVM's should install default TokenMakerFactories that support
// the language they want to use beforehand.
setTokenMakerFactory(null);
// Handle other transient stuff
this.s = new Segment();
int lineCount = getDefaultRootElement().getElementCount();
lastTokensOnLines = new DynamicIntArray(lineCount);
setSyntaxStyle(syntaxStyle); // Actually install (transient) TokenMaker
setWhitespaceVisible(in.readBoolean()); // Do after setSyntaxStyle()
}
/**
* Makes our private <code>Segment s</code> point to the text in our
* document referenced by the specified element. Note that
* <code>line</code> MUST be a valid line number in the document.
*
* @param line The line number you want to get.
*/
private final void setSharedSegment(int line) {
Element map = getDefaultRootElement();
//int numLines = map.getElementCount();
Element element = map.getElement(line);
if (element==null)
throw new InternalError("Invalid line number: " + line);
int startOffset = element.getStartOffset();
//int endOffset = (line==numLines-1 ?
// element.getEndOffset()-1 : element.getEndOffset() - 1);
int endOffset = element.getEndOffset()-1; // Why always "-1"?
try {
getText(startOffset, endOffset-startOffset, s);
} catch (BadLocationException ble) {
throw new InternalError("Text range not in document: " +
startOffset + "-" + endOffset);
}
}
/**
* Sets the syntax style being used for syntax highlighting in this
* document. What styles are supported by a document is determined by its
* {@link TokenMakerFactory}. By default, all <code>RSyntaxDocument</code>s
* support all languages built into <code>RSyntaxTextArea</code>.
*
* @param styleKey The new style to use, such as
* {@link SyntaxConstants#SYNTAX_STYLE_JAVA}. If this style is not
* known or supported by this document, then
* {@link SyntaxConstants#SYNTAX_STYLE_NONE} is used.
*/
public void setSyntaxStyle(String styleKey) {
boolean wsVisible = isWhitespaceVisible();
tokenMaker = tokenMakerFactory.getTokenMaker(styleKey);
tokenMaker.setWhitespaceVisible(wsVisible);
updateSyntaxHighlightingInformation();
this.syntaxStyle = styleKey;
}
/**
* Sets the syntax style being used for syntax highlighting in this
* document. You should call this method if you've created a custom token
* maker for a language not normally supported by
* <code>RSyntaxTextArea</code>.
*
* @param tokenMaker The new token maker to use.
*/
public void setSyntaxStyle(TokenMaker tokenMaker) {
tokenMaker.setWhitespaceVisible(isWhitespaceVisible());
this.tokenMaker = tokenMaker;
updateSyntaxHighlightingInformation();
}
/**
* Sets the token maker factory used by this document.
*
* @param tmf The <code>TokenMakerFactory</code> for this document. If
* this is <code>null</code>, a default factory is used.
*/
public void setTokenMakerFactory(TokenMakerFactory tmf) {
tokenMakerFactory = tmf!=null ? tmf :
TokenMakerFactory.getDefaultInstance();
}
/**
* Sets whether whitespace is visible. This property is actually setting
* whether the tokens generated from this document "paint" something when
* they represent whitespace.
*
* @param visible Whether whitespace should be visible.
* @see #isWhitespaceVisible()
*/
public void setWhitespaceVisible(boolean visible) {
tokenMaker.setWhitespaceVisible(visible);
}
/**
* Loops through the last-tokens-on-lines array from a specified point
* onward, updating last-token values until they stop changing. This
* should be called when lines are updated/inserted/removed, as doing
* so may cause lines below to change color.
*
* @param line The first line to check for a change in last-token value.
* @param numLines The number of lines in the document.
* @param previousTokenType The last-token value of the line just before
* <code>line</code>.
* @return The last line that needs repainting.
*/
private int updateLastTokensBelow(int line, int numLines, int previousTokenType) {
int firstLine = line;
// Loop through all lines past our starting point. Update even the last
// line's info, even though there aren't any lines after it that depend
// on it changing for them to be changed, as its state may be used
// elsewhere in the library.
int end = numLines;
//System.err.println("--- end==" + end + " (numLines==" + numLines + ")");
while (line<end) {
setSharedSegment(line); // Sets s's text to that of line 'line' in the document.
int oldTokenType = lastTokensOnLines.get(line);
int newTokenType = tokenMaker.getLastTokenTypeOnLine(s, previousTokenType);
//System.err.println("---------------- line " + line + "; oldTokenType==" + oldTokenType + ", newTokenType==" + newTokenType + ", s=='" + s + "'");
// If this line's end-token value didn't change, stop here. Note
// that we're saying this line needs repainting; this is because
// the beginning of this line did indeed change color, but the
// end didn't.
if (oldTokenType==newTokenType) {
//System.err.println("... ... ... repainting lines " + firstLine + "-" + line);
fireChangedUpdate(new DefaultDocumentEvent(firstLine, line, DocumentEvent.EventType.CHANGE));
return line;
}
// If the line's end-token value did change, update it and
// keep going.
// NOTE: "setUnsafe" is okay here as the bounds checking was
// already done in lastTokensOnLines.get(line) above.
lastTokensOnLines.setUnsafe(line, newTokenType);
previousTokenType = newTokenType;
line++;
} // End of while (line<numLines).
// If any lines had their token types changed, fire a changed update
// for them. The view will repaint the area covered by the lines.
// FIXME: We currently cheat and send the line range that needs to be
// repainted as the "offset and length" of the change, since this is
// what the view needs. We really should send the actual offset and
// length.
if (line>firstLine) {
//System.err.println("... ... ... repainting lines " + firstLine + "-" + line);
fireChangedUpdate(new DefaultDocumentEvent(firstLine, line,
DocumentEvent.EventType.CHANGE));
}
return line;
}
/**
* Updates internal state information; e.g. the "last tokens on lines"
* data. After this, a changed update is fired to let listeners know that
* the document's structure has changed.<p>
*
* This is called internally whenever the syntax style changes.
*/
protected void updateSyntaxHighlightingInformation() {
// Reinitialize the "last token on each line" array. Note that since
// the actual text in the document isn't changing, the number of lines
// is the same.
Element map = getDefaultRootElement();
int numLines = map.getElementCount();
int lastTokenType = Token.NULL;
for (int i=0; i<numLines; i++) {
setSharedSegment(i);
lastTokenType = tokenMaker.getLastTokenTypeOnLine(s, lastTokenType);
lastTokensOnLines.set(i, lastTokenType);
}
// Let everybody know that syntax styles have (probably) changed.
fireChangedUpdate(new DefaultDocumentEvent(
0, numLines-1, DocumentEvent.EventType.CHANGE));
}
/**
* Overridden for custom serialization purposes.
*
* @param out The stream to write to.
* @throws IOException If an IO error occurs.
*/
private void writeObject(ObjectOutputStream out)throws IOException {
out.defaultWriteObject();
out.writeBoolean(isWhitespaceVisible());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Toggle Current Fold
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Toggles the fold at the caret position.
Action.CollapseAllFolds.Name=Collapse All Folds
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Collapses all folds.
Action.CollapseCommentFolds.Name=Collapse All Comments
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Collapses all comment folds.
Action.ExpandAllFolds.Name=Expand All Folds
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expands all folds.

View File

@ -1,79 +0,0 @@
/*
* 10/27/2004
*
* RSyntaxTextAreaDefaultInputMap.java - The default input map for
* RSyntaxTextAreas.
*
* 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.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import org.fife.ui.rtextarea.RTADefaultInputMap;
/**
* The default input map for an <code>RSyntaxTextArea</code>.
* Currently, the new key bindings include:
* <ul>
* <li>Shift+Tab indents the current line or currently selected lines
* to the left.
* </ul>
*
* @author Robert Futrell
* @version 1.0
*/
public class RSyntaxTextAreaDefaultInputMap extends RTADefaultInputMap {
/**
* Constructs the default input map for an <code>RSyntaxTextArea</code>.
*/
public RSyntaxTextAreaDefaultInputMap() {
int defaultMod = getDefaultModifier();
//int ctrl = InputEvent.CTRL_MASK;
int shift = InputEvent.SHIFT_MASK;
//int alt = InputEvent.ALT_MASK;
put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, shift), RSyntaxTextAreaEditorKit.rstaDecreaseIndentAction);
put(KeyStroke.getKeyStroke('}'), RSyntaxTextAreaEditorKit.rstaCloseCurlyBraceAction);
put(KeyStroke.getKeyStroke('/'), RSyntaxTextAreaEditorKit.rstaCloseMarkupTagAction);
int os = RSyntaxUtilities.getOS();
if (os==RSyntaxUtilities.OS_WINDOWS || os==RSyntaxUtilities.OS_MAC_OSX) {
// *nix causes trouble with CloseMarkupTagAction and ToggleCommentAction.
// It triggers both KEY_PRESSED ctrl+'/' and KEY_TYPED '/' events when the
// user presses ctrl+'/', but Windows and OS X do not. If we try to "move"
// the KEY_TYPED event for '/' to KEY_PRESSED, it'll work for Linux boxes
// with QWERTY keyboard layouts, but non-QUERTY users won't be able to type
// a '/' character at all then (!). Rather than try to hack together a
// solution by trying to detect the IM locale and do different things for
// different OSes & keyboard layouts, we do the simplest thing and
// (unfortunately) don't have a ToggleCommentAction for *nix out-of-the-box.
// Applications can add one easily enough if they want one.
put(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, defaultMod), RSyntaxTextAreaEditorKit.rstaToggleCommentAction);
}
put(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, defaultMod), RSyntaxTextAreaEditorKit.rstaGoToMatchingBracketAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, defaultMod), RSyntaxTextAreaEditorKit.rstaCollapseFoldAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, defaultMod), RSyntaxTextAreaEditorKit.rstaExpandFoldAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DIVIDE, defaultMod), RSyntaxTextAreaEditorKit.rstaCollapseAllFoldsAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_MULTIPLY, defaultMod), RSyntaxTextAreaEditorKit.rstaExpandAllFoldsAction);
// FIXME: The keystroke associated with this action should be dynamic and
// configurable and synchronized with the "trigger" defined in RSyntaxTextArea's
// CodeTemplateManager.
// NOTE: no modifiers => mapped to keyTyped. If we had "0" as a second
// second parameter, we'd get the template action (keyPressed) AND the
// default space action (keyTyped).
//put(KeyStroke.getKeyStroke(' '), RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction);
put(CodeTemplateManager.TEMPLATE_KEYSTROKE, RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,449 +0,0 @@
/*
* 04/23/2009
*
* RSyntaxTextAreaHighlighter.java - Highlighter for RTextAreas.
*
* 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.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.basic.BasicTextUI.BasicHighlighter;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.Position;
import javax.swing.text.View;
import org.fife.ui.rsyntaxtextarea.parser.Parser;
import org.fife.ui.rsyntaxtextarea.parser.ParserNotice;
import org.fife.ui.rtextarea.RTextArea;
/**
* The highlighter implementation used by {@link RSyntaxTextArea}s. It knows to
* always paint "marked occurrences" highlights below selection highlights,
* and squiggle underline highlights above all other highlights.<p>
*
* Most of this code is copied from javax.swing.text.DefaultHighlighter;
* unfortunately, we cannot re-use much of it since it is package private.
*
* @author Robert Futrell
* @version 1.0
*/
public class RSyntaxTextAreaHighlighter extends BasicHighlighter {
/**
* The text component we are the highlighter for.
*/
private RTextArea textArea;
/**
* Marked occurrences in the document (to be painted separately from
* other highlights).
*/
private List markedOccurrences;
/**
* Highlights from document parsers. These should be painted "on top of"
* all other highlights to ensure they are always above the selection.
*/
private List parserHighlights;
/**
* The default color used for parser notices when none is specified.
*/
private static final Color DEFAULT_PARSER_NOTICE_COLOR = Color.RED;
/**
* Constructor.
*/
public RSyntaxTextAreaHighlighter() {
markedOccurrences = new ArrayList();
parserHighlights = new ArrayList(0); // Often unused
}
/**
* Adds a special "marked occurrence" highlight.
*
* @param start
* @param end
* @param p
* @return A tag to reference the highlight later.
* @throws BadLocationException
* @see {@link #clearMarkOccurrencesHighlights()}
*/
Object addMarkedOccurrenceHighlight(int start, int end,
MarkOccurrencesHighlightPainter p) throws BadLocationException {
Document doc = textArea.getDocument();
TextUI mapper = textArea.getUI();
// Always layered highlights for marked occurrences.
HighlightInfo i = new LayeredHighlightInfo();
i.painter = p;
i.p0 = doc.createPosition(start);
// HACK: Use "end-1" to prevent chars the user types at the "end" of
// the highlight to be absorbed into the highlight (default Highlight
// behavior).
i.p1 = doc.createPosition(end-1);
markedOccurrences.add(i);
mapper.damageRange(textArea, start, end);
return i;
}
/**
* Adds a special "marked occurrence" highlight.
*
* @param notice The notice from a {@link Parser}.
* @return A tag with which to reference the highlight.
* @throws BadLocationException
* @see {@link #clearParserHighlights()}
*/
Object addParserHighlight(ParserNotice notice, HighlightPainter p)
throws BadLocationException {
Document doc = textArea.getDocument();
TextUI mapper = textArea.getUI();
int start = notice.getOffset();
int end = 0;
if (start==-1) { // Could just define an invalid line number
int line = notice.getLine();
Element root = doc.getDefaultRootElement();
if (line>=0 && line<root.getElementCount()) {
Element elem = root.getElement(line);
start = elem.getStartOffset();
end = elem.getEndOffset();
}
}
else {
end = start + notice.getLength();
}
// Always layered highlights for parser highlights.
HighlightInfo i = new LayeredHighlightInfo();
i.painter = p;
i.p0 = doc.createPosition(start);
i.p1 = doc.createPosition(end);
i.notice = notice;//i.color = notice.getColor();
parserHighlights.add(i);
mapper.damageRange(textArea, start, end);
return i;
}
/**
* Removes all "marked occurrences" highlights from the view.
*
* @see #addMarkedOccurrenceHighlight(int, int, MarkOccurrencesHighlightPainter)
*/
void clearMarkOccurrencesHighlights() {
// Don't remove via the iterator; since our List is an ArrayList, this
// implies tons of System.arrayCopy()s
for (Iterator i=markedOccurrences.iterator(); i.hasNext(); ) {
repaintListHighlight(i.next());
}
markedOccurrences.clear();
}
/**
* Removes all parser highlights.
*
* @see #addParserHighlight(ParserNotice, javax.swing.text.Highlighter.HighlightPainter)
*/
void clearParserHighlights() {
// Don't remove via an iterator; since our List is an ArrayList, this
// implies tons of System.arrayCopy()s
for (int i=0; i<parserHighlights.size(); i++) {
repaintListHighlight(parserHighlights.get(i));
}
parserHighlights.clear();
}
/**
* Removes all of the highlights for a specific parser.
*
* @param parser The parser.
*/
public void clearParserHighlights(Parser parser) {
for (Iterator i=parserHighlights.iterator(); i.hasNext(); ) {
HighlightInfo info = (HighlightInfo)i.next();
if (info.notice.getParser()==parser) {
if (info instanceof LayeredHighlightInfo) {
LayeredHighlightInfo lhi = (LayeredHighlightInfo)info;
if (lhi.width > 0 && lhi.height > 0) {
textArea.repaint(lhi.x, lhi.y, lhi.width, lhi.height);
}
}
else {
TextUI ui = textArea.getUI();
ui.damageRange(textArea, info.getStartOffset(),info.getEndOffset());
//safeDamageRange(info.p0, info.p1);
}
i.remove();
}
}
}
/**
* {@inheritDoc}
*/
public void deinstall(JTextComponent c) {
this.textArea = null;
markedOccurrences.clear();
parserHighlights.clear();
}
/**
* Returns a list of "marked occurrences" in the text area. If there are
* no marked occurrences, this will be an empty list.
*
* @return The list of marked occurrences, or an empty list if none. The
* contents of this list will be of type {@link DocumentRange}.
*/
public List getMarkedOccurrences() {
List list = new ArrayList(markedOccurrences.size());
for (Iterator i=markedOccurrences.iterator(); i.hasNext(); ) {
HighlightInfo info = (HighlightInfo)i.next();
int start = info.getStartOffset();
int end = info.getEndOffset() + 1; // HACK
DocumentRange range = new DocumentRange(start, end);
list.add(range);
}
return list;
}
/**
* {@inheritDoc}
*/
public void install(JTextComponent c) {
super.install(c);
this.textArea = (RTextArea)c;
}
/**
* Renders the highlights.
*
* @param g the graphics context
*/
public void paint(Graphics g) {
paintList(g, markedOccurrences);
super.paint(g);
paintList(g, parserHighlights);
}
private void paintList(Graphics g, List highlights) {
int len = highlights.size();
for (int i = 0; i < len; i++) {
HighlightInfo info = (HighlightInfo)highlights.get(i);
if (!(info instanceof LayeredHighlightInfo)) {
// Avoid allocating unless we need it.
Rectangle a = textArea.getBounds();
Insets insets = textArea.getInsets();
a.x = insets.left;
a.y = insets.top;
a.width -= insets.left + insets.right;
a.height -= insets.top + insets.bottom;
for (; i < len; i++) {
info = (HighlightInfo)markedOccurrences.get(i);
if (!(info instanceof LayeredHighlightInfo)) {
Color c = info.getColor();
Highlighter.HighlightPainter p = info.getPainter();
if (c!=null && p instanceof ChangeableColorHighlightPainter) {
((ChangeableColorHighlightPainter)p).setColor(c);
}
p.paint(g, info.getStartOffset(), info.getEndOffset(),
a, textArea);
}
}
}
}
}
/**
* When leaf Views (such as LabelView) are rendering they should
* call into this method. If a highlight is in the given region it will
* be drawn immediately.
*
* @param g Graphics used to draw
* @param p0 starting offset of view
* @param p1 ending offset of view
* @param viewBounds Bounds of View
* @param editor JTextComponent
* @param view View instance being rendered
*/
public void paintLayeredHighlights(Graphics g, int p0, int p1,
Shape viewBounds, JTextComponent editor, View view) {
paintListLayered(g, p0,p1, viewBounds, editor, view, markedOccurrences);
super.paintLayeredHighlights(g, p0, p1, viewBounds, editor, view);
paintListLayered(g, p0,p1, viewBounds, editor, view, parserHighlights);
}
private void paintListLayered(Graphics g, int p0, int p1, Shape viewBounds,
JTextComponent editor, View view, List highlights) {
for (int i=highlights.size()-1; i>=0; i--) {
Object tag = highlights.get(i);
if (tag instanceof LayeredHighlightInfo) {
LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;
int start = lhi.getStartOffset();
int end = lhi.getEndOffset();
if ((p0 < start && p1 > start) ||
(p0 >= start && p0 < end)) {
lhi.paintLayeredHighlights(g, p0, p1, viewBounds,
editor, view);
}
}
}
}
private void repaintListHighlight(Object tag) {
if (tag instanceof LayeredHighlightInfo) {
LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;
if (lhi.width > 0 && lhi.height > 0) {
textArea.repaint(lhi.x, lhi.y, lhi.width, lhi.height);
}
}
else {
HighlightInfo info = (HighlightInfo) tag;
TextUI ui = textArea.getUI();
ui.damageRange(textArea, info.getStartOffset(),info.getEndOffset());
//safeDamageRange(info.p0, info.p1);
}
}
/**
* Removes a parser highlight from this view.
*
* @param tag The reference to the highlight.
* @see #addParserHighlight(ParserNotice, javax.swing.text.Highlighter.HighlightPainter)
*/
void removeParserHighlight(Object tag) {
repaintListHighlight(tag);
parserHighlights.remove(tag);
}
private static class HighlightInfo implements Highlighter.Highlight {
private Position p0;
private Position p1;
protected Highlighter.HighlightPainter painter;
private ParserNotice notice;//Color color; // Used only by Parser highlights.
public Color getColor() {
//return color;
Color color = null;
if (notice!=null) {
color = notice.getColor();
if (color==null) {
color = DEFAULT_PARSER_NOTICE_COLOR;
}
}
return color;
}
public int getStartOffset() {
return p0.getOffset();
}
public int getEndOffset() {
return p1.getOffset();
}
public Highlighter.HighlightPainter getPainter() {
return painter;
}
}
private static class LayeredHighlightInfo extends HighlightInfo {
private int x;
private int y;
private int width;
private int height;
void union(Shape bounds) {
if (bounds == null) {
return;
}
Rectangle alloc = (bounds instanceof Rectangle) ?
(Rectangle)bounds : bounds.getBounds();
if (width == 0 || height == 0) {
x = alloc.x;
y = alloc.y;
width = alloc.width;
height = alloc.height;
}
else {
width = Math.max(x + width, alloc.x + alloc.width);
height = Math.max(y + height, alloc.y + alloc.height);
x = Math.min(x, alloc.x);
width -= x;
y = Math.min(y, alloc.y);
height -= y;
}
}
/**
* Restricts the region based on the receivers offsets and messages
* the painter to paint the region.
*/
void paintLayeredHighlights(Graphics g, int p0, int p1,
Shape viewBounds, JTextComponent editor,
View view) {
int start = getStartOffset();
int end = getEndOffset();
// Restrict the region to what we represent
p0 = Math.max(start, p0);
p1 = Math.min(end, p1);
if (getColor()!=null &&
(painter instanceof ChangeableColorHighlightPainter)) {
((ChangeableColorHighlightPainter)painter).setColor(getColor());
}
// Paint the appropriate region using the painter and union
// the effected region with our bounds.
union(((LayeredHighlighter.LayerPainter)painter).paintLayer
(g, p0, p1, viewBounds, editor, view));
}
}
}

View File

@ -1,256 +0,0 @@
/*
* 02/24/2004
*
* RSyntaxTextAreaUI.java - UI for an RSyntaxTextArea.
*
* 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.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.text.*;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextAreaUI;
/**
* UI used by <code>RSyntaxTextArea</code>. This allows us to implement
* syntax highlighting.
*
* @author Robert Futrell
* @version 0.1
*/
public class RSyntaxTextAreaUI extends RTextAreaUI {
private static final String SHARED_ACTION_MAP_NAME = "RSyntaxTextAreaUI.actionMap";
private static final String SHARED_INPUT_MAP_NAME = "RSyntaxTextAreaUI.inputMap";
private static final EditorKit defaultKit = new RSyntaxTextAreaEditorKit();
public static ComponentUI createUI(JComponent ta) {
return new RSyntaxTextAreaUI(ta);
}
/**
* Constructor.
*/
public RSyntaxTextAreaUI(JComponent rSyntaxTextArea) {
super(rSyntaxTextArea);
}
/**
* Creates the view for an element.
*
* @param elem The element.
* @return The view.
*/
public View create(Element elem) {
RTextArea c = getRTextArea();
if (c instanceof RSyntaxTextArea) {
RSyntaxTextArea area = (RSyntaxTextArea) c;
View v;
if (area.getLineWrap())
v = new WrappedSyntaxView(elem);
else
v = new SyntaxView(elem);
return v;
}
return null;
}
/**
* Creates the highlighter to use for syntax text areas.
*
* @return The highlighter.
*/
protected Highlighter createHighlighter() {
return new RSyntaxTextAreaHighlighter();
}
/**
* Returns the name to use to cache/fetch the shared action map. This
* should be overridden by subclasses if the subclass has its own custom
* editor kit to install, so its actions get picked up.
*
* @return The name of the cached action map.
*/
protected String getActionMapName() {
return SHARED_ACTION_MAP_NAME;
}
/**
* Fetches the EditorKit for the UI.
*
* @param tc The text component for which this UI is installed.
* @return The editor capabilities.
* @see javax.swing.plaf.TextUI#getEditorKit
*/
public EditorKit getEditorKit(JTextComponent tc) {
return defaultKit;
}
/**
* Get the InputMap to use for the UI.<p>
*
* This method is not named <code>getInputMap()</code> because there is
* a package-private method in <code>BasicTextAreaUI</code> with that name.
* Thus, creating a new method with that name causes certain compilers to
* issue warnings that you are not actually overriding the original method
* (since it is package-private).
*/
protected InputMap getRTextAreaInputMap() {
InputMap map = new InputMapUIResource();
InputMap shared = (InputMap)UIManager.get(SHARED_INPUT_MAP_NAME);
if (shared==null) {
shared = new RSyntaxTextAreaDefaultInputMap();
UIManager.put(SHARED_INPUT_MAP_NAME, shared);
}
//KeyStroke[] keys = shared.allKeys();
//for (int i=0; i<keys.length; i++)
// System.err.println(keys[i] + " -> " + shared.get(keys[i]));
map.setParent(shared);
return map;
}
/**
* Paints the text area's background.
*
* @param g The graphics component on which to paint.
*/
protected void paintBackground(Graphics g) {
super.paintBackground(g);
paintMatchedBracket(g);
}
/**
* Paints the "matched bracket", if any.
*
* @param g The graphics context.
*/
protected void paintMatchedBracket(Graphics g) {
RSyntaxTextArea rsta = (RSyntaxTextArea)textArea;
if (rsta.isBracketMatchingEnabled()) {
Rectangle match = rsta.getMatchRectangle();
if (match!=null) {
paintMatchedBracketImpl(g, rsta, match);
}
if (rsta.getPaintMatchedBracketPair()) {
Rectangle dotRect = rsta.getDotRectangle();
if (dotRect!=null) { // should always be true
paintMatchedBracketImpl(g, rsta, dotRect);
}
}
}
}
private void paintMatchedBracketImpl(Graphics g, RSyntaxTextArea rsta,
Rectangle r) {
// We must add "-1" to the height because otherwise we'll paint below
// the region that gets invalidated.
if (rsta.getAnimateBracketMatching()) {
Color bg = rsta.getMatchedBracketBGColor();
if (bg!=null) {
g.setColor(bg);
g.fillRoundRect(r.x,r.y, r.width,r.height-1, 5,5);
}
g.setColor(rsta.getMatchedBracketBorderColor());
g.drawRoundRect(r.x,r.y, r.width,r.height-1, 5,5);
}
else {
Color bg = rsta.getMatchedBracketBGColor();
if (bg!=null) {
g.setColor(bg);
g.fillRect(r.x,r.y, r.width,r.height-1);
}
g.setColor(rsta.getMatchedBracketBorderColor());
g.drawRect(r.x,r.y, r.width,r.height-1);
}
}
/**
* Gets called whenever a bound property is changed on this UI's
* <code>RSyntaxTextArea</code>.
*
* @param e The property change event.
*/
protected void propertyChange(PropertyChangeEvent e) {
String name = e.getPropertyName();
// If they change the syntax scheme, we must do this so that
// WrappedSyntaxView(_TEST) updates its child views properly.
if (name.equals(RSyntaxTextArea.SYNTAX_SCHEME_PROPERTY)) {
modelChanged();
}
// Everything else is general to all RTextAreas.
else {
super.propertyChange(e);
}
}
/**
* Updates the view. This should be called when the underlying
* <code>RSyntaxTextArea</code> changes its syntax editing style.
*/
public void refreshSyntaxHighlighting() {
modelChanged();
}
/**
* Returns the y-coordinate of the specified line.<p>
*
* This method is quicker than using traditional
* <code>modelToView(int)</code> calls, as the entire bounding box isn't
* computed.
*/
public int yForLine(int line) throws BadLocationException {
Rectangle alloc = getVisibleEditorRect();
if (alloc!=null) {
RSTAView view = (RSTAView)getRootView(textArea).getView(0);
return view.yForLine(alloc, line);
}
return -1;
}
/**
* Returns the y-coordinate of the line containing a specified offset.<p>
*
* This is faster than calling <code>modelToView(offs).y</code>, so it is
* preferred if you do not need the actual bounding box.
*/
public int yForLineContaining(int offs) throws BadLocationException {
Rectangle alloc = getVisibleEditorRect();
if (alloc!=null) {
RSTAView view = (RSTAView)getRootView(textArea).getView(0);
return view.yForLineContaining(alloc, offs);
}
return -1;
}
}

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\u0637\u0648\u064a
Action.ToggleCurrentFold.Name=\u063a\u064a\u0651\u0631 \u0648\u0636\u0639\u064a\u0629 \u0627\u0644\u0637\u0648\u064a\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\u0645\u0646 \u0623\u062c\u0644 \u062a\u063a\u064a\u064a\u0631 \u0648\u0636\u0639\u064a\u0629 \u0627\u0644\u0637\u0648\u064a\u0629 \u0641\u064a \u0645\u0648\u0642\u0639 \u0627\u0644\u0645\u0624\u0634\u0631 \u0627\u0644\u062d\u0627\u0644\u064a
Action.CollapseAllFolds.Name=\u0642\u0644\u0635 \u062c\u0645\u064a\u0639 \u0627\u0644\u0637\u064a\u0627\u062a
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\u0645\u0646 \u0623\u062c\u0644 \u062a\u0642\u0644\u064a\u0635 \u062c\u0645\u064a\u0639 \u0627\u0644\u0637\u064a\u0627\u062a
Action.CollapseCommentFolds.Name=\u0642\u0644\u0635 \u062c\u0645\u064a\u0639 \u0627\u0644\u062a\u0639\u0644\u064a\u0642\u0627\u062a
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=\u0645\u0646 \u0623\u062c\u0644 \u062a\u0642\u0644\u064a\u0635 \u062c\u0645\u064a\u0639 \u0637\u064a\u0627\u062a \u0627\u0644\u062a\u0639\u0644\u064a\u0642\u0627\u062a
Action.ExpandAllFolds.Name=\u0648\u0633\u0639 \u062c\u0645\u064a\u0639 \u0627\u0644\u0637\u064a\u0627\u062a
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\u0645\u0646 \u0623\u062c\u0644 \u062a\u0648\u0633\u064a\u0639 \u062c\u0645\u064a\u0639 \u0627\u0644\u0637\u064a\u0627\u062a.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Klappung
Action.ToggleCurrentFold.Name=Aktuellen Block umschalten
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Schaltet den Block an der Position der Schreibmarke um.
Action.CollapseAllFolds.Name=Action.CollapseAllFolds.Name=Alle Bl\u00f6cke zuklappen
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Klappt alle Bl\u00f6cke zu.
Action.CollapseCommentFolds.Name=Alle Kommentarbl\u00f6cke zuklappen
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Klappt alle Kommentarbl\u00f6cke zu.
Action.ExpandAllFolds.Name=Alle Bl\u00f6cke aufklappen
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Klappt alle Bl\u00f6cke auf.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Ver Fold (solapa) actual
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Mostrar el fold en la posici\u00f3n del cursor
Action.CollapseAllFolds.Name=Ocultar todos los folds
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Oculta todos los folds
Action.CollapseCommentFolds.Name=Ocultar todos los comentarios
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Oculta todos los comentarios
Action.ExpandAllFolds.Name=Expandir todos las solapas (folds)
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expande todas las solapas (folds)

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Pliage
Action.ToggleCurrentFold.Name=Active ou d\u00e9sactive le pli actuel
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Active ou d\u00e9sactive le pli \u00e0 la position du curseur.
Action.CollapseAllFolds.Name=Comprimer tous les plis
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Comprime tous les plis.
Action.CollapseCommentFolds.Name=Comprimer tous les commentaires
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Comprime tous les plis commentaires.
Action.ExpandAllFolds.Name=D\u00e9comrpimer tous les plis
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=D\u00e9comrpime tous les plis.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\u00d6sszevon\u00e1s
Action.ToggleCurrentFold.Name=A jelenlegi \u00f6sszevon\u00e1s megjelen\u00edt\u00e9se/rejt\u00e9se.
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Megjelen\u00edti, illetve elt\u00fcnteti az \u00f6sszevon\u00e1st a kurzor poz\u00edci\u00f3j\u00e1ban.
Action.CollapseAllFolds.Name=\u00d6sszevon\u00e1sok rejt\u00e9se.
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\u00d6sszevon\u00e1sok rejt\u00e9se.
Action.CollapseCommentFolds.Name=Az \u00f6sszes megjegyz\u00e9s elrejt\u00e9se
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Megjegyz\u00e9s \u00f6sszevon\u00e1sok rejt\u00e9se.
Action.ExpandAllFolds.Name=\u00d6sszevon\u00e1sok kiterjeszt\u00e9se
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\u00d6sszevon\u00e1sok kiterjeszt\u00e9se.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Toggle Current Fold
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Toggles the fold at the caret position.
Action.CollapseAllFolds.Name=Collapse All Folds
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Collapses all folds.
Action.CollapseCommentFolds.Name=Collapse All Comments
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Collapses all comment folds.
Action.ExpandAllFolds.Name=Expand All Folds
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expands all folds.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Imposta il fold corrente
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Imposta il fold alla posizione corrente.
Action.CollapseAllFolds.Name=Raggruppa tutti i fold
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Raggruppa tutti i fold.
Action.CollapseCommentFolds.Name=Raggruppa tutti i commenti
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Raggruppa tutti i commenti.
Action.ExpandAllFolds.Name=Espandi tutti i fold
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Espandi tutti i fold.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\u30d5\u30a9\u30eb\u30c7\u30a3\u30f3\u30b0
Action.ToggleCurrentFold.Name=\u30ad\u30e3\u30ec\u30c3\u30c8\u5074\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u30c8\u30b0\u30eb\u3059\u308b\u3002
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\u30ad\u30e3\u30ec\u30c3\u30c8\u5074\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u30c8\u30b0\u30eb\u3059\u308b\u3002
Action.CollapseAllFolds.Name=\u5168\u3066\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u6298\u308a\u305f\u305f\u3080
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\u5168\u3066\u306e\u3075\u3049\u308b\u3069\u3092\u6298\u308a\u305f\u305f\u3080
Action.CollapseCommentFolds.Name=\u5168\u3066\u306e\u30b3\u30e1\u30f3\u30c8\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u6298\u308a\u305f\u305f\u3080
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=\u5168\u3066\u306e\u30b3\u30e1\u30f3\u30c8\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u6298\u308a\u305f\u305f\u3080
Action.ExpandAllFolds.Name=\u5168\u3066\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u5c55\u958b\u3059\u308b
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\u5168\u3066\u306e\u30d5\u30a9\u30eb\u30c9\u3092\u5c55\u958b\u3059\u308b

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\ucf54\ub4dc \uac10\ucd94\uae30
Action.ToggleCurrentFold.Name=\ud604\uc7ac \ucf54\ub4dc \uac10\ucd94\uae30 \ud1a0\uae00
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\uce90\ub7ff \uc704\uce58\uc5d0\uc11c \ucf54\ub4dc \uac10\ucd94\uae30\ub97c \ud1a0\uae00\ud569\ub2c8\ub2e4.
Action.CollapseAllFolds.Name=\ubaa8\ub4e0 \ucf54\ub4dc \uac10\ucd94\uae30 \uc811\uae30
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\ubaa8\ub4e0 \ucf54\ub4dc \uac10\ucd94\uae30\ub97c \uc811\uc2b5\ub2c8\ub2e4.
Action.CollapseCommentFolds.Name=\ubaa8\ub4e0 \uc8fc\uc11d \uac10\ucd94\uae30 \uc811\uae30
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=\ubaa8\ub4e0 \uc8fc\uc11d \uac10\ucd94\uae30\ub97c \uc811\uc2b5\ub2c8\ub2e4.
Action.ExpandAllFolds.Name=\ubaa8\ub4e0 \ucf54\ub4dc \uac10\ucd94\uae30 \ud3bc\uce58\uae30
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\ubaa8\ub4e0 \ucf54\ub4dc \uac10\ucd94\uae30\ub97c \ud3bc\uce69\ub2c8\ub2e4.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Toggle Current Fold
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Toggles the fold at the caret position.
Action.CollapseAllFolds.Name=Collapse All Folds
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Collapses all folds.
Action.CollapseCommentFolds.Name=Collapse All Comments
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Collapses all comment folds.
Action.ExpandAllFolds.Name=Expand All Folds
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expands all folds.

View File

@ -1,15 +0,0 @@
ContextMenu.Folding=Zwijanie
Action.ToggleCurrentFold.Name=Reguluj zwini\u0119cie
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Ustawia zwini\u0119cie na pozycji karetki.
Action.CollapseAllFolds.Name=Zwi\u0144 wszystkie zwini\u0119cia
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Zwija wszystkie zwini\u0119cia.
Action.CollapseCommentFolds.Name=Zwi\u0144 wszystkie komentarze
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Zwija wszystkie zwini\u0119cia z komentarzami.
Action.ExpandAllFolds.Name=Rozwi\u0144 zwini\u0119cia
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Rozwija wszystkie zwini\u0119cia.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Dobramento de c\u00f3digo
Action.ToggleCurrentFold.Name=Alternar o dobramento atual
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Alterna o dobramento na posi\u00e7\u00e3o do cursor.
Action.CollapseAllFolds.Name=Recolher o dobramento de c\u00f3digo
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Recolher o dobramento de c\u00f3digo.
Action.CollapseCommentFolds.Name=Recolher o dobramento de coment\u00e1rios
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Recolher o dobramento de coment\u00e1rios.
Action.ExpandAllFolds.Name=Expandir o dobramento de c\u00f3digo
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expandir o dobramento de c\u00f3digo.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\u0421\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435
Action.ToggleCurrentFold.Name=\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0431\u043b\u043e\u043a
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0431\u043b\u043e\u043a\u0430 \u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043a\u0443\u0440\u0441\u043e\u0440\u0430
Action.CollapseAllFolds.Name=\u0421\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\u0421\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0431\u043b\u043e\u043a\u043e\u0432
Action.CollapseCommentFolds.Name=\u0421\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=\u0421\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u0431\u043b\u043e\u043a\u0430
Action.ExpandAllFolds.Name=\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0431\u043b\u043e\u043a\u043e\u0432

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Katlama
Action.ToggleCurrentFold.Name=\u015eu Anki Kat\u0131 Geni\u015flet/Katla
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\u0130\u015faret\u00e7inin bulundu\u011fu kat\u0131 geni\u015fletir/katlar.
Action.CollapseAllFolds.Name=T\u00fcm Katlar\u0131 Katla
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=T\u00fcm katlar\u0131 katlar.
Action.CollapseCommentFolds.Name=T\u00fcm Yorumlar\u0131 Katla
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=T\u00fcm yorumlar\u0131 katlar.
Action.ExpandAllFolds.Name=T\u00fcm Katlar\u0131 Geni\u015flet
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=T\u00fcm katlar\u0131 geni\u015fletir.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=\u6298\u53e0
Action.ToggleCurrentFold.Name=\u6298\u53e0/\u5f00\u542f\u672c\u533a\u6bb5
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=\u6298\u53e0/\u5f00\u542f\u63d2\u5165\u7b26\u6240\u5728\u4f4d\u7f6e.
Action.CollapseAllFolds.Name=\u53d6\u6d88\u6240\u6709\u4ee3\u7801\u6298\u53e0
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=\u53d6\u6d88\u6240\u6709\u4ee3\u7801\u6298\u53e0.
Action.CollapseCommentFolds.Name=\u53d6\u6d88\u6ce8\u91ca\u4ee3\u7801\u6298\u53e0
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=\u53d6\u6d88\u6ce8\u91ca\u4ee3\u7801\u6298\u53e0.
Action.ExpandAllFolds.Name=\u6253\u5f00\u6240\u6709\u4ee3\u7801\u6298\u53e0
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=\u6253\u5f00\u6240\u6709\u4ee3\u7801\u6298\u53e0.

View File

@ -1,14 +0,0 @@
ContextMenu.Folding=Folding
Action.ToggleCurrentFold.Name=Toggle Current Fold
Action.ToggleCurrentFold.Mnemonic=F
Action.ToggleCurrentFold.Desc=Toggles the fold at the caret position.
Action.CollapseAllFolds.Name=Collapse All Folds
Action.CollapseAllFolds.Mnemonic=O
Action.CollapseAllFolds.Desc=Collapses all folds.
Action.CollapseCommentFolds.Name=Collapse All Comments
Action.CollapseCommentFolds.Mnemonic=C
Action.CollapseCommentFolds.Desc=Collapses all comment folds.
Action.ExpandAllFolds.Name=Expand All Folds
Action.ExpandAllFolds.Mnemonic=E
Action.ExpandAllFolds.Desc=Expands all folds.

File diff suppressed because it is too large Load Diff

View File

@ -1,224 +0,0 @@
/*
* 07/28/2008
*
* RtfToText.java - Returns the plain text version of RTF documents.
*
* 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.io.*;
/**
* Gets the plain text version of RTF documents.<p>
*
* This is used by <code>RtfTransferable</code> to return the plain text
* version of the transferable when the receiver does not support RTF.
*
* @author Robert Futrell
* @version 1.0
*/
class RtfToText {
private Reader r;
private StringBuffer sb;
private StringBuffer controlWord;
private int blockCount;
private boolean inControlWord;
/**
* Private constructor.
*
* @param r The reader to read RTF text from.
*/
private RtfToText(Reader r) {
this.r = r;
sb = new StringBuffer();
controlWord = new StringBuffer();
blockCount = 0;
inControlWord = false;
}
/**
* Converts the RTF text read from this converter's <code>Reader</code>
* into plain text. It is the caller's responsibility to close the
* reader after this method is called.
*
* @return The plain text.
* @throws IOException If an IO error occurs.
*/
private String convert() throws IOException {
// Skip over first curly brace as the whole file is in '{' and '}'
int i = r.read();
if (i!='{') {
throw new IOException("Invalid RTF file");
}
while ((i=r.read())!=-1) {
char ch = (char)i;
switch (ch) {
case '{':
if (inControlWord && controlWord.length()==0) { // "\{"
sb.append('{');
controlWord.setLength(0);
inControlWord = false;
}
else {
blockCount++;
}
break;
case '}':
if (inControlWord && controlWord.length()==0) { // "\}"
sb.append('}');
controlWord.setLength(0);
inControlWord = false;
}
else {
blockCount--;
}
break;
case '\\':
if (blockCount==0) {
if (inControlWord) {
if (controlWord.length()==0) { // "\\"
sb.append('\\');
controlWord.setLength(0);
inControlWord = false;
}
else {
endControlWord();
}
}
inControlWord = true;
}
break;
case ' ':
if (blockCount==0) {
if (inControlWord) {
endControlWord();
}
else {
sb.append(' ');
}
}
break;
case '\r':
case '\n':
if (blockCount==0) {
if (inControlWord) {
endControlWord();
}
// Otherwise, ignore
}
break;
default:
if (blockCount==0) {
if (inControlWord) {
controlWord.append(ch);
}
else {
sb.append(ch);
}
}
break;
}
}
return sb.toString();
}
/**
* Ends a control word. Checks whether it is a common one that affects
* the plain text output (such as "<code>par</code>" or "<code>tab</code>")
* and updates the text buffer accordingly.
*/
private void endControlWord() {
String word = controlWord.toString();
if ("par".equals(word)) {
sb.append('\n');
}
else if ("tab".equals(word)) {
sb.append('\t');
}
controlWord.setLength(0);
inControlWord = false;
}
/**
* Converts the contents of the specified byte array representing
* an RTF document into plain text.
*
* @param rtf The byte array representing an RTF document.
* @return The contents of the RTF document, in plain text.
* @throws IOException If an IO error occurs.
*/
public static String getPlainText(byte[] rtf) throws IOException {
return getPlainText(new ByteArrayInputStream(rtf));
}
/**
* Converts the contents of the specified RTF file to plain text.
*
* @param file The RTF file to convert.
* @return The contents of the file, in plain text.
* @throws IOException If an IO error occurs.
*/
public static String getPlainText(File file) throws IOException {
return getPlainText(new BufferedReader(new FileReader(file)));
}
/**
* Converts the contents of the specified input stream to plain text.
* The input stream will be closed when this method returns.
*
* @param in The input stream to convert.
* @return The contents of the stream, in plain text.
* @throws IOException If an IO error occurs.
*/
public static String getPlainText(InputStream in) throws IOException {
return getPlainText(new InputStreamReader(in, "US-ASCII"));
}
/**
* Converts the contents of the specified <code>Reader</code> to plain text.
*
* @param r The <code>Reader</code>.
* @return The contents of the <code>Reader</code>, in plain text.
* @throws IOException If an IO error occurs.
*/
private static String getPlainText(Reader r) throws IOException {
try {
RtfToText converter = new RtfToText(r);
return converter.convert();
} finally {
r.close();
}
}
/**
* Converts the contents of the specified String to plain text.
*
* @param rtf A string whose contents represent an RTF document.
* @return The contents of the String, in plain text.
* @throws IOException If an IO error occurs.
*/
public static String getPlainText(String rtf) throws IOException {
return getPlainText(new StringReader(rtf));
}
}

View File

@ -1,541 +0,0 @@
/*
* 07/28/2008
*
* RtfGenerator.java - Generates RTF via a simple Java API.
*
* 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.Color;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Generates RTF text via a simple Java API.<p>
*
* The following RTF features are supported:
* <ul>
* <li>Fonts
* <li>Font sizes
* <li>Foreground and background colors
* <li>Bold, italic, and underline
* </ul>
*
* The RTF generated isn't really "optimized," but it will do, especially for
* small amounts of text, such as what's common when copy-and-pasting. It
* tries to be sufficient for the use case of copying syntax highlighted
* code:
* <ul>
* <li>It assumes that tokens changing foreground color often is fairly
* common.
* <li>It assumes that background highlighting is fairly uncommon.
* </ul>
*
* @author Robert Futrell
* @version 1.0
*/
public class RtfGenerator {
private List fontList;
private List colorList;
private StringBuffer document;
private boolean lastWasControlWord;
private int lastFontIndex;
private int lastFGIndex;
private boolean lastBold;
private boolean lastItalic;
private int lastFontSize;
private String monospacedFontName;
/**
* Java2D assumes a 72 dpi screen resolution, but on Windows the screen
* resolution is either 96 dpi or 120 dpi, depending on your font display
* settings. This is an attempt to make the RTF generated match the
* size of what's displayed in the RSyntaxTextArea.
*/
private int screenRes;
/**
* The default font size for RTF. This is point size, in half
* points.
*/
private static final int DEFAULT_FONT_SIZE = 12;//24;
/**
* Constructor.
*/
public RtfGenerator() {
fontList = new ArrayList(1); // Usually only 1.
colorList = new ArrayList(1); // Usually only 1.
document = new StringBuffer();
reset();
}
/**
* Adds a newline to the RTF document.
*
* @see #appendToDoc(String, Font, Color, Color)
*/
public void appendNewline() {
document.append("\\par");
document.append('\n'); // Just for ease of reading RTF.
lastWasControlWord = false;
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text The text to append.
* @param f The font of the text. If this is <code>null</code>, the
* default font is used.
* @param fg The foreground of the text. If this is <code>null</code>,
* the default foreground color is used.
* @param bg The background color of the text. If this is
* <code>null</code>, the default background color is used.
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg) {
appendToDoc(text, f, fg, bg, false);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text The text to append.
* @param f The font of the text. If this is <code>null</code>, the
* default font is used.
* @param bg The background color of the text. If this is
* <code>null</code>, the default background color is used.
* @param underline Whether the text should be underlined.
* @see #appendNewline()
*/
public void appendToDocNoFG(String text, Font f, Color bg,
boolean underline) {
appendToDoc(text, f, null, bg, underline, false);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text The text to append.
* @param f The font of the text. If this is <code>null</code>, the
* default font is used.
* @param fg The foreground of the text. If this is <code>null</code>,
* the default foreground color is used.
* @param bg The background color of the text. If this is
* <code>null</code>, the default background color is used.
* @param underline Whether the text should be underlined.
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg,
boolean underline) {
appendToDoc(text, f, fg, bg, underline, true);
}
/**
* Appends styled text to the RTF document being generated.
*
* @param text The text to append.
* @param f The font of the text. If this is <code>null</code>, the
* default font is used.
* @param fg The foreground of the text. If this is <code>null</code>,
* the default foreground color is used.
* @param bg The background color of the text. If this is
* <code>null</code>, the default background color is used.
* @param underline Whether the text should be underlined.
* @param setFG Whether the foreground specified by <code>fg</code> should
* be honored (if it is non-<code>null</code>).
* @see #appendNewline()
*/
public void appendToDoc(String text, Font f, Color fg, Color bg,
boolean underline, boolean setFG) {
if (text!=null) {
// Set font to use, if different from last addition.
int fontIndex = f==null ? 0 : (getFontIndex(fontList, f)+1);
if (fontIndex!=lastFontIndex) {
document.append("\\f").append(fontIndex);
lastFontIndex = fontIndex;
lastWasControlWord = true;
}
// Set styles to use.
if (f!=null) {
int fontSize = fixFontSize(f.getSize2D()); // Half points
if (fontSize!=lastFontSize) {
document.append("\\fs").append(fontSize);
lastFontSize = fontSize;
lastWasControlWord = true;
}
if (f.isBold()!=lastBold) {
document.append(lastBold ? "\\b0" : "\\b");
lastBold = !lastBold;
lastWasControlWord = true;
}
if (f.isItalic()!=lastItalic) {
document.append(lastItalic ? "\\i0" : "\\i");
lastItalic = !lastItalic;
lastWasControlWord = true;
}
}
else { // No font specified - assume neither bold nor italic.
if (lastFontSize!=DEFAULT_FONT_SIZE) {
document.append("\\fs").append(DEFAULT_FONT_SIZE);
lastFontSize = DEFAULT_FONT_SIZE;
lastWasControlWord = true;
}
if (lastBold) {
document.append("\\b0");
lastBold = false;
lastWasControlWord = true;
}
if (lastItalic) {
document.append("\\i0");
lastItalic = false;
lastWasControlWord = true;
}
}
if (underline) {
document.append("\\ul");
lastWasControlWord = true;
}
// Set the foreground color.
if (setFG) {
int fgIndex = 0;
if (fg!=null) { // null => fg color index 0
fgIndex = getIndex(colorList, fg)+1;
}
if (fgIndex!=lastFGIndex) {
document.append("\\cf").append(fgIndex);
lastFGIndex = fgIndex;
lastWasControlWord = true;
}
}
// Set the background color.
if (bg!=null) {
int pos = getIndex(colorList, bg);
document.append("\\highlight").append(pos+1);
lastWasControlWord = true;
}
if (lastWasControlWord) {
document.append(' '); // Delimiter
lastWasControlWord = false;
}
escapeAndAdd(document, text);
// Reset everything that was set for this text fragment.
if (bg!=null) {
document.append("\\highlight0");
lastWasControlWord = true;
}
if (underline) {
document.append("\\ul0");
lastWasControlWord = true;
}
}
}
/**
* Appends some text to a buffer, with special care taken for special
* characters as defined by the RTF spec:
*
* <ul>
* <li>All tab characters are replaced with the string
* "<code>\tab</code>"
* <li>'\', '{' and '}' are changed to "\\", "\{" and "\}"
* </ul>
*
* @param text The text to append (with tab chars substituted).
* @param sb The buffer to append to.
*/
private final void escapeAndAdd(StringBuffer sb, String text) {
// TODO: On the move to 1.5 use StringBuffer append() overloads that
// can take a CharSequence and a range of that CharSequence to speed
// things up.
//int last = 0;
int count = text.length();
for (int i=0; i<count; i++) {
char ch = text.charAt(i);
switch (ch) {
case '\t':
// Micro-optimization: for syntax highlighting with
// tab indentation, there are often multiple tabs
// back-to-back at the start of lines, so don't put
// spaces between each "\tab".
sb.append("\\tab");
while ((++i<count) && text.charAt(i)=='\t') {
sb.append("\\tab");
}
sb.append(' ');
i--; // We read one too far.
break;
case '\\':
case '{':
case '}':
sb.append('\\').append(ch);
break;
default:
sb.append(ch);
break;
}
}
}
/**
* Returns a font point size adjusted for the current screen resolution.
* Java2D assumes 72 dpi. On systems with larger dpi (Windows, GTK, etc.),
* font rendering will appear to small if we simply return a Java "Font"
* object's getSize() value. We need to adjust it for the screen
* resolution.
*
* @param pointSize A Java Font's point size, as returned from
* <code>getSize2D()</code>.
* @return The font point size, adjusted for the current screen resolution.
* This will allow other applications to render fonts the same
* size as they appear in the Java application.
*/
private int fixFontSize(float pointSize) {
if (screenRes!=72) { // Java2D assumes 72 dpi
pointSize = (int)Math.round(pointSize*screenRes/72.0);
}
return (int)pointSize;
}
private String getColorTableRtf() {
// Example:
// "{\\colortbl ;\\red255\\green0\\blue0;\\red0\\green0\\blue255; }"
StringBuffer sb = new StringBuffer();
sb.append("{\\colortbl ;");
for (int i=0; i<colorList.size(); i++) {
Color c = (Color)colorList.get(i);
sb.append("\\red").append(c.getRed());
sb.append("\\green").append(c.getGreen());
sb.append("\\blue").append(c.getBlue());
sb.append(';');
}
sb.append("}");
return sb.toString();
}
/**
* Returns the index of the specified font in a list of fonts. This
* method only checks for a font by its family name; its attributes such
* as bold and italic are ignored.<p>
*
* If the font is not in the list, it is added, and its new index is
* returned.
*
* @param list The list (possibly) containing the font.
* @param font The font to get the index of.
* @return The index of the font.
*/
private static int getFontIndex(List list, Font font) {
String fontName = font.getFamily();
for (int i=0; i<list.size(); i++) {
Font font2 = (Font)list.get(i);
if (font2.getFamily().equals(fontName)) {
return i;
}
}
list.add(font);
return list.size()-1;
}
private String getFontTableRtf() {
// Example:
// "{\\fonttbl{\\f0\\fmodern\\fcharset0 Courier;}}"
StringBuffer sb = new StringBuffer();
// Workaround for text areas using the Java logical font "Monospaced"
// by default. There's no way to know what it's mapped to, so we
// just search for a monospaced font on the system.
String monoFamilyName = getMonospacedFontName();
sb.append("{\\fonttbl{\\f0\\fnil\\fcharset0 " + monoFamilyName + ";}");
for (int i=0; i<fontList.size(); i++) {
Font f = (Font)fontList.get(i);
String familyName = f.getFamily();
if (familyName.equals("Monospaced")) {
familyName = monoFamilyName;
}
sb.append("{\\f").append(i+1).append("\\fnil\\fcharset0 ");
sb.append(familyName).append(";}");
}
sb.append('}');
return sb.toString();
}
/**
* Returns the index of the specified item in a list. If the item
* is not in the list, it is added, and its new index is returned.
*
* @param list The list (possibly) containing the item.
* @param item The item to get the index of.
* @return The index of the item.
*/
private static int getIndex(List list, Object item) {
int pos = list.indexOf(item);
if (pos==-1) {
list.add(item);
pos = list.size()-1;
}
return pos;
}
/**
* Try to pick a monospaced font installed on this system. We try
* to check for monospaced fonts that are commonly installed on
* different OS's. This information was gleaned from
* http://www.codestyle.org/css/font-family/sampler-Monospace.shtml.
*
* @return The name of a monospaced font.
*/
private String getMonospacedFontName() {
if (monospacedFontName==null) {
GraphicsEnvironment ge = GraphicsEnvironment.
getLocalGraphicsEnvironment();
String[] familyNames = ge.getAvailableFontFamilyNames();
Arrays.sort(familyNames);
boolean windows = System.getProperty("os.name").toLowerCase().
indexOf("windows")>=0;
// "Monaco" is the "standard" monospaced font on OS X. We'll
// check for it first so on Macs we don't get stuck with the
// uglier Courier New. It'll look funny on Windows though, so
// don't pick it if we're on Windows.
// It's found on Windows 1.76% of the time, OS X 96.73%
// of the time, and UNIX 00.00% (?) of the time.
if (!windows && Arrays.binarySearch(familyNames, "Monaco")>=0) {
monospacedFontName = "Monaco";
}
// "Courier New" is found on Windows 96.48% of the time,
// OS X 92.38% of the time, and UNIX 61.95% of the time.
else if (Arrays.binarySearch(familyNames, "Courier New")>=0) {
monospacedFontName = "Courier New";
}
// "Courier" is found on Windows ??.??% of the time,
// OS X 96.27% of the time, and UNIX 74.04% of the time.
else if (Arrays.binarySearch(familyNames, "Courier")>=0) {
monospacedFontName = "Courier";
}
// "Nimbus Mono L" is on Windows 00.00% (?) of the time,
// OS X 00.00% (?) of the time, but on UNIX 88.79% of the time.
else if (Arrays.binarySearch(familyNames, "Nimbus Mono L")>=0) {
monospacedFontName = "Nimbus Mono L";
}
// "Lucida Sans Typewriter" is on Windows 49.37% of the time,
// OS X 90.43% of the time, and UNIX 00.00% (?) of the time.
else if (Arrays.binarySearch(familyNames, "Lucida Sans Typewriter")>=0) {
monospacedFontName = "Lucida Sans Typewriter";
}
// "Bitstream Vera Sans Mono" is on Windows 29.81% of the time,
// OS X 25.53% of the time, and UNIX 80.71% of the time.
else if (Arrays.binarySearch(familyNames, "Bitstream Vera Sans Mono")>=0) {
monospacedFontName = "Bitstream Vera Sans Mono";
}
// Windows: 34.16% of the time, OS X: 00.00% (?) of the time,
// UNIX: 33.92% of the time.
if (monospacedFontName==null) {
monospacedFontName = "Terminal";
}
}
return monospacedFontName;
}
/**
* Returns the RTF document created by this generator.
*
* @return The RTF document, as a <code>String</code>.
*/
public String getRtf() {
StringBuffer sb = new StringBuffer();
sb.append("{");
// Header
sb.append("\\rtf1\\ansi\\ansicpg1252");
sb.append("\\deff0"); // First font in font table is the default
sb.append("\\deflang1033");
sb.append("\\viewkind4"); // "Normal" view
sb.append("\\uc\\pard\\f0");
sb.append("\\fs20"); // Font size in half-points (default 24)
sb.append(getFontTableRtf()).append('\n');
sb.append(getColorTableRtf()).append('\n');
// Content
sb.append(document);
sb.append("}");
//System.err.println("*** " + sb.length());
return sb.toString();
}
/**
* Resets this generator. All document information and content is
* cleared.
*/
public void reset() {
fontList.clear();
colorList.clear();
document.setLength(0);
lastWasControlWord = false;
lastFontIndex = 0;
lastFGIndex = 0;
lastBold = false;
lastItalic = false;
lastFontSize = DEFAULT_FONT_SIZE;
screenRes = Toolkit.getDefaultToolkit().getScreenResolution();
}
}

View File

@ -1,91 +0,0 @@
/*
* 07/28/2008
*
* RtfTransferable.java - Used during drag-and-drop to represent RTF text.
*
* 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.datatransfer.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
/**
* Object used during copy/paste and DnD operations to represent RTF text.
* It can return the text being moved as either RTF or plain text. This
* class is basically the same as
* <code>java.awt.datatransfer.StringSelection</code>, except that it can also
* return the text as RTF.
*
* @author Robert Futrell
* @version 1.0
*/
class RtfTransferable implements Transferable {
/**
* The RTF data, in bytes (the RTF is 7-bit ascii).
*/
private byte[] data;
/**
* The "flavors" the text can be returned as.
*/
private final DataFlavor[] FLAVORS = {
new DataFlavor("text/rtf", "RTF"),
DataFlavor.stringFlavor,
DataFlavor.plainTextFlavor // deprecated
};
/**
* Constructor.
*
* @param data The RTF data.
*/
public RtfTransferable(byte[] data) {
this.data = data;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (flavor.equals(FLAVORS[0])) { // RTF
return new ByteArrayInputStream(data==null ? new byte[0] : data);
}
else if (flavor.equals(FLAVORS[1])) { // stringFlavor
return data==null ? "" : RtfToText.getPlainText(data);
}
else if (flavor.equals(FLAVORS[2])) { // plainTextFlavor (deprecated)
String text = ""; // Valid if data==null
if (data!=null) {
text = RtfToText.getPlainText(data);
}
return new StringReader(text);
}
else {
throw new UnsupportedFlavorException(flavor);
}
}
public DataFlavor[] getTransferDataFlavors() {
return (DataFlavor[])FLAVORS.clone();
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
for (int i=0; i<FLAVORS.length; i++) {
if (flavor.equals(FLAVORS[i])) {
return true;
}
}
return false;
}
}

View File

@ -1,117 +0,0 @@
/*
* 09/13/2005
*
* SquiggleUnderlineHighlightPainter.java - Highlighter that draws a squiggle
* underline under "highlighted" text, similar to error markers in Microsoft
* Visual Studio or Eclipse.
*
* 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.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import javax.swing.text.View;
/**
* Highlight painter that paints a squiggly underline underneath text, similar
* to what popular IDE's such as Visual Studio and Eclipse do to indicate
* errors, warnings, etc.<p>
*
* This class must be used as a <code>LayerPainter</code>.
*
* @author Robert Futrell
* @version 1.0
*/
public class SquiggleUnderlineHighlightPainter
extends ChangeableColorHighlightPainter {
private static final int AMT = 2;
/**
* Constructor.
*
* @param color The color of the squiggle. This cannot be
* <code>null</code>.
*/
public SquiggleUnderlineHighlightPainter(Color color) {
super(color);
setColor(color);
}
/**
* Paints a portion of a highlight.
*
* @param g the graphics context
* @param offs0 the starting model offset >= 0
* @param offs1 the ending model offset >= offs1
* @param bounds the bounding box of the view, which is not
* necessarily the region to paint.
* @param c the editor
* @param view View painting for
* @return region drawing occurred in
*/
public Shape paintLayer(Graphics g, int offs0, int offs1,
Shape bounds, JTextComponent c, View view) {
g.setColor(getColor());
if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
// Contained in view, can just use bounds.
Rectangle alloc;
if (bounds instanceof Rectangle)
alloc = (Rectangle)bounds;
else
alloc = bounds.getBounds();
paintSquiggle(g, alloc);
return alloc;
}
// Otherwise, should only render part of View.
try {
// --- determine locations ---
Shape shape = view.modelToView(offs0, Position.Bias.Forward,
offs1,Position.Bias.Backward,
bounds);
Rectangle r = (shape instanceof Rectangle) ?
(Rectangle)shape : shape.getBounds();
paintSquiggle(g, r);
return r;
} catch (BadLocationException e) {
e.printStackTrace(); // can't render
}
// Only if exception
return null;
}
/**
* Paints a squiggle underneath text in the specified rectangle.
*
* @param g The graphics context with which to paint.
* @param r The rectangle containing the text.
*/
protected void paintSquiggle(Graphics g, Rectangle r) {
int x = r.x;
int y = r.y + r.height - 1;
int delta = -AMT;
while (x<r.x+r.width) {
g.drawLine(x,y, x+AMT,y+delta);
y += delta;
delta = -delta;
x += AMT;
}
}
}

View File

@ -1,192 +0,0 @@
/*
* 08/06/2004
*
* Style.java - A set of traits for a particular token type to use while
* painting.
*
* 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.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import javax.swing.JPanel;
/**
* The color and style information for a token type. Each token type in an
* <code>RSyntaxTextArea</code> has a corresponding <code>Style</code>; this
* <code>Style</code> tells us the following things:
*
* <ul>
* <li>What foreground color to use for tokens of this type.</li>
* <li>What background color to use.</li>
* <li>The font to use.</li>
* <li>Whether the token should be underlined.</li>
* </ul>
*
* @author Robert Futrell
* @version 0.6
*/
public class Style implements Cloneable {
public static final Color DEFAULT_FOREGROUND = Color.BLACK;
public static final Color DEFAULT_BACKGROUND = null;
public static final Font DEFAULT_FONT = null;
public Color foreground;
public Color background;
public boolean underline;
public Font font;
FontMetrics fontMetrics;
/**
* Creates a new style defaulting to black foreground, no
* background, and no styling.
*/
public Style() {
this(DEFAULT_FOREGROUND);
}
/**
* Creates a new style with the specified foreground and no styling.
*
* @param fg The foreground color to use.
*/
public Style(Color fg) {
this(fg, DEFAULT_BACKGROUND);
}
/**
* Creates a new style with the specified colors and no styling.
*
* @param fg The foreground color to use.
* @param bg The background color to use.
*/
public Style(Color fg, Color bg) {
this(fg, bg, DEFAULT_FONT);
}
/**
* Creates a new style.
*
* @param fg The foreground color to use.
* @param bg The background color to use.
* @param font The font for this syntax scheme.
*/
public Style(Color fg, Color bg, Font font) {
this(fg, bg, font, false);
}
/**
* Creates a new style.
*
* @param fg The foreground color to use.
* @param bg The background color to use.
* @param font The font for this syntax scheme.
* @param underline Whether or not to underline tokens with this style.
*/
public Style(Color fg, Color bg, Font font, boolean underline) {
foreground = fg;
background = bg;
this.font = font;
this.underline = underline;
this.fontMetrics = font==null ? null :
new JPanel().getFontMetrics(font); // Default, no rendering hints!
}
/**
* Returns whether or not two (possibly <code>null</code>) objects are
* equal.
*/
private boolean areEqual(Object o1, Object o2) {
return (o1==null && o2==null) || (o1!=null && o1.equals(o2));
}
/**
* Returns a deep copy of this object.
*
* @return The copy.
*/
public Object clone() {
Style clone = null;
try {
clone = (Style)super.clone();
} catch (CloneNotSupportedException cnse) { // Never happens
cnse.printStackTrace();
return null;
}
clone.foreground = foreground;
clone.background = background;
clone.font = font;
clone.underline = underline;
clone.fontMetrics = fontMetrics;
return clone;
}
/**
* Returns whether or not two syntax schemes are equal.
*
* @param o2 The object with which to compare this syntax scheme.
* @return Whether or not these two syntax schemes represent the same
* scheme.
*/
public boolean equals(Object o2) {
if (o2 instanceof Style) {
Style ss2 = (Style)o2;
if (this.underline==ss2.underline &&
areEqual(foreground, ss2.foreground) &&
areEqual(background, ss2.background) &&
areEqual(font, ss2.font) &&
areEqual(fontMetrics, ss2.fontMetrics))
return true;
}
return false;
}
/**
* Computes the hash code to use when adding this syntax scheme to
* hash tables.<p>
*
* This method is implemented, since {@link #equals(Object)} is implemented,
* to keep FindBugs happy.
*
* @return The hash code.
*/
public int hashCode() {
int hashCode = underline ? 1 : 0;
if (foreground!=null) {
hashCode ^= foreground.hashCode();
}
if (background!=null) {
hashCode ^= background.hashCode();
}
return hashCode;
}
/**
* Returns a string representation of this style.
*
* @return A string representation of this style.
*/
public String toString() {
return "[Style: foreground: " + foreground +
", background: " + background + ", underline: " +
underline + ", font: " + font + "]";
}
}

View File

@ -1,247 +0,0 @@
/*
* 03/08/2004
*
* SyntaxConstants.java - Constants used by RSyntaxTextArea and friends.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* Constants that define the different programming languages understood by
* <code>RSyntaxTextArea</code>. These constants are the values you can pass
* to {@link RSyntaxTextArea#setSyntaxEditingStyle(String)} to get syntax
* highlighting.<p>
*
* By default, all <code>RSyntaxTextArea</code>s can render all of these
* languages, but this can be changed (the list can be augmented or completely
* overwritten) on a per-text area basis. What languages can be rendered is
* actually managed by the {@link TokenMakerFactory} installed on the text
* area's {@link RSyntaxDocument}. By default, all
* <code>RSyntaxDocumenet</code>s have a factory installed capable of handling
* all of these languages.
*
* @author Robert Futrell
* @version 1.0
*/
public interface SyntaxConstants {
/**
* Style meaning don't syntax highlight anything.
*/
public static final String SYNTAX_STYLE_NONE = "text/plain";
/**
* Style for highlighting ActionScript.
*/
public static final String SYNTAX_STYLE_ACTIONSCRIPT = "text/actionscript";
/**
* Style for highlighting x86 assembler.
*/
public static final String SYNTAX_STYLE_ASSEMBLER_X86 = "text/asm";
/**
* Style for highlighting BBCode.
*/
public static final String SYNTAX_STYLE_BBCODE = "text/bbcode";
/**
* Style for highlighting C.
*/
public static final String SYNTAX_STYLE_C = "text/c";
/**
* Style for highlighting Clojure.
*/
public static final String SYNTAX_STYLE_CLOJURE = "text/clojure";
/**
* Style for highlighting C++.
*/
public static final String SYNTAX_STYLE_CPLUSPLUS = "text/cpp";
/**
* Style for highlighting C#.
*/
public static final String SYNTAX_STYLE_CSHARP = "text/cs";
/**
* Style for highlighting CSS.
*/
public static final String SYNTAX_STYLE_CSS = "text/css";
/**
* Style for highlighting Delphi/Pascal.
*/
public static final String SYNTAX_STYLE_DELPHI = "text/delphi";
/**
* Style for highlighting DTD files.
*/
public static final String SYNTAX_STYLE_DTD = "text/dtd";
/**
* Style for highlighting Fortran.
*/
public static final String SYNTAX_STYLE_FORTRAN = "text/fortran";
/**
* Style for highlighting Groovy.
*/
public static final String SYNTAX_STYLE_GROOVY = "text/groovy";
/**
* Style for highlighting HTML.
*/
public static final String SYNTAX_STYLE_HTML = "text/html";
/**
* Style for highlighting Java.
*/
public static final String SYNTAX_STYLE_JAVA = "text/java";
/**
* Style for highlighting JavaScript.
*/
public static final String SYNTAX_STYLE_JAVASCRIPT = "text/javascript";
/**
* Style for highlighting JSON.
*/
public static final String SYNTAX_STYLE_JSON = "text/json";
/**
* Style for highlighting JSP.
*/
public static final String SYNTAX_STYLE_JSP = "text/jsp";
/**
* Style for highlighting LaTeX.
*/
public static final String SYNTAX_STYLE_LATEX = "text/latex";
/**
* Style for highlighting Lisp.
*/
public static final String SYNTAX_STYLE_LISP = "text/lisp";
/**
* Style for highlighting Lua.
*/
public static final String SYNTAX_STYLE_LUA = "text/lua";
/**
* Style for highlighting makefiles.
*/
public static final String SYNTAX_STYLE_MAKEFILE = "text/makefile";
/**
* Style for highlighting MXML.
*/
public static final String SYNTAX_STYLE_MXML = "text/mxml";
/**
* Style for highlighting NSIS install scripts.
*/
public static final String SYNTAX_STYLE_NSIS = "text/nsis";
/**
* Style for highlighting Perl.
*/
public static final String SYNTAX_STYLE_PERL = "text/perl";
/**
* Style for highlighting PHP.
*/
public static final String SYNTAX_STYLE_PHP = "text/php";
/**
* Style for highlighting properties files.
*/
public static final String SYNTAX_STYLE_PROPERTIES_FILE = "text/properties";
/**
* Style for highlighting Python.
*/
public static final String SYNTAX_STYLE_PYTHON = "text/python";
/**
* Style for highlighting Ruby.
*/
public static final String SYNTAX_STYLE_RUBY = "text/ruby";
/**
* Style for highlighting SAS keywords.
*/
public static final String SYNTAX_STYLE_SAS = "text/sas";
/**
* Style for highlighting Scala.
*/
public static final String SYNTAX_STYLE_SCALA = "text/scala";
/**
* Style for highlighting SQL.
*/
public static final String SYNTAX_STYLE_SQL = "text/sql";
/**
* Style for highlighting Tcl.
*/
public static final String SYNTAX_STYLE_TCL = "text/tcl";
/**
* Style for highlighting UNIX shell keywords.
*/
public static final String SYNTAX_STYLE_UNIX_SHELL = "text/unix";
/**
* Style for highlighting Windows batch files.
*/
public static final String SYNTAX_STYLE_WINDOWS_BATCH = "text/bat";
/**
* Style for highlighting XML.
*/
public static final String SYNTAX_STYLE_XML = "text/xml";
}

View File

@ -1,662 +0,0 @@
/*
* 02/26/2004
*
* SyntaxScheme.java - The set of colors and tokens used by an RSyntaxTextArea
* to color tokens.
*
* 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.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import javax.swing.text.StyleContext;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* The set of colors and styles used by an <code>RSyntaxTextArea</code> to
* color tokens. You can use this class to programmatically set the fonts
* and colors used in an RSyntaxTextArea, but for more powerful, externalized
* control, consider using {@link Theme}s instead.
*
* @author Robert Futrell
* @version 1.0
* @see Theme
*/
public class SyntaxScheme implements Cloneable, TokenTypes {
private Style[] styles;
private static final String VERSION = "*ver1";
/**
* Creates a color scheme that either has all color values set to
* a default value or set to <code>null</code>.
*
* @param useDefaults If <code>true</code>, all color values will
* be set to default colors; if <code>false</code>, all colors
* will be initially <code>null</code>.
*/
public SyntaxScheme(boolean useDefaults) {
styles = new Style[NUM_TOKEN_TYPES];
if (useDefaults) {
restoreDefaults(null);
}
}
/**
* Creates a default color scheme.
*
* @param baseFont The base font to use. Keywords will be a bold version
* of this font, and comments will be an italicized version of this
* font.
*/
public SyntaxScheme(Font baseFont) {
this(baseFont, true);
}
/**
* Creates a default color scheme.
*
* @param baseFont The base font to use. Keywords will be a bold version
* of this font, and comments will be an italicized version of this
* font.
* @param fontStyles Whether bold and italic should be used in the scheme
* (vs. all tokens using a plain font).
*/
public SyntaxScheme(Font baseFont, boolean fontStyles) {
styles = new Style[NUM_TOKEN_TYPES];
restoreDefaults(baseFont, fontStyles);
}
/**
* Changes the "base font" for this syntax scheme. This is called by
* <code>RSyntaxTextArea</code> when its font changes via
* <code>setFont()</code>. This looks for tokens that use a derivative of
* the text area's old font (but bolded and/or italicized) and make them
* use the new font with those stylings instead. This is desirable because
* most programmers prefer a single font to be used in their text editor,
* but might want bold (say for keywords) or italics.
*
* @param old The old font of the text area.
* @param font The new font of the text area.
*/
void changeBaseFont(Font old, Font font) {
for (int i=0; i<styles.length; i++) {
Style style = styles[i];
if (style!=null && style.font!=null) {
if (style.font.getFamily().equals(old.getFamily()) &&
style.font.getSize()==old.getSize()) {
int s = style.font.getStyle(); // Keep bold or italic
StyleContext sc = StyleContext.getDefaultStyleContext();
style.font= sc.getFont(font.getFamily(), s, font.getSize());
}
}
}
}
/**
* Returns a deep copy of this color scheme.
*
* @return The copy.
*/
public Object clone() {
SyntaxScheme shcs = null;
try {
shcs = (SyntaxScheme)super.clone();
} catch (CloneNotSupportedException cnse) { // Never happens
cnse.printStackTrace();
return null;
}
shcs.styles = new Style[NUM_TOKEN_TYPES];
for (int i=0; i<NUM_TOKEN_TYPES; i++) {
Style s = styles[i];
if (s!=null) {
shcs.styles[i] = (Style)s.clone();
}
}
return shcs;
}
/**
* Tests whether this color scheme is the same as another color scheme.
*
* @param otherScheme The color scheme to compare to.
* @return <code>true</code> if this color scheme and
* <code>otherScheme</code> are the same scheme;
* <code>false</code> otherwise.
*/
public boolean equals(Object otherScheme) {
// No need for null check; instanceof takes care of this for us,
// i.e. "if (!(null instanceof Foo))" evaluates to "true".
if (!(otherScheme instanceof SyntaxScheme)) {
return false;
}
Style[] otherSchemes = ((SyntaxScheme)otherScheme).styles;
int length = styles.length;
for (int i=0; i<length; i++) {
if (styles[i]==null) {
if (otherSchemes[i]!=null) {
return false;
}
}
else if (!styles[i].equals(otherSchemes[i])) {
return false;
}
}
return true;
}
/**
* Returns a hex string representing an RGB color, of the form
* <code>"$rrggbb"</code>.
*
* @param c The color.
* @return The string representation of the color.
*/
private static final String getHexString(Color c) {
return "$" + Integer.toHexString((c.getRGB() & 0xffffff)+0x1000000).
substring(1);
}
/**
* Returns the specified style.
*
* @param index The index of the style.
* @return The style.
* @see #setStyle(int, Style)
* @see #getStyleCount()
*/
public Style getStyle(int index) {
return styles[index];
}
/**
* Returns the number of styles.
*
* @return The number of styles.
* @see #getStyle(int)
*/
public int getStyleCount() {
return styles.length;
}
/**
* This is implemented to be consistent with {@link #equals(Object)}.
* This is a requirement to keep FindBugs happy.
*
* @return The hash code for this object.
*/
public int hashCode() {
// Keep me fast. Iterating over *all* syntax schemes contained is
// probably much slower than a "bad" hash code here.
int hashCode = 0;
int count = styles.length;
for (int i=0; i<count; i++) {
if (styles[i]!=null) {
hashCode ^= styles[i].hashCode();
break;
}
}
return hashCode;
}
/**
* Loads a syntax scheme from an input stream.
*
* @param baseFont The font to use as the "base" for the syntax scheme.
* If this is <code>null</code>, a default monospaced font is used.
* @param in The stream to load from. It is up to the caller to close this
* stream when they are done.
* @return The syntax scheme.
* @throws IOException If an IO error occurs.
*/
public static SyntaxScheme load(Font baseFont, InputStream in)
throws IOException {
if (baseFont==null) {
baseFont = RSyntaxTextArea.getDefaultFont();
}
return XmlParser.load(baseFont, in);
}
/**
* Loads a syntax highlighting color scheme from a string created from
* <code>toCommaSeparatedString</code>. This method is useful for saving
* and restoring color schemes.
*
* @param string A string generated from {@link #toCommaSeparatedString()}.
* @return A color scheme.
*/
public static SyntaxScheme loadFromString(String string) {
SyntaxScheme scheme = new SyntaxScheme(true);
try {
if (string!=null) {
String[] tokens = string.split(",", -1);
// Check the version string, use defaults if incompatible
if (tokens.length==0 || !VERSION.equals(tokens[0])) {
return scheme; // Still set to defaults
}
int tokenTypeCount = NUM_TOKEN_TYPES;
int tokenCount = tokenTypeCount*7 + 1; // Version string
if (tokens.length!=tokenCount) {
throw new Exception(
"Not enough tokens in packed color scheme: expected " +
tokenCount + ", found " + tokens.length);
}
// Use StyleContext to create fonts to get composite fonts for
// Asian glyphs.
StyleContext sc = StyleContext.getDefaultStyleContext();
// Loop through each token style. Format:
// "index,(fg|-),(bg|-),(t|f),((font,style,size)|(-,,))"
for (int i=0; i<tokenTypeCount; i++) {
int pos = i*7 + 1;
int integer = Integer.parseInt(tokens[pos]); // == i
if (integer!=i)
throw new Exception("Expected " + i + ", found " +
integer);
Color fg = null; String temp = tokens[pos+1];
if (!"-".equals(temp)) { // "-" => keep fg as null
fg = stringToColor(temp);
}
Color bg = null; temp = tokens[pos+2];
if (!"-".equals(temp)) { // "-" => keep bg as null
bg = stringToColor(temp);
}
// Check for "true" or "false" since we don't want to
// accidentally suck in an int representing the next
// packed color, and any string != "true" means false.
temp = tokens[pos+3];
if (!"t".equals(temp) && !"f".equals(temp))
throw new Exception("Expected 't' or 'f', found " + temp);
boolean underline = "t".equals(temp);
Font font = null;
String family = tokens[pos+4];
if (!"-".equals(family)) {
font = sc.getFont(family,
Integer.parseInt(tokens[pos+5]), // style
Integer.parseInt(tokens[pos+6])); // size
}
scheme.styles[i] = new Style(fg, bg, font, underline);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return scheme;
}
void refreshFontMetrics(Graphics2D g2d) {
// It is assumed that any rendering hints are already applied to g2d.
for (int i=0; i<styles.length; i++) {
Style s = styles[i];
if (s!=null) {
s.fontMetrics = s.font==null ? null :
g2d.getFontMetrics(s.font);
}
}
}
/**
* Restores all colors and fonts to their default values.
*
* @param baseFont The base font to use when creating this scheme. If
* this is <code>null</code>, then a default monospaced font is
* used.
*/
public void restoreDefaults(Font baseFont) {
restoreDefaults(baseFont, true);
}
/**
* Restores all colors and fonts to their default values.
*
* @param baseFont The base font to use when creating this scheme. If
* this is <code>null</code>, then a default monospaced font is
* used.
* @param fontStyles Whether bold and italic should be used in the scheme
* (vs. all tokens using a plain font).
*/
public void restoreDefaults(Font baseFont, boolean fontStyles) {
// Colors used by tokens.
Color comment = new Color(0,128,0);
Color docComment = new Color(164,0,0);
Color keyword = Color.BLUE;
Color function = new Color(173,128,0);
Color preprocessor = new Color(128,64,64);
Color regex = new Color(0,128,164);
Color variable = new Color(255,153,0);
Color literalNumber = new Color(100,0,200);
Color literalString = new Color(220,0,156);
Color error = new Color(148,148,0);
// (Possible) special font styles for keywords and comments.
if (baseFont==null) {
baseFont = RSyntaxTextArea.getDefaultFont();
}
Font commentFont = baseFont;
Font keywordFont = baseFont;
if (fontStyles) {
// WORKAROUND for Sun JRE bug 6282887 (Asian font bug in 1.4/1.5)
// That bug seems to be hidden now, see 6289072 instead.
StyleContext sc = StyleContext.getDefaultStyleContext();
Font boldFont = sc.getFont(baseFont.getFamily(), Font.BOLD,
baseFont.getSize());
Font italicFont = sc.getFont(baseFont.getFamily(), Font.ITALIC,
baseFont.getSize());
commentFont = italicFont;//baseFont.deriveFont(Font.ITALIC);
keywordFont = boldFont;//baseFont.deriveFont(Font.BOLD);
}
styles[COMMENT_EOL] = new Style(comment, null, commentFont);
styles[COMMENT_MULTILINE] = new Style(comment, null, commentFont);
styles[COMMENT_DOCUMENTATION] = new Style(docComment, null, commentFont);
styles[COMMENT_KEYWORD] = new Style(new Color(255,152,0), null, commentFont);
styles[COMMENT_MARKUP] = new Style(Color.gray, null, commentFont);
styles[RESERVED_WORD] = new Style(keyword, null, keywordFont);
styles[RESERVED_WORD_2] = new Style(keyword, null, keywordFont);
styles[FUNCTION] = new Style(function);
styles[LITERAL_BOOLEAN] = new Style(literalNumber);
styles[LITERAL_NUMBER_DECIMAL_INT] = new Style(literalNumber);
styles[LITERAL_NUMBER_FLOAT] = new Style(literalNumber);
styles[LITERAL_NUMBER_HEXADECIMAL] = new Style(literalNumber);
styles[LITERAL_STRING_DOUBLE_QUOTE] = new Style(literalString);
styles[LITERAL_CHAR] = new Style(literalString);
styles[LITERAL_BACKQUOTE] = new Style(literalString);
styles[DATA_TYPE] = new Style(new Color(0,128,128));
styles[VARIABLE] = new Style(variable);
styles[REGEX] = new Style(regex);
styles[ANNOTATION] = new Style(Color.gray);
styles[IDENTIFIER] = new Style(null);
styles[WHITESPACE] = new Style(Color.gray);
styles[SEPARATOR] = new Style(Color.RED);
styles[OPERATOR] = new Style(preprocessor);
styles[PREPROCESSOR] = new Style(Color.gray);
styles[MARKUP_TAG_DELIMITER] = new Style(Color.RED);
styles[MARKUP_TAG_NAME] = new Style(Color.BLUE);
styles[MARKUP_TAG_ATTRIBUTE] = new Style(new Color(63,127,127));
styles[MARKUP_TAG_ATTRIBUTE_VALUE]= new Style(literalString);
styles[MARKUP_PROCESSING_INSTRUCTION] = new Style(preprocessor);
styles[MARKUP_CDATA] = new Style(variable);
styles[ERROR_IDENTIFIER] = new Style(error);
styles[ERROR_NUMBER_FORMAT] = new Style(error);
styles[ERROR_STRING_DOUBLE] = new Style(error);
styles[ERROR_CHAR] = new Style(error);
}
/**
* Sets a style to use when rendering a token type.
*
* @param type The token type.
* @param style The style for the token type.
* @see #getStyle(int)
*/
public void setStyle(int type, Style style) {
styles[type] = style;
}
/**
* Returns the color represented by a string. If the first char in the
* string is '<code>$</code>', it is assumed to be in hex, otherwise it is
* assumed to be decimal. So, for example, both of these:
* <pre>
* "$00ff00"
* "65280"
* </pre>
* will return <code>new Color(0, 255, 0)</code>.
*
* @param s The string to evaluate.
* @return The color.
*/
private static final Color stringToColor(String s) {
// Check for decimal as well as hex, for backward
// compatibility (fix from GwynEvans on forums)
char ch = s.charAt(0);
return new Color((ch=='$' || ch=='#') ?
Integer.parseInt(s.substring(1),16) :
Integer.parseInt(s));
}
/**
* Returns this syntax highlighting scheme as a comma-separated list of
* values as follows:
* <ul>
* <li>If a color is non-null, it is added as a 24-bit integer
* of the form <code>((r<<16) | (g<<8) | (b))</code>; if it is
* <code>null</code>, it is added as "<i>-,</i>".
* <li>The font and style (bold/italic) is added as an integer like so:
* "<i>family,</i> <i>style,</i> <i>size</i>".
* <li>The entire syntax highlighting scheme is thus one long string of
* color schemes of the format "<i>i,[fg],[bg],uline,[style]</i>,
* where:
* <ul>
* <li><code>i</code> is the index of the syntax scheme.
* <li><i>fg</i> and <i>bg</i> are the foreground and background
* colors for the scheme, and may be null (represented by
* <code>-</code>).
* <li><code>uline</code> is whether or not the font should be
* underlined, and is either <code>t</code> or <code>f</code>.
* <li><code>style</code> is the <code>family,style,size</code>
* triplet described above.
* </ul>
* </ul>
*
* @return A string representing the rgb values of the colors.
*/
public String toCommaSeparatedString() {
StringBuffer sb = new StringBuffer(VERSION);
sb.append(',');
for (int i=0; i<NUM_TOKEN_TYPES; i++) {
sb.append(i).append(',');
Style ss = styles[i];
if (ss==null) { // Only true for i==0 (NULL token)
sb.append("-,-,f,-,,,");
continue;
}
Color c = ss.foreground;
sb.append(c!=null ? (getHexString(c) + ",") : "-,");
c = ss.background;
sb.append(c!=null ? (getHexString(c) + ",") : "-,");
sb.append(ss.underline ? "t," : "f,");
Font font = ss.font;
if (font!=null) {
sb.append(font.getFamily()).append(',').
append(font.getStyle()).append(',').
append(font.getSize()).append(',');
}
else {
sb.append("-,,,");
}
}
return sb.substring(0,sb.length()-1); // Take off final ','.
}
/**
* Loads a <code>SyntaxScheme</code> from an XML file.
*/
private static class XmlParser extends DefaultHandler {
private Font baseFont;
private SyntaxScheme scheme;
public XmlParser(Font baseFont) {
scheme = new SyntaxScheme(baseFont);
}
/**
* Creates the XML reader to use. Note that in 1.4 JRE's, the reader
* class wasn't defined by default, but in 1.5+ it is.
*
* @return The XML reader to use.
*/
private static XMLReader createReader() throws IOException {
XMLReader reader = null;
try {
reader = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
// Happens in JRE 1.4.x; 1.5+ define the reader class properly
try {
reader = XMLReaderFactory.createXMLReader(
"org.apache.crimson.parser.XMLReaderImpl");
} catch (SAXException se) {
throw new IOException(se.toString());
}
}
return reader;
}
public static SyntaxScheme load(Font baseFont,
InputStream in) throws IOException {
XMLReader reader = createReader();
XmlParser parser = new XmlParser(baseFont);
parser.baseFont = baseFont;
reader.setContentHandler(parser);
InputSource is = new InputSource(in);
is.setEncoding("UTF-8");
try {
reader.parse(is);
} catch (SAXException se) {
throw new IOException(se.toString());
}
return parser.scheme;
}
public void startElement(String uri, String localName, String qName,
Attributes attrs) {
if ("style".equals(qName)) {
String type = attrs.getValue("token");
Field field = null;
try {
field = Token.class.getField(type);
} catch (RuntimeException re) {
throw re; // FindBugs
} catch (Exception e) {
System.err.println("Invalid token type: " + type);
return;
}
if (field.getType()==int.class) {
int index = 0;
try {
index = field.getInt(scheme);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
}
String fgStr = attrs.getValue("fg");
if (fgStr!=null) {
Color fg = stringToColor(fgStr);
scheme.styles[index].foreground = fg;
}
String bgStr = attrs.getValue("bg");
if (bgStr!=null) {
Color bg = stringToColor(bgStr);
scheme.styles[index].background = bg;
}
boolean styleSpecified = false;
boolean bold = false;
boolean italic = false;
String boldStr = attrs.getValue("bold");
if (boldStr!=null) {
bold = Boolean.valueOf(boldStr).booleanValue();
styleSpecified = true;
}
String italicStr = attrs.getValue("italic");
if (italicStr!=null) {
italic = Boolean.valueOf(italicStr).booleanValue();
styleSpecified = true;
}
if (styleSpecified) {
int style = 0;
if (bold) { style |= Font.BOLD; }
if (italic) { style |= Font.ITALIC; }
scheme.styles[index].font = baseFont.deriveFont(style);
}
String ulineStr = attrs.getValue("underline");
if (ulineStr!=null) {
boolean uline= Boolean.valueOf(ulineStr).booleanValue();
scheme.styles[index].underline = uline;
}
}
}
}
}
}

View File

@ -1,871 +0,0 @@
/*
* 02/24/2004
*
* SyntaxView.java - The View object used by RSyntaxTextArea when word wrap is
* disabled.
*
* 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.event.*;
import javax.swing.text.*;
import org.fife.ui.rsyntaxtextarea.folding.Fold;
import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
/**
* The <code>javax.swing.text.View</code> object used by {@link RSyntaxTextArea}
* when word wrap is disabled. It implements syntax highlighting for
* programming languages using the colors and font styles specified by the
* <code>RSyntaxTextArea</code>.<p>
*
* You don't really have to do anything to use this class, as
* {@link RSyntaxTextAreaUI} automatically sets the text area's view to be
* an instance of this class if word wrap is disabled.<p>
*
* The tokens that specify how to paint the syntax-highlighted text are gleaned
* from the text area's {@link RSyntaxDocument}.
*
* @author Robert Futrell
* @version 0.3
*/
public class SyntaxView extends View implements TabExpander,
TokenOrientedView, RSTAView {
/**
* The default font used by the text area. If this changes we need to
* recalculate the longest line.
*/
Font font;
/**
* Font metrics for the current font.
*/
protected FontMetrics metrics;
/**
* The current longest line. This is used to calculate the preferred width
* of the view. Since the calculation is potentially expensive, we try to
* avoid it by stashing which line is currently the longest.
*/
Element longLine;
float longLineWidth;
private int tabSize;
protected int tabBase;
/**
* Cached for each paint() call so each drawLine() call has access to it.
*/
private RSyntaxTextArea host;
/**
* Cached values to speed up the painting a tad.
*/
private int lineHeight = 0;
private int ascent;
private int clipStart;
private int clipEnd;
// /**
// * The end-of-line marker.
// */
// private static final char[] eolMarker = { '.' };
/**
* Constructs a new <code>SyntaxView</code> wrapped around an element.
*
* @param elem The element representing the text to display.
*/
public SyntaxView(Element elem) {
super(elem);
}
/**
* Iterate over the lines represented by the child elements
* of the element this view represents, looking for the line
* that is the longest. The <em>longLine</em> variable is updated to
* represent the longest line contained. The <em>font</em> variable
* is updated to indicate the font used to calculate the
* longest line.
*/
void calculateLongestLine() {
Component c = getContainer();
font = c.getFont();
metrics = c.getFontMetrics(font);
tabSize = getTabSize() * metrics.charWidth(' ');
Element lines = getElement();
int n = lines.getElementCount();
for (int i=0; i<n; i++) {
Element line = lines.getElement(i);
float w = getLineWidth(i);
if (w > longLineWidth) {
longLineWidth = w;
longLine = line;
}
}
}
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param changes the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#changedUpdate
*/
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
updateDamage(changes, a, f);
}
/**
* Repaint the given line range.
*
* @param line0 The starting line number to repaint. This must
* be a valid line number in the model.
* @param line1 The ending line number to repaint. This must
* be a valid line number in the model.
* @param a The region allocated for the view to render into.
* @param host The component hosting the view (used to call repaint).
*/
protected void damageLineRange(int line0, int line1, Shape a,
Component host) {
if (a != null) {
Rectangle area0 = lineToRect(a, line0);
Rectangle area1 = lineToRect(a, line1);
if ((area0 != null) && (area1 != null)) {
Rectangle dmg = area0.union(area1); // damage.
host.repaint(dmg.x, dmg.y, dmg.width, dmg.height);
}
else
host.repaint();
}
}
/**
* Draws the passed-in text using syntax highlighting for the current
* language. The tokens used to decide how to paint the syntax
* highlighting are grabbed from the text area's document.
*
* @param token The list of tokens to draw.
* @param g The graphics context in which to draw.
* @param x The x-coordinate at which to draw.
* @param y The y-coordinate at which to draw.
* @return The x-coordinate representing the end of the painted text.
*/
public float drawLine(Token token, Graphics2D g, float x, float y) {
float nextX = x; // The x-value at the end of our text.
while (token!=null && token.isPaintable() && nextX<clipEnd) {
nextX = token.paint(g, nextX,y, host, this, clipStart);
token = token.getNextToken();
}
// 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", nextX, y);
}
// Return the x-coordinate at the end of the painted text.
return nextX;
}
/**
* Calculates the width of the line represented by the given element.
*
* @param line The line for which to get the length.
* @param lineNumber The line number of the specified line in the document.
* @return The width of the line.
*/
private float getLineWidth(int lineNumber) {
Token tokenList = ((RSyntaxDocument)getDocument()).
getTokenListForLine(lineNumber);
return RSyntaxUtilities.getTokenListWidth(tokenList,
(RSyntaxTextArea)getContainer(),
this);
}
/**
* Provides a way to determine the next visually represented model
* location that one might place a caret. Some views may not be visible,
* they might not be in the same order found in the model, or they just
* might not allow access to some of the locations in the model.
*
* @param pos the position to convert >= 0
* @param a the allocated region to render into
* @param direction the direction from the current position that can
* be thought of as the arrow keys typically found on a keyboard.
* This may be SwingConstants.WEST, SwingConstants.EAST,
* SwingConstants.NORTH, or SwingConstants.SOUTH.
* @return the location within the model that best represents the next
* location visual position.
* @exception BadLocationException
* @exception IllegalArgumentException for an invalid direction
*/
public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
int direction, Position.Bias[] biasRet)
throws BadLocationException {
return RSyntaxUtilities.getNextVisualPositionFrom(pos, b, a,
direction, biasRet, this);
}
/**
* Determines the preferred span for this view along an
* axis.
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into >= 0.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @exception IllegalArgumentException for an invalid axis
*/
public float getPreferredSpan(int axis) {
updateMetrics();
switch (axis) {
case View.X_AXIS:
float span = longLineWidth + 10; // "fudge factor."
if (host.getEOLMarkersVisible()) {
span += metrics.charWidth('\u00B6');
}
return span;
case View.Y_AXIS:
// We update lineHeight here as when this method is first
// called, lineHeight isn't initialized. If we don't do it
// here, we get no vertical scrollbar (as lineHeight==0).
lineHeight = host!=null ? host.getLineHeight() : lineHeight;
// return getElement().getElementCount() * lineHeight;
int visibleLineCount = getElement().getElementCount();
if (host.isCodeFoldingEnabled()) {
visibleLineCount -= host.getFoldManager().getHiddenLineCount();
}
return visibleLineCount * lineHeight;
default:
throw new IllegalArgumentException("Invalid axis: " + axis);
}
}
/**
* Returns the tab size set for the document, defaulting to 5.
*
* @return The tab size.
*/
protected int getTabSize() {
Integer i = (Integer)getDocument().getProperty(
PlainDocument.tabSizeAttribute);
int size = (i != null) ? i.intValue() : 5;
return size;
}
/**
* Returns a token list for the <i>physical</i> line above the physical
* line containing the specified offset into the document. Note that for
* this plain (non-wrapped) view, this is simply the token list for the
* logical line above the line containing <code>offset</code>, since lines
* are not wrapped.
*
* @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line
* before this one. If <code>offset</code> is in the first line in
* the document, <code>null</code> is returned.
*/
public Token getTokenListForPhysicalLineAbove(int offset) {
RSyntaxDocument document = (RSyntaxDocument)getDocument();
Element map = document.getDefaultRootElement();
int line = map.getElementIndex(offset);
FoldManager fm = host.getFoldManager();
if (fm==null) {
line--;
if (line>=0) {
return document.getTokenListForLine(line);
}
}
else {
line = fm.getVisibleLineAbove(line);
if (line>=0) {
return document.getTokenListForLine(line);
}
}
// int line = map.getElementIndex(offset) - 1;
// if (line>=0)
// return document.getTokenListForLine(line);
return null;
}
/**
* Returns a token list for the <i>physical</i> line below the physical
* line containing the specified offset into the document. Note that for
* this plain (non-wrapped) view, this is simply the token list for the
* logical line below the line containing <code>offset</code>, since lines
* are not wrapped.
*
* @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line
* after this one. If <code>offset</code> is in the last physical
* line in the document, <code>null</code> is returned.
*/
public Token getTokenListForPhysicalLineBelow(int offset) {
RSyntaxDocument document = (RSyntaxDocument)getDocument();
Element map = document.getDefaultRootElement();
int lineCount = map.getElementCount();
int line = map.getElementIndex(offset);
if (!host.isCodeFoldingEnabled()) {
if (line<lineCount-1) {
return document.getTokenListForLine(line+1);
}
}
else {
FoldManager fm = host.getFoldManager();
line = fm.getVisibleLineBelow(line);
if (line>=0 && line<lineCount) {
return document.getTokenListForLine(line);
}
}
// int line = map.getElementIndex(offset);
// int lineCount = map.getElementCount();
// if (line<lineCount-1)
// return document.getTokenListForLine(line+1);
return null;
}
/**
* Gives notification that something was inserted into the document
* in a location that this view is responsible for.
*
* @param changes The change information from the associated document.
* @param a The current allocation of the view.
* @param f The factory to use to rebuild if the view has children.
*/
public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
updateDamage(changes, a, f);
}
/**
* Determine the rectangle that represents the given line.
*
* @param a The region allocated for the view to render into
* @param line The line number to find the region of. This must
* be a valid line number in the model.
*/
protected Rectangle lineToRect(Shape a, int line) {
Rectangle r = null;
updateMetrics();
if (metrics != null) {
Rectangle alloc = a.getBounds();
// NOTE: lineHeight is not initially set here, leading to the
// current line not being highlighted when a document is first
// opened. So, we set it here just in case.
lineHeight = host!=null ? host.getLineHeight() : lineHeight;
if (host.isCodeFoldingEnabled()) {
FoldManager fm = host.getFoldManager();
int hiddenCount = fm.getHiddenLineCountAbove(line);
line -= hiddenCount;
}
r = new Rectangle(alloc.x, alloc.y + line*lineHeight,
alloc.width, lineHeight);
}
return r;
}
/**
* Provides a mapping from the document model coordinate space
* to the coordinate space of the view mapped to it.
*
* @param pos the position to convert >= 0
* @param a the allocated region to render into
* @return the bounding box of the given position
* @exception BadLocationException if the given position does not
* represent a valid location in the associated document
* @see View#modelToView
*/
public Shape modelToView(int pos, Shape a, Position.Bias b)
throws BadLocationException {
// line coordinates
Element map = getElement();
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
int lineIndex = map.getElementIndex(pos);
Token tokenList = doc.getTokenListForLine(lineIndex);
Rectangle lineArea = lineToRect(a, lineIndex);
tabBase = lineArea.x; // Used by listOffsetToView().
//int x = (int)RSyntaxUtilities.getTokenListWidthUpTo(tokenList,
// (RSyntaxTextArea)getContainer(),
// this, 0, pos);
// We use this method instead as it returns the actual bounding box,
// not just the x-coordinate.
lineArea = tokenList.listOffsetToView(
(RSyntaxTextArea)getContainer(), this, pos,
tabBase, lineArea);
return lineArea;
}
/**
* Provides a mapping, for a given region, from the document model
* coordinate space to the view coordinate space. The specified region is
* created as a union of the first and last character positions.<p>
*
* This is implemented to subtract the width of the second character, as
* this view's <code>modelToView</code> actually returns the width of the
* character instead of "1" or "0" like the View implementations in
* <code>javax.swing.text</code>. Thus, if we don't override this method,
* the <code>View</code> implementation will return one character's width
* too much for its consumers (implementations of
* <code>javax.swing.text.Highlighter</code>).
*
* @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; <code>b0</code>
* will have one of these values:
* <ul>
* <li> <code>Position.Bias.Forward</code>
* <li> <code>Position.Bias.Backward</code>
* </ul>
* @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 <code>b0</code> or
* <code>b1</code> are not one of the
* legal <code>Position.Bias</code> values listed above
* @see View#viewToModel
*/
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 instanceof Rectangle ? (Rectangle)s0 : 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);
}
/**
* Actually paints the text area. Only lines that have been damaged are
* repainted.
*
* @param g The graphics context with which to paint.
* @param a The allocated region in which to render.
* @see #drawLine
*/
public void paint(Graphics g, Shape a) {
RSyntaxDocument document = (RSyntaxDocument)getDocument();
Rectangle alloc = a.getBounds();
tabBase = alloc.x;
host = (RSyntaxTextArea)getContainer();
Rectangle clip = g.getClipBounds();
// An attempt to speed things up for files with long lines. Note that
// this will actually slow things down a tad for the common case of
// regular-length lines, but I don't think it'll make a difference
// visually. We'll see...
clipStart = clip.x;
clipEnd = clipStart + clip.width;
lineHeight = host.getLineHeight();
ascent = host.getMaxAscent();//metrics.getAscent();
int heightAbove = clip.y - alloc.y;
int linesAbove = Math.max(0, heightAbove / lineHeight);
FoldManager fm = host.getFoldManager();
linesAbove += fm.getHiddenLineCountAbove(linesAbove, true);
Rectangle lineArea = lineToRect(a, linesAbove);
int y = lineArea.y + ascent;
int x = lineArea.x;
Element map = getElement();
int lineCount = map.getElementCount();
RSyntaxTextAreaHighlighter h =
(RSyntaxTextAreaHighlighter)host.getHighlighter();
Graphics2D g2d = (Graphics2D)g;
Token token;
//System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1));
int line = linesAbove;
//int count = 0;
while (y<clip.y+clip.height+lineHeight && line<lineCount) {
Fold fold = fm.getFoldForLine(line);
Element lineElement = map.getElement(line);
int startOffset = lineElement.getStartOffset();
//int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 :
// lineElement.getEndOffset()-1);
int endOffset = lineElement.getEndOffset()-1; // Why always "-1"?
h.paintLayeredHighlights(g2d, startOffset, endOffset,
a, host, this);
// Paint a line of text.
token = document.getTokenListForLine(line);
drawLine(token, g2d, x,y);
if (fold!=null && fold.isCollapsed()) {
// Visible indicator of collapsed lines
Color c = RSyntaxUtilities.getFoldedLineBottomColor(host);
if (c!=null) {
g.setColor(c);
g.drawLine(x,y+lineHeight-ascent-1,
alloc.width,y+lineHeight-ascent-1);
}
// Skip to next line to paint, taking extra care for lines with
// block ends and begins together, e.g. "} else {"
do {
int hiddenLineCount = fold.getLineCount();
if (hiddenLineCount==0) {
// Fold parser identified a zero-line fold region.
// This is really a bug, but we'll be graceful here
// and avoid an infinite loop.
break;
}
line += hiddenLineCount;
fold = fm.getFoldForLine(line);
} while (fold!=null && fold.isCollapsed());
}
y += lineHeight;
line++;
//count++;
}
//System.out.println("SyntaxView: lines painted=" + count);
}
/**
* If the passed-in line is longer than the current longest line, then
* the longest line is updated.
*
* @param line The line to test against the current longest.
* @param lineNumber The line number of the passed-in line.
* @return <code>true</code> iff the current longest line was updated.
*/
protected boolean possiblyUpdateLongLine(Element line, int lineNumber) {
float w = getLineWidth(lineNumber);
if (w > longLineWidth) {
longLineWidth = w;
longLine = line;
return true;
}
return false;
}
/**
* Gives notification that something was removed from the document
* in a location that this view is responsible for.
*
* @param changes the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
*/
public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
updateDamage(changes, a, f);
}
public void setSize(float width, float height) {
super.setSize(width, height);
updateMetrics();
}
/**
* Repaint the region of change covered by the given document
* event. Damages the line that begins the range to cover
* the case when the insert/remove is only on one line.
* If lines are added or removed, damages the whole
* view. The longest line is checked to see if it has
* changed.
*/
protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) {
Component host = getContainer();
updateMetrics();
Element elem = getElement();
DocumentEvent.ElementChange ec = changes.getChange(elem);
Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null;
if (((added != null) && (added.length > 0)) ||
((removed != null) && (removed.length > 0))) {
// lines were added or removed...
if (added != null) {
int addedAt = ec.getIndex(); // FIXME: Is this correct?????
for (int i = 0; i < added.length; i++)
possiblyUpdateLongLine(added[i], addedAt+i);
}
if (removed != null) {
for (int i = 0; i < removed.length; i++) {
if (removed[i] == longLine) {
longLineWidth = -1; // Must do this!!
calculateLongestLine();
break;
}
}
}
preferenceChanged(null, true, true);
host.repaint();
}
// This occurs when syntax highlighting only changes on lines
// (i.e. beginning a multiline comment).
else if (changes.getType()==DocumentEvent.EventType.CHANGE) {
//System.err.println("Updating the damage due to a CHANGE event...");
int startLine = changes.getOffset();
int endLine = changes.getLength();
damageLineRange(startLine,endLine, a, host);
}
else {
Element map = getElement();
int line = map.getElementIndex(changes.getOffset());
damageLineRange(line, line, a, host);
if (changes.getType() == DocumentEvent.EventType.INSERT) {
// check to see if the line is longer than current
// longest line.
Element e = map.getElement(line);
if (e == longLine) {
// We must recalculate longest line's width here
// because it has gotten longer.
longLineWidth = getLineWidth(line);
preferenceChanged(null, true, false);
}
else {
// If long line gets updated, update the status bars too.
if (possiblyUpdateLongLine(e, line))
preferenceChanged(null, true, false);
}
}
else if (changes.getType() == DocumentEvent.EventType.REMOVE) {
if (map.getElement(line) == longLine) {
// removed from longest line... recalc
longLineWidth = -1; // Must do this!
calculateLongestLine();
preferenceChanged(null, true, false);
}
}
}
}
/**
* Checks to see if the font metrics and longest line are up-to-date.
*/
protected void updateMetrics() {
host = (RSyntaxTextArea)getContainer();
Font f = host.getFont();
if (font != f) {
// The font changed, we need to recalculate the longest line!
// This also updates cached font and tab size.
calculateLongestLine();
}
}
/**
* Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param fx the X coordinate >= 0
* @param fy the Y coordinate >= 0
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point in the view >= 0
*/
public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
bias[0] = Position.Bias.Forward;
Rectangle alloc = a.getBounds();
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
int x = (int) fx;
int y = (int) fy;
// If they're asking about a view position above the area covered by
// this view, then the position is assumed to be the starting position
// of this view.
if (y < alloc.y) {
return getStartOffset();
}
// If they're asking about a position below this view, the position
// is assumed to be the ending position of this view.
else if (y > alloc.y + alloc.height) {
return host.getLastVisibleOffset();
}
// They're asking about a position 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.
else {
Element map = doc.getDefaultRootElement();
int lineIndex = Math.abs((y - alloc.y) / lineHeight);//metrics.getHeight() );
FoldManager fm = host.getFoldManager();
//System.out.print("--- " + lineIndex);
lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
//System.out.println(" => " + lineIndex);
if (lineIndex >= map.getElementCount()) {
return host.getLastVisibleOffset();
}
Element line = map.getElement(lineIndex);
// If the point is to the left of the line...
if (x < alloc.x)
return line.getStartOffset();
// If the point is to the right of the line...
else if (x > alloc.x + alloc.width)
return line.getEndOffset() - 1;
else {
// Determine the offset into the text
int p0 = line.getStartOffset();
Token tokenList = doc.getTokenListForLine(lineIndex);
tabBase = alloc.x;
int offs = tokenList.getListOffset(
(RSyntaxTextArea)getContainer(),
this, tabBase, x);
return offs!=-1 ? offs : p0;
}
} // End of else.
}
/**
* {@inheritDoc}
*/
public int yForLine(Rectangle alloc, int line) throws BadLocationException {
//Rectangle lineArea = lineToRect(alloc, lineIndex);
updateMetrics();
if (metrics != null) {
// NOTE: lineHeight is not initially set here, leading to the
// current line not being highlighted when a document is first
// opened. So, we set it here just in case.
lineHeight = host!=null ? host.getLineHeight() : lineHeight;
FoldManager fm = host.getFoldManager();
if (!fm.isLineHidden(line)) {
line -= fm.getHiddenLineCountAbove(line);
return alloc.y + line*lineHeight;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
public int yForLineContaining(Rectangle alloc, int offs)
throws BadLocationException {
Element map = getElement();
int line = map.getElementIndex(offs);
return yForLine(alloc, line);
}
}

View File

@ -1,712 +0,0 @@
/*
* 11/25/2008
*
* TextEditorPane.java - A syntax highlighting text area that has knowledge of
* the file it is editing on disk.
*
* 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.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import org.fife.io.UnicodeReader;
import org.fife.io.UnicodeWriter;
import org.fife.ui.rtextarea.RTextAreaEditorKit;
/**
* An extension of {@link org.fife.ui.rsyntaxtextarea.RSyntaxTextArea}
* that adds information about the file being edited, such as:
*
* <ul>
* <li>Its name and location.
* <li>Is it dirty?
* <li>Is it read-only?
* <li>The last time it was loaded or saved to disk (local files only).
* <li>The file's encoding on disk.
* <li>Easy access to the line separator.
* </ul>
*
* Loading and saving is also built into the editor.<p>
* Both local and remote files (e.g. ftp) are supported. See the
* {@link FileLocation} class for more information.
*
* @author Robert Futrell
* @version 1.0
* @see FileLocation
*/
public class TextEditorPane extends RSyntaxTextArea implements
DocumentListener {
private static final long serialVersionUID = 1L;
public static final String FULL_PATH_PROPERTY = "TextEditorPane.fileFullPath";
public static final String DIRTY_PROPERTY = "TextEditorPane.dirty";
public static final String READ_ONLY_PROPERTY = "TextEditorPane.readOnly";
/**
* The location of the file being edited.
*/
private FileLocation loc;
/**
* The charset to use when reading or writing this file.
*/
private String charSet;
/**
* Whether the file should be treated as read-only.
*/
private boolean readOnly;
/**
* Whether the file is dirty.
*/
private boolean dirty;
/**
* The last time this file was modified on disk, for local files.
* For remote files, this value should always be
* {@link #LAST_MODIFIED_UNKNOWN}.
*/
private long lastSaveOrLoadTime;
/**
* The value returned by {@link #getLastSaveOrLoadTime()} for remote files.
*/
public static final long LAST_MODIFIED_UNKNOWN = 0;
/**
* The default name given to files if none is specified in a constructor.
*/
private static final String DEFAULT_FILE_NAME = "Untitled.txt";
/**
* Constructor. The file will be given a default name.
*/
public TextEditorPane() {
this(INSERT_MODE);
}
/**
* Constructor. The file will be given a default name.
*
* @param textMode Either <code>INSERT_MODE</code> or
* <code>OVERWRITE_MODE</code>.
*/
public TextEditorPane(int textMode) {
this(textMode, false);
}
/**
* Creates a new <code>TextEditorPane</code>. The file will be given
* a default name.
*
* @param textMode Either <code>INSERT_MODE</code> or
* <code>OVERWRITE_MODE</code>.
* @param wordWrapEnabled Whether or not to use word wrap in this pane.
*/
public TextEditorPane(int textMode, boolean wordWrapEnabled) {
super(textMode);
setLineWrap(wordWrapEnabled);
try {
init(null, null);
} catch (IOException ioe) { // Never happens
ioe.printStackTrace();
}
}
/**
* Creates a new <code>TextEditorPane</code>.
*
* @param textMode Either <code>INSERT_MODE</code> or
* <code>OVERWRITE_MODE</code>.
* @param wordWrapEnabled Whether or not to use word wrap in this pane.
* @param loc The location of the text file being edited. If this value
* is <code>null</code>, a file named "Untitled.txt" in the current
* directory is used.
* @throws IOException If an IO error occurs reading the file at
* <code>loc</code>. This of course won't happen if
* <code>loc</code> is <code>null</code>.
*/
public TextEditorPane(int textMode, boolean wordWrapEnabled,
FileLocation loc) throws IOException {
this(textMode, wordWrapEnabled, loc, null);
}
/**
* Creates a new <code>TextEditorPane</code>.
*
* @param textMode Either <code>INSERT_MODE</code> or
* <code>OVERWRITE_MODE</code>.
* @param wordWrapEnabled Whether or not to use word wrap in this pane.
* @param loc The location of the text file being edited. If this value
* is <code>null</code>, a file named "Untitled.txt" in the current
* directory is used. This file is displayed as empty even if it
* actually exists.
* @param defaultEnc The default encoding to use when opening the file,
* if the file is not Unicode. If this value is <code>null</code>,
* a system default value is used.
* @throws IOException If an IO error occurs reading the file at
* <code>loc</code>. This of course won't happen if
* <code>loc</code> is <code>null</code>.
*/
public TextEditorPane(int textMode, boolean wordWrapEnabled,
FileLocation loc, String defaultEnc) throws IOException {
super(textMode);
setLineWrap(wordWrapEnabled);
init(loc, defaultEnc);
}
/**
* Callback for when styles in the current document change.
* This method is never called.
*
* @param e The document event.
*/
public void changedUpdate(DocumentEvent e) {
}
/**
* Returns the default encoding for this operating system.
*
* @return The default encoding.
*/
private static final String getDefaultEncoding() {
// TODO: Change to "Charset.defaultCharset().name()" when 1.4 support
// is no longer needed.
// NOTE: The "file.encoding" property is not guaranteed to be set by
// the spec, so we cannot rely on it.
String encoding = System.getProperty("file.encoding");
if (encoding==null) {
try {
File f = File.createTempFile("rsta", null);
FileWriter w = new FileWriter(f);
encoding = w.getEncoding();
w.close();
f.deleteOnExit();//delete(); Keep FindBugs happy
} catch (IOException ioe) {
encoding = "US-ASCII";
}
}
return encoding;
}
/**
* Returns the encoding to use when reading or writing this file.
*
* @return The encoding.
* @see #setEncoding(String)
*/
public String getEncoding() {
return charSet;
}
/**
* Returns the full path to this document.
*
* @return The full path to the document.
*/
public String getFileFullPath() {
return loc==null ? null : loc.getFileFullPath();
}
/**
* Returns the file name of this document.
*
* @return The file name.
*/
public String getFileName() {
return loc.getFileName();
}
/**
* Returns the timestamp for when this file was last loaded or saved
* <em>by this editor pane</em>. If the file has been modified on disk by
* another process after it was loaded into this editor pane, this method
* will not return the actual file's last modified time.<p>
*
* For remote files, this method will always return
* {@link #LAST_MODIFIED_UNKNOWN}.
*
* @return The timestamp when this file was last loaded or saved by this
* editor pane, if it is a local file, or
* {@link #LAST_MODIFIED_UNKNOWN} if it is a remote file.
* @see #isModifiedOutsideEditor()
*/
public long getLastSaveOrLoadTime() {
return lastSaveOrLoadTime;
}
/**
* Returns the line separator used when writing this file (e.g.
* "<code>\n</code>", "<code>\r\n</code>", or "<code>\r</code>").<p>
*
* Note that this value is an <code>Object</code> and not a
* <code>String</code> as that is the way the {@link Document} interface
* defines its property values. If you always use
* {@link #setLineSeparator(String)} to modify this value, then the value
* returned from this method will always be a <code>String</code>.
*
* @return The line separator. If this value is <code>null</code>, then
* the system default line separator is used (usually the value
* of <code>System.getProperty("line.separator")</code>).
* @see #setLineSeparator(String)
* @see #setLineSeparator(String, boolean)
*/
public Object getLineSeparator() {
return getDocument().getProperty(
RTextAreaEditorKit.EndOfLineStringProperty);
}
/**
* Initializes this editor with the specified file location.
*
* @param loc The file location. If this is <code>null</code>, a default
* location is used and an empty file is displayed.
* @param defaultEnc The default encoding to use when opening the file,
* if the file is not Unicode. If this value is <code>null</code>,
* a system default value is used.
* @throws IOException If an IO error occurs reading from <code>loc</code>.
* If <code>loc</code> is <code>null</code>, this cannot happen.
*/
private void init(FileLocation loc, String defaultEnc) throws IOException {
if (loc==null) {
// Don't call load() just in case Untitled.txt actually exists,
// just to ensure there is no chance of an IOException being thrown
// in the default case.
this.loc = FileLocation.create(DEFAULT_FILE_NAME);
charSet = defaultEnc==null ? getDefaultEncoding() : defaultEnc;
// Ensure that line separator always has a value, even if the file
// does not exist (or is the "default" file). This makes life
// easier for host applications that want to display this value.
setLineSeparator(System.getProperty("line.separator"));
}
else {
load(loc, defaultEnc); // Sets this.loc
}
if (this.loc.isLocalAndExists()) {
File file = new File(this.loc.getFileFullPath());
lastSaveOrLoadTime = file.lastModified();
setReadOnly(!file.canWrite());
}
else {
lastSaveOrLoadTime = LAST_MODIFIED_UNKNOWN;
setReadOnly(false);
}
setDirty(false);
}
/**
* Callback for when text is inserted into the document.
*
* @param e Information on the insertion.
*/
public void insertUpdate(DocumentEvent e) {
if (!dirty) {
setDirty(true);
}
}
/**
* Returns whether or not the text in this editor has unsaved changes.
*
* @return Whether or not the text has unsaved changes.
* @see #setDirty(boolean)
*/
public boolean isDirty() {
return dirty;
}
/**
* Returns whether this file is a local file.
*
* @return Whether this is a local file.
*/
public boolean isLocal() {
return loc.isLocal();
}
/**
* Returns whether this is a local file that already exists.
*
* @return Whether this is a local file that already exists.
*/
public boolean isLocalAndExists() {
return loc.isLocalAndExists();
}
/**
* Returns whether the text file has been modified outside of this editor
* since the last load or save operation. Note that if this is a remote
* file, this method will always return <code>false</code>.<p>
*
* This method may be used by applications to implement a reloading
* feature, where the user is prompted to reload a file if it has been
* modified since their last open or save.
*
* @return Whether the text file has been modified outside of this
* editor.
* @see #getLastSaveOrLoadTime()
*/
public boolean isModifiedOutsideEditor() {
return loc.getActualLastModified()>getLastSaveOrLoadTime();
}
/**
* Returns whether or not the text area should be treated as read-only.
*
* @return Whether or not the text area should be treated as read-only.
* @see #setReadOnly(boolean)
*/
public boolean isReadOnly() {
return readOnly;
}
/**
* Loads the specified file in this editor. This method fires a property
* change event of type {@link #FULL_PATH_PROPERTY}.
*
* @param loc The location of the file to load. This cannot be
* <code>null</code>.
* @param defaultEnc The encoding to use when loading/saving the file.
* This encoding will only be used if the file is not Unicode.
* If this value is <code>null</code>, the system default encoding
* is used.
* @throws IOException If an IO error occurs.
* @see #save()
* @see #saveAs(FileLocation)
*/
public void load(FileLocation loc, String defaultEnc) throws IOException {
// For new local files, just go with it.
if (loc.isLocal() && !loc.isLocalAndExists()) {
this.charSet = defaultEnc!=null ? defaultEnc : getDefaultEncoding();
this.loc = loc;
setText(null);
discardAllEdits();
setDirty(false);
return;
}
// Old local files and remote files, load 'em up. UnicodeReader will
// check for BOMs and handle them correctly in all cases, then pass
// rest of stream down to InputStreamReader.
UnicodeReader ur = new UnicodeReader(loc.getInputStream(), defaultEnc);
// Remove listener so dirty flag doesn't get set when loading a file.
Document doc = getDocument();
doc.removeDocumentListener(this);
BufferedReader r = new BufferedReader(ur);
try {
read(r, null);
} finally {
doc.addDocumentListener(this);
r.close();
}
// No IOException thrown, so we can finally change the location.
charSet = ur.getEncoding();
String old = getFileFullPath();
this.loc = loc;
setDirty(false);
setCaretPosition(0);
firePropertyChange(FULL_PATH_PROPERTY, old, getFileFullPath());
}
/**
* Reloads this file from disk. The file must exist for this operation
* to not throw an exception.<p>
*
* The file's "dirty" state will be set to <code>false</code> after this
* operation. If this is a local file, its "last modified" time is
* updated to reflect that of the actual file.<p>
*
* Note that if the file has been modified on disk, and is now a Unicode
* encoding when before it wasn't (or if it is a different Unicode now),
* this will cause this {@link TextEditorPane}'s encoding to change.
* Otherwise, the file's encoding will stay the same.
*
* @throws IOException If the file does not exist, or if an IO error
* occurs reading the file.
* @see #isLocalAndExists()
*/
public void reload() throws IOException {
String oldEncoding = getEncoding();
UnicodeReader ur = new UnicodeReader(loc.getInputStream(), oldEncoding);
String encoding = ur.getEncoding();
BufferedReader r = new BufferedReader(ur);
try {
read(r, null); // Dumps old contents.
} finally {
r.close();
}
setEncoding(encoding);
setDirty(false);
syncLastSaveOrLoadTimeToActualFile();
discardAllEdits(); // Prevent user from being able to undo the reload
}
/**
* Called whenever text is removed from this editor.
*
* @param e The document event.
*/
public void removeUpdate(DocumentEvent e) {
if (!dirty) {
setDirty(true);
}
}
/**
* Saves the file in its current encoding.<p>
*
* The text area's "dirty" state is set to <code>false</code>, and if
* this is a local file, its "last modified" time is updated.
*
* @throws IOException If an IO error occurs.
* @see #saveAs(FileLocation)
* @see #load(FileLocation, String)
*/
public void save() throws IOException {
saveImpl(loc);
setDirty(false);
syncLastSaveOrLoadTimeToActualFile();
}
/**
* Saves this file in a new local location. This method fires a property
* change event of type {@link #FULL_PATH_PROPERTY}.
*
* @param loc The location to save to.
* @throws IOException If an IO error occurs.
* @see #save()
* @see #load(FileLocation, String)
*/
public void saveAs(FileLocation loc) throws IOException {
saveImpl(loc);
// No exception thrown - we can "rename" the file.
String old = getFileFullPath();
this.loc = loc;
setDirty(false);
lastSaveOrLoadTime = loc.getActualLastModified();
firePropertyChange(FULL_PATH_PROPERTY, old, getFileFullPath());
}
/**
* Saves the text in this editor to the specified location.
*
* @param loc The location to save to.
* @throws IOException If an IO error occurs.
*/
private void saveImpl(FileLocation loc) throws IOException {
OutputStream out = loc.getOutputStream();
BufferedWriter w = new BufferedWriter(
new UnicodeWriter(out, getEncoding()));
try {
write(w);
} finally {
w.close();
}
}
/**
* Sets whether or not this text in this editor has unsaved changes.
* This fires a property change event of type {@link #DIRTY_PROPERTY}.<p>
*
* Applications will usually have no need to call this method directly; the
* only time you might have a need to call this method directly is if you
* have to initialize an instance of TextEditorPane with content that does
* not come from a file. <code>TextEditorPane</code> automatically sets its
* own dirty flag when its content is edited, when its encoding is changed,
* or when its line ending property is changed. It is cleared whenever
* <code>load()</code>, <code>reload()</code>, <code>save()</code>, or
* <code>saveAs()</code> are called.
*
* @param dirty Whether or not the text has been modified.
* @see #isDirty()
*/
public void setDirty(boolean dirty) {
if (this.dirty!=dirty) {
this.dirty = dirty;
firePropertyChange(DIRTY_PROPERTY, !dirty, dirty);
}
}
/**
* Sets the document for this editor.
*
* @param doc The new document.
*/
public void setDocument(Document doc) {
Document old = getDocument();
if (old!=null) {
old.removeDocumentListener(this);
}
super.setDocument(doc);
doc.addDocumentListener(this);
}
/**
* Sets the encoding to use when reading or writing this file. This
* method sets the editor's dirty flag when the encoding is changed.
*
* @param encoding The new encoding.
* @throws UnsupportedCharsetException If the encoding is not supported.
* @throws NullPointerException If <code>encoding</code> is
* <code>null</code>.
* @see #getEncoding()
*/
public void setEncoding(String encoding) {
if (encoding==null) {
throw new NullPointerException("encoding cannot be null");
}
else if (!Charset.isSupported(encoding)) {
throw new UnsupportedCharsetException(encoding);
}
if (charSet==null || !charSet.equals(encoding)) {
charSet = encoding;
setDirty(true);
}
}
/**
* Sets the line separator sequence to use when this file is saved (e.g.
* "<code>\n</code>", "<code>\r\n</code>" or "<code>\r</code>").
*
* Besides parameter checking, this method is preferred over
* <code>getDocument().putProperty()</code> because it sets the editor's
* dirty flag when the line separator is changed.
*
* @param separator The new line separator.
* @throws NullPointerException If <code>separator</code> is
* <code>null</code>.
* @throws IllegalArgumentException If <code>separator</code> is not one
* of "<code>\n</code>", "<code>\r\n</code>" or "<code>\r</code>".
* @see #getLineSeparator()
*/
public void setLineSeparator(String separator) {
setLineSeparator(separator, true);
}
/**
* Sets the line separator sequence to use when this file is saved (e.g.
* "<code>\n</code>", "<code>\r\n</code>" or "<code>\r</code>").
*
* Besides parameter checking, this method is preferred over
* <code>getDocument().putProperty()</code> because can set the editor's
* dirty flag when the line separator is changed.
*
* @param separator The new line separator.
* @param setDirty Whether the dirty flag should be set if the line
* separator is changed.
* @throws NullPointerException If <code>separator</code> is
* <code>null</code>.
* @throws IllegalArgumentException If <code>separator</code> is not one
* of "<code>\n</code>", "<code>\r\n</code>" or "<code>\r</code>".
* @see #getLineSeparator()
*/
public void setLineSeparator(String separator, boolean setDirty) {
if (separator==null) {
throw new NullPointerException("terminator cannot be null");
}
if (!"\r\n".equals(separator) && !"\n".equals(separator) &&
!"\r".equals(separator)) {
throw new IllegalArgumentException("Invalid line terminator");
}
Document doc = getDocument();
Object old = doc.getProperty(
RTextAreaEditorKit.EndOfLineStringProperty);
if (!separator.equals(old)) {
doc.putProperty(RTextAreaEditorKit.EndOfLineStringProperty,
separator);
if (setDirty) {
setDirty(true);
}
}
}
/**
* Sets whether or not this text area should be treated as read-only.
* This fires a property change event of type {@link #READ_ONLY_PROPERTY}.
*
* @param readOnly Whether or not the document is read-only.
* @see #isReadOnly()
*/
public void setReadOnly(boolean readOnly) {
if (this.readOnly!=readOnly) {
this.readOnly = readOnly;
firePropertyChange(READ_ONLY_PROPERTY, !readOnly, readOnly);
}
}
/**
* Syncs this text area's "last saved or loaded" time to that of the file
* being edited, if that file is local and exists. If the file is
* remote or is local but does not yet exist, nothing happens.<p>
*
* You normally do not have to call this method, as the "last saved or
* loaded" time for {@link TextEditorPane}s is kept up-to-date internally
* during such operations as {@link #save()}, {@link #reload()}, etc.
*
* @see #getLastSaveOrLoadTime()
* @see #isModifiedOutsideEditor()
*/
public void syncLastSaveOrLoadTimeToActualFile() {
if (loc.isLocalAndExists()) {
lastSaveOrLoadTime = loc.getActualLastModified();
}
}
}

View File

@ -1,705 +0,0 @@
/*
* 10/30/2011
*
* Theme.java - A color theme for RSyntaxTextArea.
*
* 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.Color;
import java.awt.Font;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import javax.swing.text.StyleContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.fife.io.UnicodeWriter;
import org.fife.ui.rtextarea.Gutter;
/**
* A theme is a set of fonts and colors to use to style RSyntaxTextArea.
* Themes are defined in XML files that are validated against
* <code>themes.dtd</code>. This provides applications and other consumers
* with an easy way to style RSyntaxTextArea without having to use the API.<p>
*
* Sample themes are included in the source tree under the <code>/themes</code>
* folder, but are not a part of the built RSyntaxTextArea jar. Hosting
* applications are free to ship and use these themes as-is, modify them, or
* create their own.<p>
*
* Note that to save a <code>Theme</code> via {@link #save(OutputStream)},
* you must currently create a <code>Theme</code> from a text area wrapped in
* an <code>RTextScrollPane</code>, so that the color information for the
* gutter can be retrieved.
*
* @author Robert Futrell
* @version 1.0
*/
public class Theme {
private Font baseFont;
private Color bgColor;
private Color caretColor;
private Color selectionBG;
private boolean selectionRoundedEdges;
private Color currentLineHighlight;
private boolean fadeCurrentLineHighlight;
private Color marginLineColor;
private Color markAllHighlightColor;
private Color markOccurrencesColor;
private boolean markOccurrencesBorder;
private Color matchedBracketFG;
private Color matchedBracketBG;
private boolean matchedBracketHighlightBoth;
private boolean matchedBracketAnimate;
private Color hyperlinkFG;
private Color[] secondaryLanguages;
private SyntaxScheme scheme;
private Color gutterBorderColor;
private Color lineNumberColor;
private String lineNumberFont;
private int lineNumberFontSize;
private Color foldIndicatorFG;
private Color foldBG;
/**
* Private constructor, used when loading from a stream.
*/
private Theme() {
secondaryLanguages = new Color[3];
}
/**
* Creates a theme from an RSyntaxTextArea. It should be contained in
* an <code>RTextScrollPane</code> to get all gutter color information.
*
* @param textArea The text area.
*/
public Theme(RSyntaxTextArea textArea) {
baseFont = textArea.getFont();
bgColor = textArea.getBackground();
caretColor = textArea.getCaretColor();
selectionBG = textArea.getSelectionColor();
selectionRoundedEdges = textArea.getRoundedSelectionEdges();
currentLineHighlight = textArea.getCurrentLineHighlightColor();
fadeCurrentLineHighlight = textArea.getFadeCurrentLineHighlight();
marginLineColor = textArea.getMarginLineColor();
markAllHighlightColor = textArea.getMarkAllHighlightColor();
markOccurrencesColor = textArea.getMarkOccurrencesColor();
markOccurrencesBorder = textArea.getPaintMarkOccurrencesBorder();
matchedBracketBG = textArea.getMatchedBracketBGColor();
matchedBracketFG = textArea.getMatchedBracketBorderColor();
matchedBracketHighlightBoth = textArea.getPaintMatchedBracketPair();
matchedBracketAnimate = textArea.getAnimateBracketMatching();
hyperlinkFG = textArea.getHyperlinkForeground();
int count = textArea.getSecondaryLanguageCount();
secondaryLanguages = new Color[count];
for (int i=0; i<count; i++) {
secondaryLanguages[i]= textArea.getSecondaryLanguageBackground(i+1);
}
scheme = textArea.getSyntaxScheme();
Gutter gutter = RSyntaxUtilities.getGutter(textArea);
if (gutter!=null) {
bgColor = gutter.getBackground();
gutterBorderColor = gutter.getBorderColor();
lineNumberColor = gutter.getLineNumberColor();
lineNumberFont = gutter.getLineNumberFont().getFamily();
lineNumberFontSize = gutter.getLineNumberFont().getSize();
foldIndicatorFG = gutter.getFoldIndicatorForeground();
foldBG = gutter.getFoldBackground();
}
}
/**
* Applies this theme to a text area.
*
* @param textArea The text area to apply this theme to.
*/
public void apply(RSyntaxTextArea textArea) {
textArea.setFont(baseFont);
textArea.setBackground(bgColor);
textArea.setCaretColor(caretColor);
textArea.setSelectionColor(selectionBG);
textArea.setRoundedSelectionEdges(selectionRoundedEdges);
textArea.setCurrentLineHighlightColor(currentLineHighlight);
textArea.setFadeCurrentLineHighlight(fadeCurrentLineHighlight);
textArea.setMarginLineColor(marginLineColor);
textArea.setMarkAllHighlightColor(markAllHighlightColor);
textArea.setMarkOccurrencesColor(markOccurrencesColor);
textArea.setPaintMarkOccurrencesBorder(markOccurrencesBorder);
textArea.setMatchedBracketBGColor(matchedBracketBG);
textArea.setMatchedBracketBorderColor(matchedBracketFG);
textArea.setPaintMatchedBracketPair(matchedBracketHighlightBoth);
textArea.setAnimateBracketMatching(matchedBracketAnimate);
textArea.setHyperlinkForeground(hyperlinkFG);
int count = secondaryLanguages.length;
for (int i=0; i<count; i++) {
textArea.setSecondaryLanguageBackground(i+1, secondaryLanguages[i]);
}
textArea.setSyntaxScheme(scheme);
Gutter gutter = RSyntaxUtilities.getGutter(textArea);
if (gutter!=null) {
gutter.setBackground(bgColor);
gutter.setBorderColor(gutterBorderColor);
gutter.setLineNumberColor(lineNumberColor);
String fontName = lineNumberFont!=null ? lineNumberFont :
baseFont.getFamily();
int fontSize = lineNumberFontSize>0 ? lineNumberFontSize :
baseFont.getSize();
Font font = getFont(fontName, Font.PLAIN, fontSize);
gutter.setLineNumberFont(font);
gutter.setFoldIndicatorForeground(foldIndicatorFG);
gutter.setFoldBackground(foldBG);
}
}
private static final String colorToString(Color c) {
int color = c.getRGB() & 0xffffff;
String str = Integer.toHexString(color);
while (str.length()<6) {
str = "0" + str;
}
return str;
}
/**
* Returns the specified font.
*
* @param family The font family.
* @param style The style of font.
* @param size The size of the font.
* @return The font.
*/
private static Font getFont(String family, int style, int size) {
// Use StyleContext to get a composite font for Asian glyphs.
StyleContext sc = StyleContext.getDefaultStyleContext();
return sc.getFont(family, style, size);
}
/**
* Loads a theme.
*
* @param in The input stream to read from. This will be closed when this
* method returns.
* @return The theme.
* @throws IOException If an IO error occurs.
* @see #save(OutputStream)
*/
public static Theme load(InputStream in) throws IOException {
Theme theme = new Theme();
BufferedInputStream bin = new BufferedInputStream(in);
try {
XmlHandler.load(theme, bin);
} finally {
bin.close();
}
return theme;
}
/**
* Saves this theme to an output stream.
*
* @param out The output stream to write to.
* @throws IOException If an IO error occurs.
* @see #load(InputStream)
*/
public void save(OutputStream out) throws IOException {
BufferedOutputStream bout = new BufferedOutputStream(out);
try {
DocumentBuilder db = DocumentBuilderFactory.newInstance().
newDocumentBuilder();
DOMImplementation impl = db.getDOMImplementation();
Document doc = impl.createDocument(null, "RSyntaxTheme", null);
Element root = doc.getDocumentElement();
root.setAttribute("version", "1.0");
Element elem = doc.createElement("baseFont");
if (!baseFont.getFamily().equals(
RSyntaxTextArea.getDefaultFont().getFamily())) {
elem.setAttribute("family", baseFont.getFamily());
}
elem.setAttribute("size", Integer.toString(baseFont.getSize()));
root.appendChild(elem);
elem = doc.createElement("background");
elem.setAttribute("color", colorToString(bgColor));
root.appendChild(elem);
elem = doc.createElement("caret");
elem.setAttribute("color", colorToString(caretColor));
root.appendChild(elem);
elem = doc.createElement("selection");
elem.setAttribute("bg", colorToString(selectionBG));
elem.setAttribute("roundedEdges", Boolean.toString(selectionRoundedEdges));
root.appendChild(elem);
elem = doc.createElement("currentLineHighlight");
elem.setAttribute("color", colorToString(currentLineHighlight));
elem.setAttribute("fade", Boolean.toString(fadeCurrentLineHighlight));
root.appendChild(elem);
elem = doc.createElement("marginLine");
elem.setAttribute("fg", colorToString(marginLineColor));
root.appendChild(elem);
elem = doc.createElement("markAllHighlight");
elem.setAttribute("color", colorToString(markAllHighlightColor));
root.appendChild(elem);
elem = doc.createElement("markOccurrencesHighlight");
elem.setAttribute("color", colorToString(markOccurrencesColor));
elem.setAttribute("border", Boolean.toString(markOccurrencesBorder));
root.appendChild(elem);
elem = doc.createElement("matchedBracket");
elem.setAttribute("fg", colorToString(matchedBracketFG));
elem.setAttribute("bg", colorToString(matchedBracketBG));
elem.setAttribute("highlightBoth", Boolean.toString(matchedBracketHighlightBoth));
elem.setAttribute("animate", Boolean.toString(matchedBracketAnimate));
root.appendChild(elem);
elem = doc.createElement("hyperlinks");
elem.setAttribute("fg", colorToString(hyperlinkFG));
root.appendChild(elem);
elem = doc.createElement("secondaryLanguages");
for (int i=0; i<secondaryLanguages.length; i++) {
Color color = secondaryLanguages[i];
Element elem2 = doc.createElement("language");
elem2.setAttribute("index", Integer.toString(i+1));
elem2.setAttribute("bg", color==null ? "":colorToString(color));
}
elem = doc.createElement("gutterBorder");
elem.setAttribute("color", colorToString(gutterBorderColor));
root.appendChild(elem);
elem = doc.createElement("lineNumbers");
elem.setAttribute("fg", colorToString(lineNumberColor));
if (lineNumberFont!=null) {
elem.setAttribute("lineNumberFont", lineNumberFont);
}
if (lineNumberFontSize>0) {
elem.setAttribute("lineNumberFontSize",
Integer.toString(lineNumberFontSize));
}
root.appendChild(elem);
elem = doc.createElement("foldIndicator");
elem.setAttribute("fg", colorToString(foldIndicatorFG));
elem.setAttribute("iconBg", colorToString(foldBG));
root.appendChild(elem);
elem = doc.createElement("tokenStyles");
Field[] fields = TokenTypes.class.getFields();
for (int i=0; i<fields.length; i++) {
Field field = fields[i];
int value = field.getInt(null);
if (value!=TokenTypes.NUM_TOKEN_TYPES) {
Style style = scheme.getStyle(value);
if (style!=null) {
Element elem2 = doc.createElement("style");
elem2.setAttribute("token", field.getName());
Color fg = style.foreground;
if (fg!=null) {
elem2.setAttribute("fg", colorToString(fg));
}
Color bg = style.background;
if (bg!=null) {
elem2.setAttribute("bg", colorToString(bg));
}
Font font = style.font;
if (font!=null) {
if (!font.getFamily().equals(
baseFont.getFamily())) {
elem2.setAttribute("fontFamily", font.getFamily());
}
if (font.getSize()!=baseFont.getSize()) {
elem2.setAttribute("fontSize", Integer.toString(font.getSize()));
}
if (font.isBold()) {
elem2.setAttribute("bold", "true");
}
if (font.isItalic()) {
elem2.setAttribute("italic", "true");
}
}
if (style.underline) {
elem2.setAttribute("underline", "true");
}
elem.appendChild(elem2);
}
}
}
root.appendChild(elem);
DOMSource source = new DOMSource(doc);
// Use a writer instead of OutputStream to allow pretty printing.
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6337981
StreamResult result = new StreamResult(new PrintWriter(
new UnicodeWriter(bout, "UTF-8")));
TransformerFactory transFac = TransformerFactory.newInstance();
Transformer transformer = transFac.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "theme.dtd");
transformer.transform(source, result);
} catch (RuntimeException re) {
throw re; // FindBugs
} catch (Exception e) {
e.printStackTrace();
throw new IOException("Error generating XML: " + e.getMessage());
// When Java 6 is minimum required version
//throw new IOException("Error generating XML: " + e.getMessage(), e);
} finally {
bout.close();
}
}
/**
* Returns the color represented by a string. The input is expected to
* be a 6-digit hex string, optionally prefixed by a '$'. For example,
* either of the following:
* <pre>
* "$00ff00"
* "00ff00"
* </pre>
* will return <code>new Color(0, 255, 0)</code>.
*
* @param s The string to evaluate.
* @return The color.
*/
private static final Color stringToColor(String s) {
if (s!=null && (s.length()==6 || s.length()==7)) {
if (s.charAt(0)=='$') {
s = s.substring(1);
}
return new Color(Integer.parseInt(s, 16));
}
return null;
}
/**
* Loads a <code>SyntaxScheme</code> from an XML file.
*/
private static class XmlHandler extends DefaultHandler {
private Theme theme;
public void error(SAXParseException e) throws SAXException {
throw e;
}
public void fatalError(SAXParseException e) throws SAXException {
throw e;
}
public static void load(Theme theme, InputStream in) throws IOException {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setValidating(true);
try {
SAXParser parser = spf.newSAXParser();
XMLReader reader = parser.getXMLReader();
XmlHandler handler = new XmlHandler();
handler.theme = theme;
reader.setEntityResolver(handler);
reader.setContentHandler(handler);
reader.setDTDHandler(handler);
reader.setErrorHandler(handler);
InputSource is = new InputSource(in);
is.setEncoding("UTF-8");
reader.parse(is);
} catch (/*SAX|ParserConfiguration*/Exception se) {
se.printStackTrace();
throw new IOException(se.toString());
}
}
private static final int parseInt(Attributes attrs, String attr,
int def) {
int value = def;
String temp = attrs.getValue(attr);
if (temp != null) {
try {
value = Integer.parseInt(temp);
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
}
return value;
}
public InputSource resolveEntity(String publicID,
String systemID) throws SAXException {
return new InputSource(getClass().
getResourceAsStream("/theme.dtd"));
}
public void startElement(String uri, String localName, String qName,
Attributes attrs) {
if ("background".equals(qName)) {
String color = attrs.getValue("color");
if (color!=null) {
theme.bgColor = stringToColor(color);
}
else {
String img = attrs.getValue("image");
if (img!=null) {
throw new IllegalArgumentException("Not yet implemented");
}
}
}
// The base font to use in the editor.
else if ("baseFont".equals(qName)) {
String family = attrs.getValue("family");
int size = Integer.parseInt(attrs.getValue("size"));
if (family!=null) {
theme.baseFont = getFont(family, Font.PLAIN, size);
}
else {
theme.baseFont = RSyntaxTextArea.getDefaultFont();
theme.baseFont = theme.baseFont.deriveFont(size*1f);
}
}
else if ("caret".equals(qName)) {
String color = attrs.getValue("color");
theme.caretColor = stringToColor(color);
}
else if ("currentLineHighlight".equals(qName)) {
String color = attrs.getValue("color");
theme.currentLineHighlight = stringToColor(color);
String fadeStr = attrs.getValue("fade");
boolean fade = Boolean.valueOf(fadeStr).booleanValue();
theme.fadeCurrentLineHighlight = fade;
}
else if ("foldIndicator".equals(qName)) {
String color = attrs.getValue("fg");
theme.foldIndicatorFG = stringToColor(color);
color = attrs.getValue("iconBg");
theme.foldBG = stringToColor(color);
}
else if ("gutterBorder".equals(qName)) {
String color = attrs.getValue("color");
theme.gutterBorderColor = stringToColor(color);
}
else if ("lineNumbers".equals(qName)) {
String color = attrs.getValue("fg");
theme.lineNumberColor = stringToColor(color);
theme.lineNumberFont = attrs.getValue("fontFamily");
theme.lineNumberFontSize = parseInt(attrs, "fontSize", -1);
}
else if ("marginLine".equals(qName)) {
String color = attrs.getValue("fg");
theme.marginLineColor = stringToColor(color);
}
else if ("markAllHighlight".equals(qName)) {
String color = attrs.getValue("color");
theme.markAllHighlightColor = stringToColor(color);
}
else if ("markOccurrencesHighlight".equals(qName)) {
String color = attrs.getValue("color");
theme.markOccurrencesColor = stringToColor(color);
String border = attrs.getValue("border");
theme.markOccurrencesBorder = Boolean.valueOf(border).booleanValue();
}
else if ("matchedBracket".equals(qName)) {
String fg = attrs.getValue("fg");
theme.matchedBracketFG = stringToColor(fg);
String bg = attrs.getValue("bg");
theme.matchedBracketBG = stringToColor(bg);
String highlightBoth = attrs.getValue("highlightBoth");
theme.matchedBracketHighlightBoth = Boolean.valueOf(highlightBoth).booleanValue();
String animate = attrs.getValue("animate");
theme.matchedBracketAnimate = Boolean.valueOf(animate).booleanValue();
}
else if ("hyperlinks".equals(qName)) {
String fg = attrs.getValue("fg");
theme.hyperlinkFG = stringToColor(fg);
}
else if ("language".equals(qName)) {
String indexStr = attrs.getValue("index");
int index = Integer.parseInt(indexStr) - 1;
if (theme.secondaryLanguages.length>index) { // Sanity
Color bg = stringToColor(attrs.getValue("bg"));
theme.secondaryLanguages[index] = bg;
}
}
else if ("selection".equals(qName)) {
String color = attrs.getValue("bg");
theme.selectionBG = stringToColor(color);
String roundedStr = attrs.getValue("roundedEdges");
theme.selectionRoundedEdges = Boolean.valueOf(roundedStr).booleanValue();
}
// Start of the syntax scheme definition
else if ("tokenStyles".equals(qName)) {
theme.scheme = new SyntaxScheme(theme.baseFont, false);
}
// A style in the syntax scheme
else if ("style".equals(qName)) {
String type = attrs.getValue("token");
Field field = null;
try {
field = Token.class.getField(type);
} catch (RuntimeException re) {
throw re; // FindBugs
} catch (Exception e) {
System.err.println("Invalid token type: " + type);
return;
}
if (field.getType()==int.class) {
int index = 0;
try {
index = field.getInt(theme.scheme);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
}
String fgStr = attrs.getValue("fg");
Color fg = stringToColor(fgStr);
theme.scheme.getStyle(index).foreground = fg;
String bgStr = attrs.getValue("bg");
Color bg = stringToColor(bgStr);
theme.scheme.getStyle(index).background = bg;
Font font = theme.baseFont;
String familyName = attrs.getValue("fontFamily");
if (familyName!=null) {
font = getFont(familyName, font.getStyle(),
font.getSize());
}
String sizeStr = attrs.getValue("fontSize");
if (sizeStr!=null) {
try {
float size = Float.parseFloat(sizeStr);
size = Math.max(size, 1f);
font = font.deriveFont(size);
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
}
theme.scheme.getStyle(index).font = font;
boolean styleSpecified = false;
boolean bold = false;
boolean italic = false;
String boldStr = attrs.getValue("bold");
if (boldStr!=null) {
bold = Boolean.valueOf(boldStr).booleanValue();
styleSpecified = true;
}
String italicStr = attrs.getValue("italic");
if (italicStr!=null) {
italic = Boolean.valueOf(italicStr).booleanValue();
styleSpecified = true;
}
if (styleSpecified) {
int style = 0;
if (bold) { style |= Font.BOLD; }
if (italic) { style |= Font.ITALIC; }
Font orig = theme.scheme.getStyle(index).font;
theme.scheme.getStyle(index).font =
orig.deriveFont(style);
}
String ulineStr = attrs.getValue("underline");
if (ulineStr!=null) {
boolean uline= Boolean.valueOf(ulineStr).booleanValue();
theme.scheme.getStyle(index).underline = uline;
}
}
}
}
public void warning(SAXParseException e) throws SAXException {
throw e;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
/*
* 10/28/2004
*
* TokenFactory.java - Interface for a class that generates tokens of some 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 javax.swing.text.Segment;
/**
* Interface for a class that generates tokens somehow.
*
* @author Robert Futrell
* @version 0.1
*/
interface TokenFactory {
/**
* Returns a null token.
*
* @return A null token.
*/
public Token createToken();
/**
* Returns a token.
*
* @param line The segment from which to get the token's text.
* @param beg The starting offset of the token's text in the segment.
* @param end The ending offset of the token's text in the segment.
* @param startOffset The offset in the document of the token.
* @param type The type of token.
* @return The token.
*/
public Token createToken(final Segment line, final int beg,
final int end, final int startOffset, final int type);
/**
* Returns a token.
*
* @param line The char array from which to get the token's text.
* @param beg The starting offset of the token's text in the char array.
* @param end The ending offset of the token's text in the char array.
* @param startOffset The offset in the document of the token.
* @param type The type of token.
* @return The token.
*/
public Token createToken(final char[] line, final int beg,
final int end, final int startOffset, final int type);
/**
* Resets the state of this token maker, if necessary.
* FIXME: Improve documentation.
*/
public void resetAllTokens();
}

View File

@ -1,165 +0,0 @@
/*
* 02/24/2004
*
* TokenMaker.java - An object that can take a chunk of text and return a
* linked list of <code>Token</code>s representing it.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.Action;
import javax.swing.text.Segment;
/**
* An implementation of <code>TokenMaker</code> is a class that turns text into
* a linked list of <code>Token</code>s for syntax highlighting
* in a particular language.
*
* @see Token
* @see AbstractTokenMaker
*
* @author Robert Futrell
* @version 0.2
*/
public interface TokenMaker {
/**
* Adds a null token to the end of the current linked list of tokens.
* This should be put at the end of the linked list whenever the last
* token on the current line is NOT a multi-line token.
*/
public void addNullToken();
/**
* Adds the token specified to the current linked list of tokens.
*
* @param array The character array from which to get the text.
* @param start Start offset in <code>segment</code> of token.
* @param end End offset in <code>segment</code> of token.
* @param tokenType The token's type.
* @param startOffset The offset in the document at which this token
* occurs.
*/
public void addToken(char[] array, int start, int end, int tokenType,
int startOffset);
/**
* Returns whether this programming language uses curly braces
* ('<tt>{</tt>' and '<tt>}</tt>') to denote code blocks.
*
* @return Whether curly braces denote code blocks.
*/
public boolean getCurlyBracesDenoteCodeBlocks();
/**
* Returns the last token on this line's type if the token is "unfinished",
* or {@link Token#NULL} if it was finished. For example, if C-style
* syntax highlighting is being implemented, and <code>text</code>
* contained a line of code that contained the beginning of a comment but
* no end-comment marker ("*\/"), then this method would return
* {@link Token#COMMENT_MULTILINE} for that line. This is useful
* for doing syntax highlighting.
*
* @param text The line of tokens to examine.
* @param initialTokenType The token type to start with (i.e., the value
* of <code>getLastTokenTypeOnLine</code> for the line before
* <code>text</code>).
* @return The last token on this line's type, or {@link Token#NULL}
* if the line was completed.
*/
public int getLastTokenTypeOnLine(Segment text, int initialTokenType);
/**
* Returns the text to place at the beginning and end of a
* line to "comment" it in a this programming language.
*
* @return The start and end strings to add to a line to "comment"
* it out. A <code>null</code> value for either means there
* is no string to add for that part. A value of
* <code>null</code> for the array means this language
* does not support commenting/uncommenting lines.
*/
public String[] getLineCommentStartAndEnd();
/**
* Returns an action to handle "insert break" key presses (i.e. Enter).
*
* @return The action, or <code>null</code> if the default action should
* be used.
*/
public Action getInsertBreakAction();
/**
* Returns whether tokens of the specified type should have "mark
* occurrences" enabled for the current programming language.
*
* @param type The token type.
* @return Whether tokens of this type should have "mark occurrences"
* enabled.
*/
public boolean getMarkOccurrencesOfTokenType(int type);
/**
* If a line ends in the specified token, this method returns whether
* a new line inserted after that line should be indented.
*
* @param token The token the previous line ends with.
* @return Whether the next line should be indented.
*/
public boolean getShouldIndentNextLineAfter(Token token);
/**
* Returns the first token in the linked list of tokens generated
* from <code>text</code>. This method must be implemented by
* subclasses so they can correctly implement syntax highlighting.
*
* @param text The text from which to get tokens.
* @param initialTokenType The token type we should start with.
* @param startOffset The offset into the document at which
* <code>text</code> starts.
* @return The first <code>Token</code> in a linked list representing
* the syntax highlighted text.
*/
public Token getTokenList(Segment text, int initialTokenType,
int startOffset);
/**
* Returns whether this language is a markup language.
*
* @return Whether this language is markup.
*/
public boolean isMarkupLanguage();
/**
* Returns whether whitespace is visible.
*
* @return Whether whitespace is visible.
* @see #setWhitespaceVisible(boolean)
*/
public boolean isWhitespaceVisible();
/**
* Sets whether tokens are generated that "show" whitespace.
*
* @param visible Whether whitespace should be visible.
* @see #isWhitespaceVisible()
*/
public void setWhitespaceVisible(boolean visible);
}

View File

@ -1,272 +0,0 @@
/*
* 08/26/2004
*
* TokenMakerBase.java - A base class for token makers.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.Action;
import javax.swing.text.Segment;
/**
* Base class for token makers.
*
* @author Robert Futrell
* @version 1.0
*/
abstract class TokenMakerBase implements TokenMaker {
/**
* The first token in the returned linked list.
*/
protected Token firstToken;
/**
* Used in the creation of the linked list.
*/
protected Token currentToken;
/**
* Used in the creation of the linked list.
*/
protected Token previousToken;
/**
* The factory that gives us our tokens to use.
*/
private TokenFactory tokenFactory;
/**
* "0" implies this is the "main" language being highlighted. Positive
* values imply various "secondary" or "embedded" languages, such as CSS
* or JavaScript in HTML. While this value is non-zero, tokens will be
* generated with this language index so they can (possibly) be painted
* differently, so "embedded" languages can be rendered with a special
* background.
*/
private int languageIndex;
/**
* Constructor.
*/
public TokenMakerBase() {
firstToken = currentToken = previousToken = null;
tokenFactory = new DefaultTokenFactory();
}
/**
* {@inheritDoc}
*/
public void addNullToken() {
if (firstToken==null) {
firstToken = tokenFactory.createToken();
currentToken = firstToken;
}
else {
currentToken.setNextToken(tokenFactory.createToken());
previousToken = currentToken;
currentToken = currentToken.getNextToken();
}
}
/**
* Adds the token specified to the current linked list of tokens.
*
* @param segment <code>Segment</code> to get text from.
* @param start Start offset in <code>segment</code> of token.
* @param end End offset in <code>segment</code> of token.
* @param tokenType The token's type.
* @param startOffset The offset in the document at which this token
* occurs.
*/
public void addToken(Segment segment, int start, int end, int tokenType,
int startOffset) {
addToken(segment.array, start,end, tokenType, startOffset);
}
/**
* {@inheritDoc}
*/
public void addToken(char[] array, int start, int end, int tokenType,
int startOffset) {
addToken(array, start, end, tokenType, startOffset, false);
}
/**
* Adds the token specified to the current linked list of tokens.
*
* @param array The character array.
* @param start The starting offset in the array.
* @param end The ending offset in the array.
* @param tokenType The token's type.
* @param startOffset The offset in the document at which this token
* occurs.
* @param hyperlink Whether this token is a hyperlink.
*/
public void addToken(char[] array, int start, int end, int tokenType,
int startOffset, boolean hyperlink) {
if (firstToken==null) {
firstToken = tokenFactory.createToken(array, start, end,
startOffset, tokenType);
currentToken = firstToken; // previous token is still null.
}
else {
currentToken.setNextToken(tokenFactory.createToken(array,
start,end, startOffset, tokenType));
previousToken = currentToken;
currentToken = currentToken.getNextToken();
}
currentToken.setLanguageIndex(languageIndex);
currentToken.setHyperlink(hyperlink);
}
/**
* Returns whether this programming language uses curly braces
* ('<tt>{</tt>' and '<tt>}</tt>') to denote code blocks.<p>
*
* The default implementation returns <code>false</code>; subclasses can
* override this method if necessary.
*
* @return Whether curly braces denote code blocks.
*/
public boolean getCurlyBracesDenoteCodeBlocks() {
return false;
}
/**
* Returns an action to handle "insert break" key presses (i.e. Enter).
* The default implementation returns <code>null</code>. Subclasses
* can override.
*
* @return The default implementation always returns <code>null</code>.
*/
public Action getInsertBreakAction() {
return null;
}
/**
* {@inheritDoc}
*/
public int getLastTokenTypeOnLine(Segment text, int initialTokenType) {
// Last parameter doesn't matter if we're not painting.
Token t = getTokenList(text, initialTokenType, 0);
while (t.getNextToken()!=null)
t = t.getNextToken();
return t.type;
}
/**
* {@inheritDoc}
*/
public String[] getLineCommentStartAndEnd() {
return null;
}
/**
* Returns whether tokens of the specified type should have "mark
* occurrences" enabled for the current programming language. The default
* implementation returns true if <tt>type</tt> is {@link Token#IDENTIFIER}.
* Subclasses can override this method to support other token types, such
* as {@link Token#VARIABLE}.
*
* @param type The token type.
* @return Whether tokens of this type should have "mark occurrences"
* enabled.
*/
public boolean getMarkOccurrencesOfTokenType(int type) {
return type==Token.IDENTIFIER;
}
/**
* The default implementation returns <code>false</code> always. Languages
* that wish to better support auto-indentation can override this method.
*
* @param token The token the previous line ends with.
* @return Whether the next line should be indented.
*/
public boolean getShouldIndentNextLineAfter(Token token) {
return false;
}
/**
* The default implementation returns <code>false</code> always.
* Subclasses that are highlighting a markup language should override this
* method to return <code>true</code>.
*
* @return <code>false</code> always.
*/
public boolean isMarkupLanguage() {
return false;
}
/**
* {@inheritDoc}
*/
public boolean isWhitespaceVisible() {
return tokenFactory instanceof VisibleWhitespaceTokenFactory;
}
/**
* Deletes the linked list of tokens so we can begin anew. This should
* never have to be called by the programmer, as it is automatically
* called whenever the user calls
* {@link #getLastTokenTypeOnLine(Segment, int)} or
* {@link #getTokenList(Segment, int, int)}.
*/
protected void resetTokenList() {
firstToken = currentToken = previousToken = null;
tokenFactory.resetAllTokens();
}
/**
* Sets the language index to assign to tokens moving forward. This
* property is used to designate tokens as being in "secondary" languages
* (such as CSS or JavaScript in HTML).
*
* @param languageIndex The new language index. A value of
* <code>0</code> denotes the "main" language, any positive value
* denotes a specific secondary language. Negative values will
* be treated as <code>0</code>.
*/
public void setLanguageIndex(int languageIndex) {
this.languageIndex = Math.max(0, languageIndex);
}
/**
* {@inheritDoc}
*/
public void setWhitespaceVisible(boolean visible) {
// FIXME: Initialize with the proper sizes.
tokenFactory = visible ? new VisibleWhitespaceTokenFactory() :
new DefaultTokenFactory();
}
}

View File

@ -1,124 +0,0 @@
/*
* 12/12/2008
*
* TokenMakerFactory.java - A factory for TokenMakers.
*
* 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.util.Set;
import org.fife.ui.rsyntaxtextarea.modes.PlainTextTokenMaker;
/**
* A factory that maps syntax styles to {@link TokenMaker}s capable of splitting
* text into tokens for those syntax styles.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class TokenMakerFactory {
/**
* If this system property is set, a custom <code>TokenMakerFactory</code>
* of the specified class will be used as the default token maker factory.
*/
public static final String PROPERTY_DEFAULT_TOKEN_MAKER_FACTORY =
"TokenMakerFactory";
/**
* The singleton default <code>TokenMakerFactory</code> instance.
*/
private static TokenMakerFactory DEFAULT_INSTANCE;
/**
* Returns the default <code>TokenMakerFactory</code> instance. This is
* the factory used by all {@link RSyntaxDocument}s by default.
*
* @return The factory.
* @see #setDefaultInstance(TokenMakerFactory)
*/
public static synchronized TokenMakerFactory getDefaultInstance() {
if (DEFAULT_INSTANCE==null) {
String clazz = null;
try {
clazz= System.getProperty(PROPERTY_DEFAULT_TOKEN_MAKER_FACTORY);
} catch (java.security.AccessControlException ace) {
clazz = null; // We're in an applet; take default.
}
if (clazz==null) {
clazz = "org.fife.ui.rsyntaxtextarea.DefaultTokenMakerFactory";
}
try {
DEFAULT_INSTANCE = (TokenMakerFactory)Class.forName(clazz).
newInstance();
} catch (RuntimeException re) { // FindBugs
throw re;
} catch (Exception e) {
e.printStackTrace();
throw new InternalError("Cannot find TokenMakerFactory: " +
clazz);
}
}
return DEFAULT_INSTANCE;
}
/**
* Returns a {@link TokenMaker} for the specified key.
*
* @param key The key.
* @return The corresponding <code>TokenMaker</code>, or
* {@link PlainTextTokenMaker} if none matches the specified key.
*/
public final TokenMaker getTokenMaker(String key) {
TokenMaker tm = getTokenMakerImpl(key);
if (tm==null) {
tm = new PlainTextTokenMaker();
}
return tm;
}
/**
* Returns a {@link TokenMaker} for the specified key.
*
* @param key The key.
* @return The corresponding <code>TokenMaker</code>, or <code>null</code>
* if none matches the specified key.
*/
protected abstract TokenMaker getTokenMakerImpl(String key);
/**
* Returns the set of keys that this factory maps to token makers.
*
* @return The set of keys.
*/
public abstract Set keySet();
/**
* Sets the default <code>TokenMakerFactory</code> instance. This is
* the factory used by all future {@link RSyntaxDocument}s by default.
* <code>RSyntaxDocument</code>s that have already been created are not
* affected.
*
* @param tmf The factory.
* @throws IllegalArgumentException If <code>tmf</code> is
* <code>null</code>.
* @see #getDefaultInstance()
*/
public static synchronized void setDefaultInstance(TokenMakerFactory tmf) {
if (tmf==null) {
throw new IllegalArgumentException("tmf cannot be null");
}
DEFAULT_INSTANCE = tmf;
}
}

View File

@ -1,276 +0,0 @@
/*
* 08/26/2004
*
* TokenMap.java - Similar to a Map in Java, only designed specifically for
* org.fife.ui.rsyntaxtextarea.Tokens.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
import javax.swing.text.Segment;
/**
* A hash table for reserved words, etc. defined by a {@link TokenMaker}.
* This class is designed for the quick lookup of tokens, as it can compare
* <code>Segment</code>s without the need to allocate a new string.<p>
*
* The <code>org.fife.ui.rsyntaxtextarea</code> package uses this class to help
* identify reserved words in programming languages. An instance of
* {@link TokenMaker} will create and initialize an instance of this class
* containing all reserved words, data types, and all other words that need to
* be syntax-highlighted for that particular language. When the token maker
* parses a line and identifies an individual token, it is looked up in the
* <code>TokenMap</code> to see if it should be syntax-highlighted.
*
* @author Robert Futrell
* @version 0.6
*/
public class TokenMap {
private int size;
private TokenMapToken[] tokenMap;
private boolean ignoreCase;
private static final int DEFAULT_TOKEN_MAP_SIZE = 52;
/**
* Constructs a new token map that is case-sensitive.
*/
public TokenMap() {
this(DEFAULT_TOKEN_MAP_SIZE);
}
/**
* Constructs a new token map that is case-sensitive.
*
* @param size The size of the token map.
*/
public TokenMap(int size) {
this(size, false);
}
/**
* Constructs a new token map.
*
* @param ignoreCase Whether or not this token map should ignore case
* when comparing tokens.
*/
public TokenMap(boolean ignoreCase) {
this(DEFAULT_TOKEN_MAP_SIZE, ignoreCase);
}
/**
* Constructs a new token map.
*
* @param size The size of the token map.
* @param ignoreCase Whether or not this token map should ignore case
* when comparing tokens.
*/
public TokenMap(int size, boolean ignoreCase) {
this.size = size;
tokenMap = new TokenMapToken[size];
this.ignoreCase = ignoreCase;
}
/**
* Adds a token to a specified bucket in the token map.
*
* @param bucket The bucket in which to add the token.
* @param token The token to add.
*/
private void addTokenToBucket(int bucket, TokenMapToken token) {
TokenMapToken old = tokenMap[bucket];
token.nextToken = old;
tokenMap[bucket] = token;
}
/**
* Returns the token type associated with the given text, if the given
* text is in this token map. If it isn't, <code>-1</code> is returned.
*
* @param text The segment from which to get the text to compare.
* @param start The starting index in the segment of the text.
* @param end The ending index in the segment of the text.
* @return The token type associated with the given text, or
* <code>-1</code> if this token was not specified in this map.
*/
public int get(Segment text, int start, int end) {
return get(text.array, start, end);
}
/**
* Returns the token type associated with the given text, if the given
* text is in this token map. If it isn't, <code>-1</code> is returned.
*
* @param array1 An array of characters containing the text.
* @param start The starting index in the array of the text.
* @param end The ending index in the array of the text.
* @return The token type associated with the given text, or
* <code>-1</code> if this token was not specified in this map.
*/
public int get(char[] array1, int start, int end) {
int length1 = end - start + 1;
int hash = getHashCode(array1, start, length1);
TokenMapToken token = tokenMap[hash];
char[] array2;
int offset2;
int offset1;
int length;
/* We check whether or not to ignore case before doing any looping to
* minimize the number of extraneous comparisons we do. This makes
* for slightly redundant code, but it'll be a little more efficient.
*/
// If matches are case-sensitive (C, C++, Java, etc.)...
if (ignoreCase==false) {
mainLoop:
while (token!=null) {
if (token.length==length1) {
array2 = token.text;
offset2 = token.offset;
offset1 = start;
length = length1;
while (length-- > 0) {
if (array1[offset1++]!=array2[offset2++]) {
token = token.nextToken;
continue mainLoop;
}
}
return token.tokenType;
}
token = token.nextToken;
}
}
// If matches are NOT case-sensitive (HTML)...
// Note that all tokens saved in this map were converted to
// lower-case already.
else {
mainLoop2:
while (token!=null) {
if (token.length==length1) {
array2 = token.text;
offset2 = token.offset;
offset1 = start;
length = length1;
while (length-- > 0) {
if (RSyntaxUtilities.toLowerCase(
array1[offset1++]) != array2[offset2++]) {
token = token.nextToken;
continue mainLoop2;
}
}
return token.tokenType;
}
token = token.nextToken;
}
}
// Didn't match any of the tokens in the bucket.
return -1;
}
/**
* Returns the hash code for a given string.
*
* @param text The text to hash.
* @param offset The offset into the text at which to start hashing.
* @param length The last character in the text to hash.
* @return The hash code.
*/
private final int getHashCode(char[] text, int offset, int length) {
return (RSyntaxUtilities.toLowerCase(text[offset]) +
RSyntaxUtilities.toLowerCase(text[offset+length-1])) % size;
}
/**
* Returns whether this token map ignores case when checking for tokens.
* This property is set in the constructor and cannot be changed, as this
* is an intrinsic property of a particular programming language.
*
* @return Whether or not this token maker is ignoring case.
*/
protected boolean isIgnoringCase() {
return ignoreCase;
}
/**
* Adds a string to this token map.
*
* @param string The string to add.
* @param tokenType The type of token the string is.
*/
public void put(final String string, final int tokenType) {
if (isIgnoringCase())
put(string.toLowerCase().toCharArray(), tokenType);
else
put(string.toCharArray(), tokenType);
}
/**
* Adds a string to this token map. The char array passed-in will be used
* as the actual data for the token, so it may well be modified (such as
* lower-casing it if <code>ignoreCase</code> is <code>true</code>). This
* shouldn't be an issue though as this method is only called from the
* public <code>put</code> method, which allocates a new char array.
*
* @param string The string to add.
* @param tokenType The type of token the string is.
*/
private void put(char[] string, int tokenType) {
int hashCode = getHashCode(string, 0, string.length);
addTokenToBucket(hashCode, new TokenMapToken(string, tokenType));
}
/**
* The "token" used by a token map. Note that this isn't the same thing
* as the {@link Token} class, but it's basically a 1-1 correspondence
* for reserved words, etc.
*/
private static class TokenMapToken {
char[] text;
int offset;
int length;
int tokenType;
TokenMapToken nextToken;
TokenMapToken(char[] text, int tokenType) {
this.text = text;
this.offset = 0;
this.length = text.length;
this.tokenType = tokenType;
}
public String toString() {
return "[TokenMapToken: " + new String(text,offset,length) + "]";
}
}
}

View File

@ -1,61 +0,0 @@
/*
* 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.<p>
*
* 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 <i>physical</i> 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 <code>offset</code>, 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 <code>offset</code>, <code>null</code> is returned.
*/
public Token getTokenListForPhysicalLineAbove(int offset);
/**
* Returns a token list for the <i>physical</i> 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 <code>offset</code>, 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 <code>offset</code>, <code>null</code> is returned.
*/
public Token getTokenListForPhysicalLineBelow(int offset);
}

View File

@ -1,81 +0,0 @@
/*
* 12/04/2011
*
* TokenTypes.java - All token types supported by RSyntaxTextArea.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* All token types supported by RSyntaxTextArea.<p>
*
* Note that all valid token types are &gt;= 0, so extensions of the TokenMaker
* class are free to internally use all ints &lt; 0 ONLY for "end-of-line"
* style markers; they are ignored by painting implementations.
*
* @author Robert Futrell
* @version 1.0
*/
public interface TokenTypes {
/**
* Tokens of type <code>NULL</code> mark the end of lines with no
* multi-line token at the end (such as a block comment in C++).
*/
public static final int NULL = 0;
public static final int COMMENT_EOL = 1;
public static final int COMMENT_MULTILINE = 2;
public static final int COMMENT_DOCUMENTATION = 3;
public static final int COMMENT_KEYWORD = 4;
public static final int COMMENT_MARKUP = 5;
public static final int RESERVED_WORD = 6;
public static final int RESERVED_WORD_2 = 7;
public static final int FUNCTION = 8;
public static final int LITERAL_BOOLEAN = 9;
public static final int LITERAL_NUMBER_DECIMAL_INT = 10;
public static final int LITERAL_NUMBER_FLOAT = 11;
public static final int LITERAL_NUMBER_HEXADECIMAL = 12;
public static final int LITERAL_STRING_DOUBLE_QUOTE = 13;
public static final int LITERAL_CHAR = 14;
public static final int LITERAL_BACKQUOTE = 15;
public static final int DATA_TYPE = 16;
public static final int VARIABLE = 17;
public static final int REGEX = 18;
public static final int ANNOTATION = 19;
public static final int IDENTIFIER = 20;
public static final int WHITESPACE = 21;
public static final int SEPARATOR = 22;
public static final int OPERATOR = 23;
public static final int PREPROCESSOR = 24;
public static final int MARKUP_TAG_DELIMITER = 25;
public static final int MARKUP_TAG_NAME = 26;
public static final int MARKUP_TAG_ATTRIBUTE = 27;
public static final int MARKUP_TAG_ATTRIBUTE_VALUE = 28;
public static final int MARKUP_PROCESSING_INSTRUCTION = 29;
public static final int MARKUP_CDATA = 30;
public static final int ERROR_IDENTIFIER = 31;
public static final int ERROR_NUMBER_FORMAT = 32;
public static final int ERROR_STRING_DOUBLE = 33;
public static final int ERROR_CHAR = 34;
public static final int NUM_TOKEN_TYPES = 35;
}

View File

@ -1,153 +0,0 @@
/*
* 11/13/2008
*
* URLFileLocation.java - The location of a file at a (remote) URL.
*
* 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.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
/**
* The location of a file at a (remote) URL.
*
* @author Robert Futrell
* @version 1.0
*/
class URLFileLocation extends FileLocation {
/**
* URL of the remote file.
*/
private URL url;
/**
* A prettied-up full path of the URL (password removed, etc.).
*/
private String fileFullPath;
/**
* A prettied-up filename (leading slash, and possibly "<code>%2F</code>",
* removed).
*/
private String fileName;
/**
* Constructor.
*
* @param url The URL of the file.
*/
URLFileLocation(URL url) {
this.url = url;
fileFullPath = createFileFullPath();
fileName = createFileName();
}
/**
* Creates a "prettied-up" URL to use. This will be stripped of
* sensitive information such as passwords.
*
* @return The full path to use.
*/
private String createFileFullPath() {
String fullPath = url.toString();
fullPath = fullPath.replaceFirst("://([^:]+)(?:.+)@", "://$1@");
return fullPath;
}
/**
* Creates the "prettied-up" filename to use.
*
* @return The base name of the file of this URL.
*/
private String createFileName() {
String fileName = url.getPath();
if (fileName.startsWith("/%2F/")) { // Absolute path
fileName = fileName.substring(4);
}
else if (fileName.startsWith("/")) { // All others
fileName = fileName.substring(1);
}
return fileName;
}
/**
* Returns the last time this file was modified, or
* {@link TextEditorPane#LAST_MODIFIED_UNKNOWN} if this value cannot be
* computed (such as for a remote file).
*
* @return The last time this file was modified. This will always be
* {@link TextEditorPane#LAST_MODIFIED_UNKNOWN} for URL's.
*/
protected long getActualLastModified() {
return TextEditorPane.LAST_MODIFIED_UNKNOWN;
}
/**
* {@inheritDoc}
*/
public String getFileFullPath() {
return fileFullPath;
}
/**
* {@inheritDoc}
*/
public String getFileName() {
return fileName;
}
/**
* {@inheritDoc}
*/
protected InputStream getInputStream() throws IOException {
return url.openStream();
}
/**
* {@inheritDoc}
*/
protected OutputStream getOutputStream() throws IOException {
return url.openConnection().getOutputStream();
}
/**
* Returns whether this file location is a local file.
*
* @return Whether this is a local file.
* @see #isLocalAndExists()
*/
public boolean isLocal() {
return "file".equalsIgnoreCase(url.getProtocol());
}
/**
* Returns whether this file location is a local file and already
* exists. This method always returns <code>false</code> since we
* cannot check this value easily.
*
* @return <code>false</code> always.
* @see #isLocal()
*/
public boolean isLocalAndExists() {
return false;
}
}

View File

@ -1,241 +0,0 @@
/*
* 10/28/2004
*
* VisibleWhitespaceToken.java - Token that paints special symbols for its
* whitespace characters (space and tab).
*
* 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.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
/**
* This token class paints spaces and tabs with special symbols so the user
* can see the whitespace in his document. Rendering hints are honored.<p>
*
* The current implementation paints as follows:
* <ul>
* <li>The first tab or space, if any, is found in the token.</li>
* <li>If a tab was found, all characters up to it are painted as a
* group.</li>
* <li>If a space was found, all characters up to and including it are
* painted (it is painted with a special symbol to denote it as
* a space).</li>
* <li>If neither a tab nor a whitespace was found, all characters in the
* token are painted.</li>
* <li>Repeat until all characters are painted.</li>
* </ul>
* This means that rendering hints are applied to all groups of characters
* within a token, excluding whitespace and tabs.<p>
*
* A problem with this implementation is that FontMetrics.charsWidth() is still
* used to calculate the width of a group of chars painted. Thus, the group of
* characters will be painted with the rendering hints specified, but the
* following tab (or group of characters if the current group was the end of a
* token) will not necessarily be painted at the proper x-coordinate (as
* FontMetrics.charsWidth() returns an <code>int</code> and not a
* <code>float</code>). The way around this would be to calculate the token's
* width in such a way that a float is returned (Font.getStringBounds()?).
*
* @author Robert Futrell
* @version 0.5
* @see Token
* @see DefaultToken
*/
public class VisibleWhitespaceToken extends DefaultToken {
private Rectangle2D.Float dotRect;
/**
* Creates a "null token." The token itself is not null; rather, it
* signifies that it is the last token in a linked list of tokens and
* that it is not part of a "multi-line token."
*/
public VisibleWhitespaceToken() {
super();
dotRect = new Rectangle2D.Float(0,0, 1,1);
}
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public VisibleWhitespaceToken(final Segment line, final int beg,
final int end, final int startOffset, final int type) {
this(line.array, beg,end, startOffset, type);
}
/**
* Constructor.
*
* @param line The segment from which to get the token.
* @param beg The first character's position in <code>line</code>.
* @param end The last character's position in <code>line</code>.
* @param startOffset The offset into the document at which this
* token begins.
* @param type A token type listed as "generic" above.
*/
public VisibleWhitespaceToken(final char[] line, final int beg,
final int end, final int startOffset, final int type) {
super(line, beg,end, startOffset, type);
}
/**
* Paints this token, using special symbols for whitespace characters.
*
* @param g The graphics context in which to paint.
* @param x The x-coordinate at which to paint.
* @param y The y-coordinate at which to paint.
* @param host The text area this token is in.
* @param e How to expand tabs.
* @param clipStart The left boundary of the clip rectangle in which we're
* painting. This optimizes painting by allowing us to not paint
* not paint when this token is "to the left" of the clip rectangle.
* @return The x-coordinate representing the end of the painted text.
*/
public final float paint(Graphics2D g, float x, float y,
RSyntaxTextArea host, TabExpander e,
float clipStart) {
int origX = (int)x;
int end = textOffset + textCount;
float nextX = x;
int flushLen = 0;
int flushIndex = textOffset;
Color fg = host.getForegroundForToken(this);
Color bg = host.getBackgroundForToken(this);
g.setFont(host.getFontForTokenType(type));
FontMetrics fm = host.getFontMetricsForTokenType(type);
int ascent = fm.getAscent();
int height = fm.getHeight();
for (int i=textOffset; i<end; i++) {
switch (text[i]) {
case '\t':
// Fill in background.
nextX = x+fm.charsWidth(text, flushIndex,flushLen);
float nextNextX = e.nextTabStop(nextX, 0);
if (bg!=null) {
paintBackground(x,y, nextNextX-x,height, g,
ascent, host, bg);
}
g.setColor(fg);
// Paint chars cached before the tab.
if (flushLen > 0) {
g.drawChars(text, flushIndex, flushLen, (int)x,(int)y);
flushLen = 0;
}
flushIndex = i + 1;
// Draw an arrow representing the tab.
int halfHeight = height / 2;
int quarterHeight = halfHeight / 2;
int ymid = (int)y - ascent + halfHeight;
g.drawLine((int)nextX,ymid, (int)nextNextX,ymid);
g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid-quarterHeight);
g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid+quarterHeight);
x = nextNextX;
break;
case ' ':
// NOTE: There is a little bit of a "fudge factor"
// here when "smooth text" is enabled, as "width"
// below may well not be the width given to the space
// by fm.charsWidth() (it depends on how it places the
// space with respect to the preceding character).
// But, we assume the approximation is close enough for
// our drawing a dot for the space.
// "flushLen+1" ensures text is aligned correctly (or,
// aligned the same as in getWidth()).
nextX = x+fm.charsWidth(text, flushIndex,flushLen+1);
int width = fm.charWidth(' ');
// Paint background.
if (bg!=null) {
paintBackground(x,y, nextX-x,height, g,
ascent, host, bg);
}
g.setColor(fg);
// Paint chars before space.
if (flushLen>0) {
g.drawChars(text, flushIndex, flushLen, (int)x,(int)y);
flushLen = 0;
}
// Paint a dot representing the space.
dotRect.x = nextX - width/2.0f; // "2.0f" for FindBugs
dotRect.y = y - ascent + height/2.0f; // Ditto
g.fill(dotRect);
flushIndex = i + 1;
x = nextX;
break;
case '\f':
// ???
// fall-through for now.
default:
flushLen += 1;
break;
}
}
nextX = x+fm.charsWidth(text, flushIndex,flushLen);
if (flushLen>0 && nextX>=clipStart) {
if (bg!=null) {
paintBackground(x,y, nextX-x,height, g,
ascent, host, bg);
}
g.setColor(fg);
g.drawChars(text, flushIndex, flushLen, (int)x,(int)y);
}
if (host.getUnderlineForToken(this)) {
g.setColor(fg);
int y2 = (int)(y+1);
g.drawLine(origX,y2, (int)nextX,y2);
}
// Don't check if it's whitespace - some TokenMakers may return types
// other than Token.WHITESPACE for spaces (such as Token.IDENTIFIER).
// This also allows us to paint tab lines for MLC's.
if (host.getPaintTabLines() && origX==host.getMargin().left) {// && isWhitespace()) {
paintTabLines(origX, (int)y, (int)nextX, g, e, host);
}
return nextX;
}
}

View File

@ -1,56 +0,0 @@
/*
* 10/28/2004
*
* VisibleWhitespaceTokenFactory.java - Visible whitespace token factory.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea;
/**
* Token factory that generates tokens that display special symbols for the
* whitespace characters space and tab.<p>
*
* NOTE: This class should only be used by {@link TokenMaker}; nobody else
* needs it!
*
* @author Robert Futrell
* @version 0.1
*/
class VisibleWhitespaceTokenFactory extends DefaultTokenFactory {
/**
* Cosnstructor.
*/
public VisibleWhitespaceTokenFactory() {
this(DEFAULT_START_SIZE, DEFAULT_INCREMENT);
}
/**
* Constructor.
*
* @param size The initial number of tokens in this factory.
* @param increment How many tokens to increment by when the stack gets
* empty.
*/
public VisibleWhitespaceTokenFactory(int size, int increment) {
super(size, increment);
}
/**
* Creates a token for use internally by this token factory. This method
* should NOT be called externally; only by this class and possibly
* subclasses.
*
* @return A token to add to this token factory's internal stack.
*/
protected Token createInternalUseOnlyToken() {
return new VisibleWhitespaceToken();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +0,0 @@
package org.fife.ui.rsyntaxtextarea;
//import java.awt.Graphics;
//import java.awt.Rectangle;
//import java.awt.Shape;
//import javax.swing.text.CompositeView;
import javax.swing.text.Element;
//import javax.swing.text.View;
/**
* Replacement for the old <code>WrappedSyntaxView</code> class, designed to
* be faster with large wrapped documents. Heavily based off of
* <code>BoxView</code>, but streamlined to only care about the y-axis, and
* takes code folding into account.<p>
*
* This class is not currently used.
*
* @author Robert Futrell
* @version 1.0
*/
public class WrappedSyntaxView2 {//extends CompositeView {
// private Rectangle tempRect;
// private int[] cachedOffsets;
// private int[] cachedSpans;
// private boolean sizeRequirementsValid;
public WrappedSyntaxView2(Element root) {
//super(root);
// tempRect = new Rectangle();
// cachedOffsets = new int[0];
// cachedSpans = new int[0];
// sizeRequirementsValid = false;
}
// protected void childAllocation(int index, Rectangle alloc) {
// alloc.y += getOffset(index);
// alloc.height = getHeight(index);
// }
//
//
// private int getHeight(int childIndex) {
// return cachedSpans[childIndex];
// }
//
//
// private int getOffset(int childIndex) {
// return cachedOffsets[childIndex];
// }
//
//
// protected View getViewAtPoint(int x, int y, Rectangle alloc) {
// // TODO Auto-generated method stub
// return null;
// }
//
//
// /**
// * @param alloc The allocated region; this is the area inside of the insets
// * @return Whether the point lies after the region.
// */
// protected boolean isAfter(int x, int y, Rectangle alloc) {
// return y > (alloc.y + alloc.height);
// }
//
//
// /**
// * @param alloc The allocated region; this is the area inside of the insets
// * @return Whether the point lies before the region.
// */
// protected boolean isBefore(int x, int y, Rectangle alloc) {
// return y < alloc.y;
// }
//
//
// public float getPreferredSpan(int axis) {
// if (axis==X_AXIS) {
// return preferredWidth + getLeftInset() + getRightInset();
// }
// else {
// return preferredHeight + getTopInset() + getBottomInset();
// }
// }
//
//
// public void paint(Graphics g, Shape allocation) {
//
// Rectangle alloc = (allocation instanceof Rectangle) ?
// (Rectangle)allocation : allocation.getBounds();
// int n = getViewCount();
//
// int x = alloc.x + getLeftInset();
// int y = alloc.y + getTopInset();
// Rectangle clip = g.getClipBounds();
// int preferredWidth = (int)getPreferredSpan(X_AXIS);
//
// for (int i = 0; i < n; i++) {
// tempRect.x = x;
// tempRect.y = y + getOffset(i);
// tempRect.width = preferredWidth;
// tempRect.height = getHeight(i);
// if (tempRect.intersects(clip)) {
// paintChild(g, tempRect, i);
// }
// }
//
// }
//
//
// /**
// * Called when a child view's preferred span changes. This invalidates
// * our layout cache and calls the super implementation.
// */
// public void preferenceChanged(View child, boolean widthPreferenceChanged,
// boolean heightPreferenceChanged) {
//
// if (heightPreferenceChanged) {
// sizeRequirementsValid = false;
//// majorAllocValid = false;
// }
//// if (width) {
//// minorReqValid = false;
//// minorAllocValid = false;
//// }
//
// super.preferenceChanged(child, widthPreferenceChanged, heightPreferenceChanged);
//
// }
//
// public void replace(int index, int length, View[] elems) {
//
// super.replace(index, length, elems);
//
// // Invalidate cache
// int insertCount = elems==null ? 0 : elems.length;
// cachedOffsets = updateLayoutArray(cachedOffsets, index, insertCount);
// majorReqValid = false;
// majorAllocValid = false;
//
// }
//
//
// private int[] updateLayoutArray(int[] oldArray, int offset, int nInserted) {
// int n = getViewCount(); // Called after super.replace() so this is accurate
// int[] newArray = new int[n];
// System.arraycopy(oldArray, 0, newArray, 0, offset);
// System.arraycopy(oldArray, offset,
// newArray, offset + nInserted, n - nInserted - offset);
// return newArray;
// }
//
}

View File

@ -1,344 +0,0 @@
/*
* 07/29/2009
*
* FocusableTip.java - A focusable tool tip, like those in Eclipse.
*
* This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rsyntaxtextarea.focusabletip;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ResourceBundle;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.MouseInputAdapter;
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
/**
* A focusable tool tip, similar to those found in Eclipse. The user
* can click in the tip and it becomes a "real," resizable window.
*
* @author Robert Futrell
* @version 1.0
*/
public class FocusableTip {
private JTextArea textArea;
private TipWindow tipWindow;
private URL imageBase;
private TextAreaListener textAreaListener;
private HyperlinkListener hyperlinkListener;
private String lastText;
/**
* The screen bounds in which the mouse has to stay for the currently
* displayed tip to stay visible.
*/
private Rectangle tipVisibleBounds;
/**
* Margin from mouse cursor at which to draw focusable tip.
*/
private static final int X_MARGIN = 18;
/**
* Margin from mouse cursor at which to draw focusable tip.
*/
private static final int Y_MARGIN = 12;
private static final String MSG =
"org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip";
private static final ResourceBundle msg = ResourceBundle.getBundle(MSG);
public FocusableTip(JTextArea textArea, HyperlinkListener listener) {
setTextArea(textArea);
this.hyperlinkListener = listener;
textAreaListener = new TextAreaListener();
tipVisibleBounds = new Rectangle();
}
/**
* Compute the bounds in which the user can move the mouse without the
* tip window disappearing.
*/
private void computeTipVisibleBounds() {
// Compute area that the mouse can move in without hiding the
// tip window. Note that Java 1.4 can only detect mouse events
// in Java windows, not globally.
Rectangle r = tipWindow.getBounds();
Point p = r.getLocation();
SwingUtilities.convertPointFromScreen(p, textArea);
r.setLocation(p);
tipVisibleBounds.setBounds(r.x,r.y-15, r.width,r.height+15*2);
}
private void createAndShowTipWindow(final MouseEvent e, final String text) {
Window owner = SwingUtilities.getWindowAncestor(textArea);
tipWindow = new TipWindow(owner, this, text);
tipWindow.setHyperlinkListener(hyperlinkListener);
// Give apps a chance to decorate us with drop shadows, etc.
PopupWindowDecorator decorator = PopupWindowDecorator.get();
if (decorator!=null) {
decorator.decorate(tipWindow);
}
// TODO: Position tip window better (handle RTL, edges of screen, etc.).
// Wrap in an invokeLater() to work around a JEditorPane issue where it
// doesn't return its proper preferred size until after it is displayed.
// See http://forums.sun.com/thread.jspa?forumID=57&threadID=574810
// for a discussion.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// If a new FocusableTip is requested while another one is
// *focused* and visible, the focused tip (i.e. "tipWindow")
// will be disposed of. If this Runnable is run after the
// dispose(), tipWindow will be null. All of this is done on
// the EDT so no synchronization should be necessary.
if (tipWindow==null) {
return;
}
tipWindow.fixSize();
ComponentOrientation o = textArea.getComponentOrientation();
Point p = e.getPoint();
SwingUtilities.convertPointToScreen(p, textArea);
// Ensure tool tip is in the window bounds.
// Multi-monitor support - make sure the completion window (and
// description window, if applicable) both fit in the same
// window in a multi-monitor environment. To do this, we decide
// which monitor the rectangle "p" is in, and use that one.
Rectangle sb = TipUtil.getScreenBoundsForPoint(p.x, p.y);
//Dimension ss = tipWindow.getToolkit().getScreenSize();
// Try putting our stuff "below" the mouse first.
int y = p.y + Y_MARGIN;
if (y+tipWindow.getHeight()>=sb.y+sb.height) {
y = p.y - Y_MARGIN - tipWindow.getHeight();
}
// Get x-coordinate of completions. Try to align left edge
// with the mouse first (with a slight margin).
int x = p.x - X_MARGIN; // ltr
if (!o.isLeftToRight()) {
x = p.x - tipWindow.getWidth() + X_MARGIN;
}
if (x<sb.x) {
x = sb.x;
}
else if (x+tipWindow.getWidth()>sb.x+sb.width) { // completions don't fit
x = sb.x + sb.width - tipWindow.getWidth();
}
tipWindow.setLocation(x, y);
tipWindow.setVisible(true);
computeTipVisibleBounds(); // Do after tip is visible
textAreaListener.install(textArea);
lastText = text;
}
});
}
/**
* Returns the base URL to use when loading images in this focusable tip.
*
* @return The base URL to use.
* @see #setImageBase(URL)
*/
public URL getImageBase() {
return imageBase;
}
/**
* Returns localized text for the given key.
*
* @param key The key into the resource bundle.
* @return The localized text.
*/
static String getString(String key) {
return msg.getString(key);
}
/**
* Disposes of the focusable tip currently displayed, if any.
*/
public void possiblyDisposeOfTipWindow() {
if (tipWindow != null) {
tipWindow.dispose();
tipWindow = null;
textAreaListener.uninstall();
tipVisibleBounds.setBounds(-1, -1, 0, 0);
lastText = null;
textArea.requestFocus();
}
}
void removeListeners() {
//System.out.println("DEBUG: Removing text area listeners");
textAreaListener.uninstall();
}
/**
* Sets the base URL to use when loading images in this focusable tip.
*
* @param url The base URL to use.
* @see #getImageBase()
*/
public void setImageBase(URL url) {
imageBase = url;
}
private void setTextArea(JTextArea textArea) {
this.textArea = textArea;
// Is okay to do multiple times.
ToolTipManager.sharedInstance().registerComponent(textArea);
}
public void toolTipRequested(MouseEvent e, String text) {
if (text==null || text.length()==0) {
possiblyDisposeOfTipWindow();
lastText = text;
return;
}
if (lastText==null || text.length()!=lastText.length()
|| !text.equals(lastText)) {
possiblyDisposeOfTipWindow();
createAndShowTipWindow(e, text);
}
}
private class TextAreaListener extends MouseInputAdapter implements
CaretListener, ComponentListener, FocusListener, KeyListener {
public void caretUpdate(CaretEvent e) {
Object source = e.getSource();
if (source == textArea) {
possiblyDisposeOfTipWindow();
}
}
public void componentHidden(ComponentEvent e) {
handleComponentEvent(e);
}
public void componentMoved(ComponentEvent e) {
handleComponentEvent(e);
}
public void componentResized(ComponentEvent e) {
handleComponentEvent(e);
}
public void componentShown(ComponentEvent e) {
handleComponentEvent(e);
}
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
// Only dispose of tip if it wasn't the TipWindow that was clicked
// "c" can be null, at least on OS X, so we must check that before
// calling SwingUtilities.getWindowAncestor() to guard against an
// NPE.
Component c = e.getOppositeComponent();
boolean tipClicked = (c instanceof TipWindow) ||
(c!=null &&
SwingUtilities.getWindowAncestor(c) instanceof TipWindow);
if (!tipClicked) {
possiblyDisposeOfTipWindow();
}
}
private void handleComponentEvent(ComponentEvent e) {
possiblyDisposeOfTipWindow();
}
public void install(JTextArea textArea) {
textArea.addCaretListener(this);
textArea.addComponentListener(this);
textArea.addFocusListener(this);
textArea.addKeyListener(this);
textArea.addMouseListener(this);
textArea.addMouseMotionListener(this);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_ESCAPE) {
possiblyDisposeOfTipWindow();
}
else if (e.getKeyCode()==KeyEvent.VK_F2) {
if (tipWindow!=null && !tipWindow.getFocusableWindowState()) {
tipWindow.actionPerformed(null);
e.consume(); // Don't do bookmarking stuff
}
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void mouseExited(MouseEvent e) {
// possiblyDisposeOfTipWindow();
}
public void mouseMoved(MouseEvent e) {
if (tipVisibleBounds==null ||
!tipVisibleBounds.contains(e.getPoint())) {
possiblyDisposeOfTipWindow();
}
}
public void uninstall() {
textArea.removeCaretListener(this);
textArea.removeComponentListener(this);
textArea.removeFocusListener(this);
textArea.removeKeyListener(this);
textArea.removeMouseListener(this);
textArea.removeMouseMotionListener(this);
}
}
}

View File

@ -1 +0,0 @@
FocusHotkey=Press 'F2' for focus

Some files were not shown because too many files have changed in this diff Show More