Updated to support Java 11, but only Java 8 features

This commit is contained in:
SuspiciousActivity committed 2018-09-26 17:19:03 +02:00
1 parent 58c8e90c81
commit 89f9753d8b
19 files changed
+984 -1252

No files matched your search

+19 -22
View File
@@ -79,8 +79,8 @@ public class Assembler {
clazz.innerClasses = new ArrayList<>(); clazz.innerClasses = new ArrayList<>();
} else { } else {
String split[] = s.split(" "); String split[] = s.split(" ");
clazz.innerClasses.add(new InnerClassNode(UnicodeUtils.unescape(split[1]), clazz.innerClasses
split[2].equals("null") ? null : UnicodeUtils.unescape(split[2]), .add(new InnerClassNode(UnicodeUtils.unescape(split[1]), split[2].equals("null") ? null : UnicodeUtils.unescape(split[2]),
split[3].equals("null") ? null : UnicodeUtils.unescape(split[3]), Integer.parseInt(split[4].substring(2), 16))); split[3].equals("null") ? null : UnicodeUtils.unescape(split[3]), Integer.parseInt(split[4].substring(2), 16)));
} }
} }
@@ -297,9 +297,8 @@ public class Assembler {
_end = new LabelNode(entry.getKey()); _end = new LabelNode(entry.getKey());
} }
} }
node.localVariables node.localVariables.add(new LocalVariableNode(sp[0], UnicodeUtils.unescape(sp[1].substring(1, sp[1].length() - 2)),
.add(new LocalVariableNode(sp[0], UnicodeUtils.unescape(sp[1].substring(1, sp[1].length() - 2)), signat, signat, _start, _end, Integer.parseInt(sp[2].substring(0, sp[2].length() - 2))));
_start, _end, Integer.parseInt(sp[2].substring(0, sp[2].length() - 2))));
} }
for (String st : tryCatchBlocksToParse) { for (String st : tryCatchBlocksToParse) {
String[] sp = st.split(" "); String[] sp = st.split(" ");
@@ -320,8 +319,8 @@ public class Assembler {
_handler = new LabelNode(entry.getKey()); _handler = new LabelNode(entry.getKey());
} }
} }
node.tryCatchBlocks.add(new TryCatchBlockNode(_start, _end, _handler, node.tryCatchBlocks
sp[0].equals("null") ? null : UnicodeUtils.unescape(sp[0]))); .add(new TryCatchBlockNode(_start, _end, _handler, sp[0].equals("null") ? null : UnicodeUtils.unescape(sp[0])));
} }
clazz.methods.add(node); clazz.methods.add(node);
// signature = null; // signature = null;
@@ -643,8 +642,8 @@ public class Assembler {
} }
} }
} }
return new FrameNode(Integer.parseInt(str1.split(" ")[0]), local != null ? local.length : 0, local, return new FrameNode(Integer.parseInt(str1.split(" ")[0]), local != null ? local.length : 0, local, stack != null ? stack.length : 0,
stack != null ? stack.length : 0, stack); stack);
} else { } else {
String[] split = s.split(" "); String[] split = s.split(" ");
String command = split[0]; String command = split[0];
@@ -694,12 +693,12 @@ public class Assembler {
if (str.startsWith("Type: ")) { if (str.startsWith("Type: ")) {
str = str.substring(8, str.length() - 2); str = str.substring(8, str.length() - 2);
String[] split2 = str.split("\n\t"); String[] split2 = str.split("\n\t");
Constructor<Type> constr = Type.class.getDeclaredConstructor(int.class, char[].class, int.class, int.class); Constructor<Type> constr = Type.class.getDeclaredConstructor(int.class, String.class, int.class, int.class);
constr.setAccessible(true); constr.setAccessible(true);
String type = split2[0].substring(7); String type = split2[0].substring(7);
val = constr.newInstance(new Object[] { ClassUtil.getIDFromClassNameForType(type), val = constr.newInstance(
split2[3].substring(6, split2[3].length() - 1).toCharArray(), Integer.parseInt(split2[1].substring(5)), new Object[] { ClassUtil.getIDFromClassNameForType(type), split2[3].substring(6, split2[3].length() - 1),
Integer.parseInt(split2[2].substring(5)) }); Integer.parseInt(split2[1].substring(7)), Integer.parseInt(split2[2].substring(5)) });
} else if (str.startsWith("\"") && str.endsWith("\"")) { } else if (str.startsWith("\"") && str.endsWith("\"")) {
val = UnicodeUtils.unescape(str.substring(1, str.length() - 1)); val = UnicodeUtils.unescape(str.substring(1, str.length() - 1));
} else if (str.endsWith("l")) { } else if (str.endsWith("l")) {
@@ -1226,8 +1225,7 @@ public class Assembler {
arr[counter] = ln; arr[counter] = ln;
counter++; counter++;
} }
return new TableSwitchInsnNode(Integer.parseInt(split2[0].substring(5)), Integer.parseInt(split2[1].substring(5)), dflt, return new TableSwitchInsnNode(Integer.parseInt(split2[0].substring(5)), Integer.parseInt(split2[1].substring(5)), dflt, arr);
arr);
} }
case "lookupswitch": { case "lookupswitch": {
String str = s.substring(15, s.length() - 2).replace("\t", ""); String str = s.substring(15, s.length() - 2).replace("\t", "");
@@ -1375,19 +1373,18 @@ public class Assembler {
if (st.equals("]")) { if (st.equals("]")) {
if (stage == 1) { if (stage == 1) {
try { try {
Constructor<Type> constr = Type.class.getDeclaredConstructor(int.class, char[].class, int.class, Constructor<Type> constr = Type.class.getDeclaredConstructor(int.class, String.class, int.class, int.class);
int.class);
constr.setAccessible(true); constr.setAccessible(true);
args.add(constr.newInstance(new Object[] { Integer.parseInt(vals.get(0).substring(6)), args.add(constr.newInstance(new Object[] { Integer.parseInt(vals.get(0).substring(6)),
UnicodeUtils.unescape(vals.get(3).substring(6, vals.get(3).length() - 1)).toCharArray(), UnicodeUtils.unescape(vals.get(3).substring(6, vals.get(3).length() - 1)),
Integer.parseInt(vals.get(1).substring(5)), Integer.parseInt(vals.get(2).substring(5)) })); Integer.parseInt(vals.get(1).substring(7)), Integer.parseInt(vals.get(2).substring(5)) }));
} catch (Exception e) { } catch (Exception e) {
throw e; throw e;
} }
} else if (stage == 2) { } else if (stage == 2) {
args.add(new Handle(Integer.parseInt(vals.get(4).substring(5)), args.add(new Handle(Integer.parseInt(vals.get(4).substring(5)), UnicodeUtils.unescape(vals.get(1).substring(7)),
UnicodeUtils.unescape(vals.get(1).substring(7)), UnicodeUtils.unescape(vals.get(0).substring(6)), UnicodeUtils.unescape(vals.get(0).substring(6)), UnicodeUtils.unescape(vals.get(2).substring(6)),
UnicodeUtils.unescape(vals.get(2).substring(6)), Boolean.parseBoolean(vals.get(3).substring(13)))); Boolean.parseBoolean(vals.get(3).substring(13))));
vals.clear(); vals.clear();
} }
stage = 0; stage = 0;
+40 -42
View File
@@ -139,8 +139,10 @@ public class Disassembler {
} }
s += "// #Class v:" + classNode.version + "\n"; s += "// #Class v:" + classNode.version + "\n";
s += "// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n"; s += "// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n";
s += "// #OuterMethod: " + (classNode.outerMethod == null ? "null" : (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " s += "// #OuterMethod: "
+ UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc))) + "\n"; + (classNode.outerMethod == null ? "null"
: (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " " + UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc)))
+ "\n";
s += "// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n"; s += "// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n";
s += "// #InnerClasses:\n"; s += "// #InnerClasses:\n";
if (classNode.innerClasses != null) { if (classNode.innerClasses != null) {
@@ -163,8 +165,7 @@ public class Disassembler {
if (!interfaceStr.isEmpty()) if (!interfaceStr.isEmpty())
s += "implements " + interfaceStr + " "; s += "implements " + interfaceStr + " ";
} }
s += "{\n// #SourceFile: " + (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile)) s += "{\n// #SourceFile: " + (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile)) + "\n\n// #Fields\n";
+ "\n\n// #Fields\n";
for (FieldNode fn : classNode.fields) { for (FieldNode fn : classNode.fields) {
if (fn.signature != null) if (fn.signature != null)
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n"; s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n";
@@ -227,8 +228,8 @@ public class Disassembler {
s += "\n"; s += "\n";
} }
} }
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") + UnicodeUtils.escapeWithSpaces(fn.desc) s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient") + UnicodeUtils.escapeWithSpaces(fn.desc) + " "
+ " " + UnicodeUtils.escapeWithSpaces(fn.name); + UnicodeUtils.escapeWithSpaces(fn.name);
if (fn.value != null) { if (fn.value != null) {
s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true); s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true);
} }
@@ -323,8 +324,8 @@ public class Disassembler {
s += dis[0]; s += dis[0];
s += "\t}\n\n"; s += "\t}\n\n";
} catch (Exception e) { } catch (Exception e) {
s += "\t\t// Method couldn't be disassembled:\n\t\t// " + e.getClass().getName() + ": " + e.getMessage() + "\n" + Arrays s += "\t\t// Method couldn't be disassembled:\n\t\t// " + e.getClass().getName() + ": " + e.getMessage() + "\n"
.toString(e.getStackTrace()).replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "") + Arrays.toString(e.getStackTrace()).replace(", ", "\n\t\t// \tat ").replace("[", "\t\t// \tat ").replace("]", "")
+ "\n\t}\n\n"; + "\n\t}\n\n";
} }
} }
@@ -427,38 +428,36 @@ public class Disassembler {
} }
case "InvokeDynamicInsnNode": { case "InvokeDynamicInsnNode": {
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n; InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: " String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: " + UnicodeUtils.escapeWithSpaces(node.name)
+ UnicodeUtils.escapeWithSpaces(node.name) + "\n\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(node.desc) + "\n\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: "
+ "\n\t\t\tHandle: [\n\t\t\t\tname: " + UnicodeUtils.escapeWithSpaces(node.bsm.getName()) + "\n\t\t\t\towner: " + UnicodeUtils.escapeWithSpaces(node.bsm.getName()) + "\n\t\t\t\towner: " + UnicodeUtils.escapeWithSpaces(node.bsm.getOwner())
+ UnicodeUtils.escapeWithSpaces(node.bsm.getOwner()) + "\n\t\t\t\tdesc: " + "\n\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(node.bsm.getDesc()) + "\n\t\t\t\tisInterface: " + node.bsm.isInterface()
+ UnicodeUtils.escapeWithSpaces(node.bsm.getDesc()) + "\n\t\t\t\tisInterface: " + node.bsm.isInterface()
+ "\n\t\t\t\ttag: " + node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n"; + "\n\t\t\t\ttag: " + node.bsm.getTag() + "\n\t\t\t]\n\t\t\targs: [\n";
for (Object l : node.bsmArgs) { for (Object l : node.bsmArgs) {
if (l.getClass().getName().equals("org.objectweb.asm.Type")) { if (l.getClass().getName().equals("org.objectweb.asm.Type")) {
Type type = (Type) l; Type type = (Type) l;
int off = 0; int valueBegin = 0;
int len = 0; int valueEnd = 0;
char[] buf = null; String buf = null;
try { try {
Field f_off = Type.class.getDeclaredField("off"); Field f_off = Type.class.getDeclaredField("valueBegin");
f_off.setAccessible(true); f_off.setAccessible(true);
off = f_off.getInt(type); valueBegin = f_off.getInt(type);
Field f_len = Type.class.getDeclaredField("len"); Field f_len = Type.class.getDeclaredField("valueEnd");
f_len.setAccessible(true); f_len.setAccessible(true);
len = f_len.getInt(type); valueEnd = f_len.getInt(type);
Field f_buf = Type.class.getDeclaredField("buf"); Field f_buf = Type.class.getDeclaredField("valueBuffer");
f_buf.setAccessible(true); f_buf.setAccessible(true);
buf = (char[]) f_buf.get(type); buf = (String) f_buf.get(type);
} catch (Exception e) {} } catch (Exception e) {}
s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\t\t\toff: " + off s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\t\t\tstart: " + valueBegin
+ "\n\t\t\t\t\tlen: " + len + "\n\t\t\t\t\tbuf: " + ClassUtil.getDecompiledValue(new String(buf), ""); + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, "");
s += "\n\t\t\t\t]\n"; s += "\n\t\t\t\t]\n";
} else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) { } else if (l.getClass().getName().equals("org.objectweb.asm.Handle")) {
Handle h = (Handle) l; Handle h = (Handle) l;
s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: " + UnicodeUtils.escapeWithSpaces(h.getName()) + "\n\t\t\t\t\towner: " s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: " + UnicodeUtils.escapeWithSpaces(h.getName()) + "\n\t\t\t\t\towner: "
+ UnicodeUtils.escapeWithSpaces(h.getOwner()) + "\n\t\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(h.getOwner()) + "\n\t\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(h.getDesc())
+ UnicodeUtils.escapeWithSpaces(h.getDesc()) + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: " + h.getTag();
+ "\n\t\t\t\t\ttag: " + h.getTag();
s += "\n\t\t\t\t]\n"; s += "\n\t\t\t\t]\n";
} else { } else {
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n"; s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n";
@@ -478,8 +477,8 @@ public class Disassembler {
} }
case "MultiANewArrayInsnNode": { case "MultiANewArrayInsnNode": {
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n; MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + " " return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + UnicodeUtils.escapeWithSpaces(node.desc) + " " + node.dims
+ node.dims + "\n"; + "\n";
} }
case "LdcInsnNode": { case "LdcInsnNode": {
LdcInsnNode node = (LdcInsnNode) n; LdcInsnNode node = (LdcInsnNode) n;
@@ -489,28 +488,27 @@ public class Disassembler {
case "Integer": case "Integer":
case "Float": case "Float":
case "Long": { case "Long": {
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + ClassUtil.getDecompiledValue(node.cst, "") return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + ClassUtil.getDecompiledValue(node.cst, "") + "\n";
+ "\n";
} }
case "Type": { case "Type": {
Type type = (Type) node.cst; Type type = (Type) node.cst;
int off = 0; int valueBegin = 0;
int len = 0; int valueEnd = 0;
char[] buf = null; String buf = null;
try { try {
Field f_off = Type.class.getDeclaredField("off"); Field f_off = Type.class.getDeclaredField("valueBegin");
f_off.setAccessible(true); f_off.setAccessible(true);
off = f_off.getInt(type); valueBegin = f_off.getInt(type);
Field f_len = Type.class.getDeclaredField("len"); Field f_len = Type.class.getDeclaredField("valueEnd");
f_len.setAccessible(true); f_len.setAccessible(true);
len = f_len.getInt(type); valueEnd = f_len.getInt(type);
Field f_buf = Type.class.getDeclaredField("buf"); Field f_buf = Type.class.getDeclaredField("valueBuffer");
f_buf.setAccessible(true); f_buf.setAccessible(true);
buf = (char[]) f_buf.get(type); buf = (String) f_buf.get(type);
} catch (Exception e) {} } catch (Exception e) {}
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: " String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: "
+ ClassUtil.getClassNameFromType(type) + "\n\t\t\toff: " + off + "\n\t\t\tlen: " + len + "\n\t\t\tbuf: " + ClassUtil.getClassNameFromType(type) + "\n\t\t\tstart: " + valueBegin + "\n\t\t\tend: " + valueEnd + "\n\t\t\tbuf: "
+ ClassUtil.getDecompiledValue(new String(buf), ""); + ClassUtil.getDecompiledValue(buf, "");
s += "\n\t\t]\n"; s += "\n\t\t]\n";
return s; return s;
} }
+2 -5
View File
@@ -604,11 +604,8 @@ public class Main extends JFrame {
class ArchiveTreeModel extends DefaultTreeModel { class ArchiveTreeModel extends DefaultTreeModel {
public ArchiveTreeModel(JarFile jar) { public ArchiveTreeModel(JarFile jar) {
super(new DefaultMutableTreeNode( super(new DefaultMutableTreeNode(jar.getName().split(File.separator.equals("\\") ? "\\\\"
jar.getName() : File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length - 1]));
.split(File.separator.equals("\\") ? "\\\\"
: File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length
- 1]));
try { try {
ArrayList<String> paths = new ArrayList<>(); ArrayList<String> paths = new ArrayList<>();
classNodes.clear(); classNodes.clear();
+54 -79
View File
@@ -25,8 +25,8 @@ import java.io.Reader;
* <li>UTF-32LE * <li>UTF-32LE
* <li>UTF-32BE * <li>UTF-32BE
* </ul> * </ul>
* If the stream is not found to be any of the above, then a default encoding * If the stream is not found to be any of the above, then a default encoding is
* is used for reading. The user can specify this default encoding, or a system * used for reading. The user can specify this default encoding, or a system
* default will be used. * default will be used.
* <p> * <p>
* *
@@ -40,7 +40,6 @@ import java.io.Reader;
* @author Robert Futrell * @author Robert Futrell
* @version 0.9 * @version 0.9
*/ */
@SuppressWarnings({ "checkstyle:magicnumber" })
public class UnicodeReader extends Reader { public class UnicodeReader extends Reader {
/** /**
@@ -48,9 +47,9 @@ public class UnicodeReader extends Reader {
*/ */
private InputStreamReader internalIn = null; private InputStreamReader internalIn = null;
/** /**
* The encoding being used. We keep our own instead of using the string * The encoding being used. We keep our own instead of using the string returned
* returned by <code>java.io.InputStreamReader</code> since that class * by <code>java.io.InputStreamReader</code> since that class does not return
* does not return user-friendly names. * user-friendly names.
*/ */
private String encoding; private String encoding;
/** /**
@@ -62,17 +61,14 @@ public class UnicodeReader extends Reader {
* This utility constructor is here because you will usually use a * This utility constructor is here because you will usually use a
* <code>UnicodeReader</code> on files. * <code>UnicodeReader</code> on files.
* <p> * <p>
* Creates a reader using the encoding specified by the BOM in the file; * Creates a reader using the encoding specified by the BOM in the file; if
* if there is no recognized BOM, then a system default encoding is used. * there is no recognized BOM, then a system default encoding is used.
* *
* @param file * @param file The file from which you want to read.
* The file from which you want to read. * @throws IOException If an error occurs when checking for/reading the
* @throws IOException
* If an error occurs when checking for/reading the
* BOM. * BOM.
* @throws SecurityException * @throws SecurityException If a security manager exists and its checkRead
* If a security manager exists and its * method denies read access to the file.
* checkRead method denies read access to the file.
*/ */
public UnicodeReader(String file) throws IOException { public UnicodeReader(String file) throws IOException {
this(new File(file)); this(new File(file));
@@ -82,17 +78,14 @@ public class UnicodeReader extends Reader {
* This utility constructor is here because you will usually use a * This utility constructor is here because you will usually use a
* <code>UnicodeReader</code> on files. * <code>UnicodeReader</code> on files.
* <p> * <p>
* Creates a reader using the encoding specified by the BOM in the file; * Creates a reader using the encoding specified by the BOM in the file; if
* if there is no recognized BOM, then a system default encoding is used. * there is no recognized BOM, then a system default encoding is used.
* *
* @param file * @param file The file from which you want to read.
* The file from which you want to read. * @throws IOException If an error occurs when checking for/reading the
* @throws IOException
* If an error occurs when checking for/reading the
* BOM. * BOM.
* @throws SecurityException * @throws SecurityException If a security manager exists and its checkRead
* If a security manager exists and its * method denies read access to the file.
* checkRead method denies read access to the file.
*/ */
public UnicodeReader(File file) throws IOException { public UnicodeReader(File file) throws IOException {
this(new FileInputStream(file)); this(new FileInputStream(file));
@@ -102,54 +95,41 @@ public class UnicodeReader extends Reader {
* This utility constructor is here because you will usually use a * This utility constructor is here because you will usually use a
* <code>UnicodeReader</code> on files. * <code>UnicodeReader</code> on files.
* <p> * <p>
* Creates a reader using the encoding specified by the BOM in the file; * Creates a reader using the encoding specified by the BOM in the file; if
* if there is no recognized BOM, then a specified default encoding is * there is no recognized BOM, then a specified default encoding is used.
* used.
* *
* @param file * @param file The file from which you want to read.
* The file from which you want to read. * @param defaultEncoding The encoding to use if no BOM is found. If this value
* @param defaultEncoding * is <code>null</code>, a system default is used.
* The encoding to use if no BOM is found. If * @throws IOException If an error occurs when checking for/reading the
* this value is <code>null</code>, a system default is used.
* @throws IOException
* If an error occurs when checking for/reading the
* BOM. * BOM.
* @throws SecurityException * @throws SecurityException If a security manager exists and its checkRead
* If a security manager exists and its * method denies read access to the file.
* checkRead method denies read access to the file.
*/ */
public UnicodeReader(File file, String defaultEncoding) throws IOException { public UnicodeReader(File file, String defaultEncoding) throws IOException {
this(new FileInputStream(file), defaultEncoding); this(new FileInputStream(file), defaultEncoding);
} }
/** /**
* Creates a reader using the encoding specified by the BOM in the file; * Creates a reader using the encoding specified by the BOM in the file; if
* if there is no recognized BOM, then a system default encoding is used. * there is no recognized BOM, then a system default encoding is used.
* *
* @param in * @param in The input stream from which to read.
* The input stream from which to read. * @throws IOException If an error occurs when checking for/reading the BOM.
* @throws IOException
* If an error occurs when checking for/reading the
* BOM.
*/ */
public UnicodeReader(InputStream in) throws IOException { public UnicodeReader(InputStream in) throws IOException {
this(in, null); this(in, null);
} }
/** /**
* Creates a reader using the encoding specified by the BOM in the file; * Creates a reader using the encoding specified by the BOM in the file; if
* if there is no recognized BOM, then <code>defaultEncoding</code> is * there is no recognized BOM, then <code>defaultEncoding</code> is used.
* used.
* *
* @param in * @param in The input stream from which to read.
* The input stream from which to read. * @param defaultEncoding The encoding to use if no recognized BOM is found. If
* @param defaultEncoding * this value is <code>null</code>, a system default is
* The encoding to use if no recognized BOM is * used.
* found. If this value is <code>null</code>, a system default * @throws IOException If an error occurs when checking for/reading the BOM.
* is used.
* @throws IOException
* If an error occurs when checking for/reading the
* BOM.
*/ */
public UnicodeReader(InputStream in, String defaultEncoding) throws IOException { public UnicodeReader(InputStream in, String defaultEncoding) throws IOException {
init(in, defaultEncoding); init(in, defaultEncoding);
@@ -164,10 +144,10 @@ public class UnicodeReader extends Reader {
} }
/** /**
* Returns the encoding being used to read this input stream (i.e., the * Returns the encoding being used to read this input stream (i.e., the encoding
* encoding of the file). If a BOM was recognized, then the specific * of the file). If a BOM was recognized, then the specific Unicode type is
* Unicode type is returned; otherwise, either the default encoding passed * returned; otherwise, either the default encoding passed into the constructor
* into the constructor or the system default is returned. * or the system default is returned.
* *
* @return The encoding of the stream. * @return The encoding of the stream.
*/ */
@@ -176,15 +156,13 @@ public class UnicodeReader extends Reader {
} }
/** /**
* Read-ahead four bytes and check for BOM marks. Extra bytes are * Read-ahead four bytes and check for BOM marks. Extra bytes are unread back to
* unread back to the stream, only BOM bytes are skipped. * the stream, only BOM bytes are skipped.
* *
* @param defaultEncoding * @param defaultEncoding The encoding to use if no BOM was recognized. If this
* The encoding to use if no BOM was recognized. If * value is <code>null</code>, then a system default is
* this value is <code>null</code>, then a system default is
* used. * used.
* @throws IOException * @throws IOException If an error occurs when trying to read a BOM.
* If an error occurs when trying to read a BOM.
*/ */
protected void init(InputStream in, String defaultEncoding) throws IOException { protected void init(InputStream in, String defaultEncoding) throws IOException {
PushbackInputStream tempIn = new PushbackInputStream(in, BOM_SIZE); PushbackInputStream tempIn = new PushbackInputStream(in, BOM_SIZE);
@@ -196,7 +174,8 @@ public class UnicodeReader extends Reader {
unread = n - 4; unread = n - 4;
} else if (n == BOM_SIZE && // Last 2 bytes are 0; could be an empty } else if (n == BOM_SIZE && // Last 2 bytes are 0; could be an empty
// UTF-16 // UTF-16
(bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { (bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00)
&& (bom[3] == (byte) 0x00)) {
encoding = "UTF-32LE"; encoding = "UTF-32LE";
unread = n - 4; unread = n - 4;
} else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
@@ -228,19 +207,15 @@ public class UnicodeReader extends Reader {
} }
/** /**
* Read characters into a portion of an array. This method will block until * Read characters into a portion of an array. This method will block until some
* some input is available, an I/O error occurs, or the end of the stream * input is available, an I/O error occurs, or the end of the stream is reached.
* is reached.
* *
* @param cbuf * @param cbuf The buffer into which to read.
* The buffer into which to read. * @param off The offset at which to start storing characters.
* @param off * @param len The maximum number of characters to read.
* 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 * @return The number of characters read, or <code>-1</code> if the end of the
* of the stream has been reached. * stream has been reached.
*/ */
@Override @Override
public int read(char[] cbuf, int off, int len) throws IOException { public int read(char[] cbuf, int off, int len) throws IOException {
@@ -15,9 +15,9 @@ import java.util.List;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
/** /**
* A base class for completion providers. {@link Completion}s are kept in * A base class for completion providers. {@link Completion}s are kept in a
* a sorted list. To get the list of completions that match a given input, * sorted list. To get the list of completions that match a given input, a
* a binary search is done to find the first matching completion, then all * binary search is done to find the first matching completion, then all
* succeeding completions that also match are also returned. * succeeding completions that also match are also returned.
* *
* @author Robert Futrell * @author Robert Futrell
@@ -26,8 +26,8 @@ import javax.swing.text.JTextComponent;
public abstract class AbstractCompletionProvider extends CompletionProviderBase { public abstract class AbstractCompletionProvider extends CompletionProviderBase {
/** /**
* The completions this provider is aware of. Subclasses should ensure * The completions this provider is aware of. Subclasses should ensure that this
* that this list is sorted alphabetically (case-insensitively). * list is sorted alphabetically (case-insensitively).
*/ */
protected List<Completion> completions; protected List<Completion> completions;
/** /**
@@ -46,14 +46,12 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
/** /**
* Adds a single completion to this provider. If you are adding multiple * Adds a single completion to this provider. If you are adding multiple
* completions to this provider, for efficiency reasons please consider * completions to this provider, for efficiency reasons please consider using
* using {@link #addCompletions(List)} instead. * {@link #addCompletions(List)} instead.
* *
* @param c * @param c The completion to add.
* The completion to add. * @throws IllegalArgumentException If the completion's provider isn't this
* @throws IllegalArgumentException * <tt>CompletionProvider</tt>.
* If the completion's provider isn't
* this <tt>CompletionProvider</tt>.
* @see #addCompletions(List) * @see #addCompletions(List)
* @see #removeCompletion(Completion) * @see #removeCompletion(Completion)
* @see #clear() * @see #clear()
@@ -66,12 +64,9 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
/** /**
* Adds {@link Completion}s to this provider. * Adds {@link Completion}s to this provider.
* *
* @param completions * @param completions The completions to add. This cannot be <code>null</code>.
* The completions to add. This cannot be * @throws IllegalArgumentException If a completion's provider isn't this
* <code>null</code>. * <tt>CompletionProvider</tt>.
* @throws IllegalArgumentException
* If a completion's provider isn't
* this <tt>CompletionProvider</tt>.
* @see #addCompletion(Completion) * @see #addCompletion(Completion)
* @see #removeCompletion(Completion) * @see #removeCompletion(Completion)
* @see #clear() * @see #clear()
@@ -87,8 +82,7 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
/** /**
* Adds simple completions for a list of words. * Adds simple completions for a list of words.
* *
* @param words * @param words The words.
* The words.
* @see BasicCompletion * @see BasicCompletion
*/ */
protected void addWordCompletions(String[] words) { protected void addWordCompletions(String[] words) {
@@ -107,8 +101,8 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
} }
/** /**
* Removes all completions from this provider. This does not affect * Removes all completions from this provider. This does not affect the parent
* the parent <tt>CompletionProvider</tt>, if there is one. * <tt>CompletionProvider</tt>, if there is one.
* *
* @see #addCompletion(Completion) * @see #addCompletion(Completion)
* @see #addCompletions(List) * @see #addCompletions(List)
@@ -119,15 +113,13 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
} }
/** /**
* Returns a list of <tt>Completion</tt>s in this provider with the * Returns a list of <tt>Completion</tt>s in this provider with the specified
* specified input text. * input text.
* *
* @param inputText * @param inputText The input text to search for.
* The input text to search for. * @return A list of {@link Completion}s, or <code>null</code> if there are no
* @return A list of {@link Completion}s, or <code>null</code> if there * matching <tt>Completion</tt>s.
* are no matching <tt>Completion</tt>s.
*/ */
@SuppressWarnings("unchecked")
public List<Completion> getCompletionByInputText(String inputText) { public List<Completion> getCompletionByInputText(String inputText) {
// Find any entry that matches this input text (there may be > 1). // Find any entry that matches this input text (there may be > 1).
int end = Collections.binarySearch(completions, inputText, comparator); int end = Collections.binarySearch(completions, inputText, comparator);
@@ -140,7 +132,8 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
start--; start--;
} }
int count = completions.size(); int count = completions.size();
while (++end < count && comparator.compare(completions.get(end), inputText) == 0); while (++end < count && comparator.compare(completions.get(end), inputText) == 0)
;
return completions.subList(start, end); // (inclusive, exclusive) return completions.subList(start, end); // (inclusive, exclusive)
} }
@@ -148,7 +141,6 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
@SuppressWarnings("unchecked")
protected List<Completion> getCompletionsImpl(JTextComponent comp) { protected List<Completion> getCompletionsImpl(JTextComponent comp) {
List<Completion> retVal = new ArrayList<Completion>(); List<Completion> retVal = new ArrayList<Completion>();
String text = getAlreadyEnteredText(comp); String text = getAlreadyEnteredText(comp);
@@ -190,11 +182,10 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
} }
/** /**
* Removes the specified completion from this provider. This method * Removes the specified completion from this provider. This method will not
* will not remove completions from the parent provider, if there is one. * remove completions from the parent provider, if there is one.
* *
* @param c * @param c The completion to remove.
* The completion to remove.
* @return <code>true</code> if this provider contained the specified * @return <code>true</code> if this provider contained the specified
* completion. * completion.
* @see #clear() * @see #clear()
@@ -212,10 +203,9 @@ public abstract class AbstractCompletionProvider extends CompletionProviderBase
} }
/** /**
* A comparator that compares the input text of a {@link Completion} * A comparator that compares the input text of a {@link Completion} against a
* against a String lexicographically, ignoring case. * String lexicographically, ignoring case.
*/ */
@SuppressWarnings("rawtypes")
public static class CaseInsensitiveComparator implements Comparator, Serializable { public static class CaseInsensitiveComparator implements Comparator, Serializable {
@Override @Override
@@ -32,19 +32,18 @@ import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate;
* Manages "code templates." * Manages "code templates."
* <p> * <p>
* *
* All methods in this class are synchronized for thread safety, but as a * All methods in this class are synchronized for thread safety, but as a best
* best practice, you should probably only modify the templates known to a * practice, you should probably only modify the templates known to a
* <code>CodeTemplateManager</code> on the EDT. Modifying a * <code>CodeTemplateManager</code> on the EDT. Modifying a
* <code>CodeTemplate</code> retrieved from a <code>CodeTemplateManager</code> * <code>CodeTemplate</code> retrieved from a <code>CodeTemplateManager</code>
* while <em>not</em> on the EDT could cause problems. * while <em>not</em> on the EDT could cause problems.
* <p> * <p>
* *
* For more flexible boilerplate code insertion, consider using the * For more flexible boilerplate code insertion, consider using the <a href=
* <a href=
* "http://javadoc.fifesoft.com/autocomplete/org/fife/ui/autocomplete/TemplateCompletion.html"> * "http://javadoc.fifesoft.com/autocomplete/org/fife/ui/autocomplete/TemplateCompletion.html">
* TemplateCompletion class</a> in the * TemplateCompletion class</a> in the
* <a href="https://github.com/bobbylight/AutoComplete">AutoComplete * <a href="https://github.com/bobbylight/AutoComplete">AutoComplete add-on
* add-on library</a>. * library</a>.
* *
* @author Robert Futrell * @author Robert Futrell
* @version 1.0 * @version 1.0
@@ -69,10 +68,8 @@ public class CodeTemplateManager {
/** /**
* Registers the specified template with this template manager. * Registers the specified template with this template manager.
* *
* @param template * @param template The template to register.
* The template to register. * @throws IllegalArgumentException If <code>template</code> is
* @throws IllegalArgumentException
* If <code>template</code> is
* <code>null</code>. * <code>null</code>.
* @see #removeTemplate(CodeTemplate) * @see #removeTemplate(CodeTemplate)
* @see #removeTemplate(String) * @see #removeTemplate(String)
@@ -86,11 +83,10 @@ public class CodeTemplateManager {
} }
/** /**
* Returns the template that should be inserted at the current caret * Returns the template that should be inserted at the current caret position,
* position, assuming the trigger character was pressed. * assuming the trigger character was pressed.
* *
* @param textArea * @param textArea The text area that's getting text inserted into it.
* The text area that's getting text inserted into it.
* @return A template that should be inserted, if appropriate, or * @return A template that should be inserted, if appropriate, or
* <code>null</code> if no template should be inserted. * <code>null</code> if no template should be inserted.
*/ */
@@ -100,7 +96,6 @@ public class CodeTemplateManager {
try { try {
Document doc = textArea.getDocument(); Document doc = textArea.getDocument();
doc.getText(caretPos - charsToGet, charsToGet, s); doc.getText(caretPos - charsToGet, charsToGet, s);
@SuppressWarnings("unchecked")
int index = Collections.binarySearch(templates, s, comparator); int index = Collections.binarySearch(templates, s, comparator);
return index >= 0 ? (CodeTemplate) templates.get(index) : null; return index >= 0 ? (CodeTemplate) templates.get(index) : null;
} catch (BadLocationException ble) { } catch (BadLocationException ble) {
@@ -132,8 +127,7 @@ public class CodeTemplateManager {
* Returns whether the specified character is a valid character for a * Returns whether the specified character is a valid character for a
* <code>CodeTemplate</code> id. * <code>CodeTemplate</code> id.
* *
* @param ch * @param ch The character to check.
* The character to check.
* @return Whether the character is a valid template character. * @return Whether the character is a valid template character.
*/ */
public static final boolean isValidChar(char ch) { public static final boolean isValidChar(char ch) {
@@ -143,12 +137,10 @@ public class CodeTemplateManager {
/** /**
* Returns the specified code template. * Returns the specified code template.
* *
* @param template * @param template The template to remove.
* The template to remove. * @return <code>true</code> if the template was removed, <code>false</code> if
* @return <code>true</code> if the template was removed, <code>false</code> * the template was not in this template manager.
* if the template was not in this template manager. * @throws IllegalArgumentException If <code>template</code> is
* @throws IllegalArgumentException
* If <code>template</code> is
* <code>null</code>. * <code>null</code>.
* @see #removeTemplate(String) * @see #removeTemplate(String)
* @see #addTemplate(CodeTemplate) * @see #addTemplate(CodeTemplate)
@@ -164,12 +156,10 @@ public class CodeTemplateManager {
/** /**
* Returns the code template with the specified id. * Returns the code template with the specified id.
* *
* @param id * @param id The id to check for.
* The id to check for. * @return The code template that was removed, or <code>null</code> if there was
* @return The code template that was removed, or <code>null</code> if * no template with the specified ID.
* there was no template with the specified ID. * @throws IllegalArgumentException If <code>id</code> is <code>null</code>.
* @throws IllegalArgumentException
* If <code>id</code> is <code>null</code>.
* @see #removeTemplate(CodeTemplate) * @see #removeTemplate(CodeTemplate)
* @see #addTemplate(CodeTemplate) * @see #addTemplate(CodeTemplate)
*/ */
@@ -189,12 +179,10 @@ public class CodeTemplateManager {
} }
/** /**
* Replaces the current set of available templates with the ones * Replaces the current set of available templates with the ones specified.
* specified.
* *
* @param newTemplates * @param newTemplates The new set of templates. Note that we will be taking a
* The new set of templates. Note that we will * shallow copy of these and sorting them.
* be taking a shallow copy of these and sorting them.
*/ */
public synchronized void replaceTemplates(CodeTemplate[] newTemplates) { public synchronized void replaceTemplates(CodeTemplate[] newTemplates) {
templates.clear(); templates.clear();
@@ -245,12 +233,11 @@ public class CodeTemplateManager {
} }
/** /**
* Sets the directory in which to look for templates. Calling this * Sets the directory in which to look for templates. Calling this method adds
* method adds any new templates found in the specified directory to * any new templates found in the specified directory to the templates already
* the templates already registered. * registered.
* *
* @param dir * @param dir The new directory in which to look for templates.
* The new directory in which to look for templates.
* @return The new number of templates in this template manager, or * @return The new number of templates in this template manager, or
* <code>-1</code> if the specified directory does not exist. * <code>-1</code> if the specified directory does not exist.
*/ */
@@ -287,9 +274,8 @@ public class CodeTemplateManager {
} }
/** /**
* Removes any null entries in the current set of templates (if * Removes any null entries in the current set of templates (if any), sorts the
* any), sorts the remaining templates, and computes the new * remaining templates, and computes the new maximum template ID length.
* maximum template ID length.
*/ */
private synchronized void sortTemplates() { private synchronized void sortTemplates() {
// Get the maximum length of a template ID. // Get the maximum length of a template ID.
@@ -309,11 +295,10 @@ public class CodeTemplateManager {
} }
/** /**
* A comparator that takes a <code>CodeTemplate</code> as its first * A comparator that takes a <code>CodeTemplate</code> as its first parameter
* parameter and a <code>Segment</code> as its second, and knows * and a <code>Segment</code> as its second, and knows to compare the template's
* to compare the template's ID to the segment's text. * ID to the segment's text.
*/ */
@SuppressWarnings("rawtypes")
private static class TemplateComparator implements Comparator, Serializable { private static class TemplateComparator implements Comparator, Serializable {
@Override @Override
@@ -15,17 +15,16 @@ import javax.swing.KeyStroke;
import org.fife.ui.rtextarea.RTADefaultInputMap; import org.fife.ui.rtextarea.RTADefaultInputMap;
/** /**
* The default input map for an <code>RSyntaxTextArea</code>. * The default input map for an <code>RSyntaxTextArea</code>. Currently, the new
* Currently, the new key bindings include: * key bindings include:
* <ul> * <ul>
* <li>Shift+Tab indents the current line or currently selected lines * <li>Shift+Tab indents the current line or currently selected lines to the
* to the left. * left.
* </ul> * </ul>
* *
* @author Robert Futrell * @author Robert Futrell
* @version 1.0 * @version 1.0
*/ */
@SuppressWarnings({ "checkstyle:linelength" })
public class RSyntaxTextAreaDefaultInputMap extends RTADefaultInputMap { public class RSyntaxTextAreaDefaultInputMap extends RTADefaultInputMap {
/** /**
@@ -60,18 +59,23 @@ public class RSyntaxTextAreaDefaultInputMap extends RTADefaultInputMap {
// (unfortunately) don't have a ToggleCommentAction for *nix // (unfortunately) don't have a ToggleCommentAction for *nix
// out-of-the-box. // out-of-the-box.
// Applications can add one easily enough if they want one. // Applications can add one easily enough if they want one.
put(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, defaultMod), RSyntaxTextAreaEditorKit.rstaToggleCommentAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, defaultMod),
RSyntaxTextAreaEditorKit.rstaToggleCommentAction);
} }
put(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, defaultMod), RSyntaxTextAreaEditorKit.rstaGoToMatchingBracketAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, defaultMod),
RSyntaxTextAreaEditorKit.rstaGoToMatchingBracketAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, defaultMod), RSyntaxTextAreaEditorKit.rstaCollapseFoldAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, defaultMod), RSyntaxTextAreaEditorKit.rstaCollapseFoldAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, defaultMod), RSyntaxTextAreaEditorKit.rstaExpandFoldAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, defaultMod), RSyntaxTextAreaEditorKit.rstaExpandFoldAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DIVIDE, defaultMod), RSyntaxTextAreaEditorKit.rstaCollapseAllFoldsAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_DIVIDE, defaultMod),
put(KeyStroke.getKeyStroke(KeyEvent.VK_MULTIPLY, defaultMod), RSyntaxTextAreaEditorKit.rstaExpandAllFoldsAction); RSyntaxTextAreaEditorKit.rstaCollapseAllFoldsAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_MULTIPLY, defaultMod),
RSyntaxTextAreaEditorKit.rstaExpandAllFoldsAction);
// NOTE: no modifiers => mapped to keyTyped. If we had "0" as a second // NOTE: no modifiers => mapped to keyTyped. If we had "0" as a second
// second parameter, we'd get the template action (keyPressed) AND the // second parameter, we'd get the template action (keyPressed) AND the
// default space action (keyTyped). // default space action (keyTyped).
// put(KeyStroke.getKeyStroke(' '), // put(KeyStroke.getKeyStroke(' '),
// RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction); // RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, defaultShift), RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, defaultShift),
RSyntaxTextAreaEditorKit.rstaPossiblyInsertTemplateAction);
} }
} }
@@ -63,7 +63,6 @@ import org.fife.ui.rtextarea.RecordableTextAction;
* @author Robert Futrell * @author Robert Futrell
* @version 0.5 * @version 0.5
*/ */
@SuppressWarnings({ "checkstyle:constantname" })
public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit { public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -88,21 +87,25 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
*/ */
private static final Action[] defaultActions = { new CloseCurlyBraceAction(), new CloseMarkupTagAction(), private static final Action[] defaultActions = { new CloseCurlyBraceAction(), new CloseMarkupTagAction(),
new BeginWordAction(beginWordAction, false), new BeginWordAction(selectionBeginWordAction, true), new BeginWordAction(beginWordAction, false), new BeginWordAction(selectionBeginWordAction, true),
new ChangeFoldStateAction(rstaCollapseFoldAction, true), new ChangeFoldStateAction(rstaExpandFoldAction, false), new ChangeFoldStateAction(rstaCollapseFoldAction, true),
new CollapseAllFoldsAction(), new CopyAsRtfAction(), new ChangeFoldStateAction(rstaExpandFoldAction, false), new CollapseAllFoldsAction(), new CopyAsRtfAction(),
// new DecreaseFontSizeAction(), // new DecreaseFontSizeAction(),
new DecreaseIndentAction(), new DeletePrevWordAction(), new DumbCompleteWordAction(), new EndAction(endAction, false), new DecreaseIndentAction(), new DeletePrevWordAction(), new DumbCompleteWordAction(),
new EndAction(selectionEndAction, true), new EndWordAction(endWordAction, false), new EndWordAction(endWordAction, true), new EndAction(endAction, false), new EndAction(selectionEndAction, true),
new ExpandAllFoldsAction(), new GoToMatchingBracketAction(), new InsertBreakAction(), new EndWordAction(endWordAction, false), new EndWordAction(endWordAction, true), new ExpandAllFoldsAction(),
new GoToMatchingBracketAction(), new InsertBreakAction(),
// new IncreaseFontSizeAction(), // new IncreaseFontSizeAction(),
new InsertTabAction(), new NextWordAction(nextWordAction, false), new NextWordAction(selectionNextWordAction, true), new InsertTabAction(), new NextWordAction(nextWordAction, false),
new PossiblyInsertTemplateAction(), new PreviousWordAction(previousWordAction, false), new NextWordAction(selectionNextWordAction, true), new PossiblyInsertTemplateAction(),
new PreviousWordAction(selectionPreviousWordAction, true), new SelectWordAction(), new ToggleCommentAction(), }; new PreviousWordAction(previousWordAction, false),
new PreviousWordAction(selectionPreviousWordAction, true), new SelectWordAction(),
new ToggleCommentAction(), };
/** /**
* Constructor. * Constructor.
*/ */
public RSyntaxTextAreaEditorKit() {} public RSyntaxTextAreaEditorKit() {
}
/** /**
* Returns the default document used by <code>RSyntaxTextArea</code>s. * Returns the default document used by <code>RSyntaxTextArea</code>s.
@@ -117,8 +120,7 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
/** /**
* Overridden to return a row header that is aware of folding. * Overridden to return a row header that is aware of folding.
* *
* @param textArea * @param textArea The text area.
* The text area.
* @return The icon row header. * @return The icon row header.
*/ */
@Override @Override
@@ -127,9 +129,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Fetches the set of commands that can be used * Fetches the set of commands that can be used on a text component that is
* on a text component that is using a model and * using a model and view produced by this kit.
* view produced by this kit.
* *
* @return the command list * @return the command list
*/ */
@@ -139,11 +140,10 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Returns localized text for an action. There's definitely a better place * Returns localized text for an action. There's definitely a better place for
* for this functionality. * this functionality.
* *
* @param key * @param key The key into the action resource bundle.
* The key into the action resource bundle.
* @return The localized text. * @return The localized text.
*/ */
public static String getString(String key) { public static String getString(String key) {
@@ -151,9 +151,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Positions the caret at the beginning of the word. This class is here * Positions the caret at the beginning of the word. This class is here to
* to better handle finding the "beginning of the word" for programming * better handle finding the "beginning of the word" for programming languages.
* languages.
*/ */
protected static class BeginWordAction extends RTextAreaEditorKit.BeginWordAction { protected static class BeginWordAction extends RTextAreaEditorKit.BeginWordAction {
@@ -358,7 +357,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
rsta.replaceSelection("/"); rsta.replaceSelection("/");
// Don't automatically complete a tag if there was a selection // Don't automatically complete a tag if there was a selection
int dot = c.getDot(); int dot = c.getDot();
if (doc.getLanguageIsMarkup() && doc.getCompleteMarkupCloseTags() && !selection && rsta.getCloseMarkupTags() && dot > 1) { if (doc.getLanguageIsMarkup() && doc.getCompleteMarkupCloseTags() && !selection && rsta.getCloseMarkupTags()
&& dot > 1) {
try { try {
// Check actual char before token type, since it's quicker // Check actual char before token type, since it's quicker
char ch = doc.charAt(dot - 2); char ch = doc.charAt(dot - 2);
@@ -381,18 +381,15 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Discovers the name of the tag being closed. Assumes standard * Discovers the name of the tag being closed. Assumes standard SGML-style
* SGML-style markup tags. * markup tags.
* *
* @param doc * @param doc The document to parse.
* The document to parse. * @param dot The location of the caret. This should be right after the start of
* @param dot * a closing tag token (e.g. "<code>&lt;/</code>" or "<code>[</code>"
* The location of the caret. This should be right after * in the case of BBCode).
* the start of a closing tag token (e.g. * @return The name of the tag to close, or <code>null</code> if it could not be
* "<code>&lt;/</code>" * determined.
* or "<code>[</code>" in the case of BBCode).
* @return The name of the tag to close, or <code>null</code> if it
* could not be determined.
*/ */
private String discoverTagName(RSyntaxDocument doc, int dot) { private String discoverTagName(RSyntaxDocument doc, int dot) {
Stack<String> stack = new Stack<String>(); Stack<String> stack = new Stack<String>();
@@ -416,11 +413,13 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
t = t.getNextToken(); t = t.getNextToken();
} }
} else if (t.length() == 2 && t.charAt(0) == '/' && (t.charAt(1) == '>' || t.charAt(1) == ']')) { } else if (t.length() == 2 && t.charAt(0) == '/'
&& (t.charAt(1) == '>' || t.charAt(1) == ']')) {
if (!stack.isEmpty()) { // Always true for valid XML if (!stack.isEmpty()) { // Always true for valid XML
stack.pop(); stack.pop();
} }
} else if (t.length() == 2 && (t.charAt(0) == '<' || t.charAt(0) == '[') && t.charAt(1) == '/') { } else if (t.length() == 2 && (t.charAt(0) == '<' || t.charAt(0) == '[')
&& t.charAt(1) == '/') {
String tagName = null; String tagName = null;
if (!stack.isEmpty()) { // Always true for valid XML if (!stack.isEmpty()) { // Always true for valid XML
tagName = stack.pop(); tagName = stack.pop();
@@ -454,7 +453,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
setProperties(msg, "Action.CollapseCommentFolds"); setProperties(msg, "Action.CollapseCommentFolds");
} }
public CollapseAllCommentFoldsAction(String name, Icon icon, String desc, Integer mnemonic, KeyStroke accelerator) { public CollapseAllCommentFoldsAction(String name, Icon icon, String desc, Integer mnemonic,
KeyStroke accelerator) {
super(name, icon, desc, mnemonic, accelerator); super(name, icon, desc, mnemonic, accelerator);
} }
@@ -712,21 +712,17 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Actually does the "de-indentation." This method finds where the * Actually does the "de-indentation." This method finds where the given
* given element's leading whitespace ends, then, if there is indeed * element's leading whitespace ends, then, if there is indeed leading
* leading whitespace, removes either the last char in it (if it is a * whitespace, removes either the last char in it (if it is a tab), or removes
* tab), or removes up to the number of spaces equal to a tab in the * up to the number of spaces equal to a tab in the specified document (i.e., if
* specified document (i.e., if the tab size was 5 and there were 3 * the tab size was 5 and there were 3 spaces at the end of the leading
* spaces at the end of the leading whitespace, the three will be * whitespace, the three will be removed; if there were 8 spaces, only the first
* removed; if there were 8 spaces, only the first 5 would be * 5 would be removed).
* removed).
* *
* @param elem * @param elem The element to "de-indent."
* The element to "de-indent." * @param doc The document containing the specified element.
* @param doc * @param tabSize The size of a tab, in spaces.
* The document containing the specified element.
* @param tabSize
* The size of a tab, in spaces.
*/ */
private void handleDecreaseIndent(Element elem, Document doc, int tabSize) throws BadLocationException { private void handleDecreaseIndent(Element elem, Document doc, int tabSize) throws BadLocationException {
int start = elem.getStartOffset(); int start = elem.getStartOffset();
@@ -756,8 +752,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Deletes the previous word, but differentiates symbols from "words" to * Deletes the previous word, but differentiates symbols from "words" to match
* match the behavior of code editors. * the behavior of code editors.
*/ */
public static class DeletePrevWordAction extends RTextAreaEditorKit.DeletePrevWordAction { public static class DeletePrevWordAction extends RTextAreaEditorKit.DeletePrevWordAction {
@@ -814,8 +810,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Overridden to use the programming language RSTA is displaying when * Overridden to use the programming language RSTA is displaying when computing
* computing words to complete. * words to complete.
*/ */
public static class DumbCompleteWordAction extends RTextAreaEditorKit.DumbCompleteWordAction { public static class DumbCompleteWordAction extends RTextAreaEditorKit.DumbCompleteWordAction {
@@ -849,7 +845,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
return prevWordStart; return prevWordStart;
} }
private int getPreviousWordStartInLine(RSyntaxDocument doc, Element elem, int offs) throws BadLocationException { private int getPreviousWordStartInLine(RSyntaxDocument doc, Element elem, int offs)
throws BadLocationException {
int start = elem.getStartOffset(); int start = elem.getStartOffset();
int cur = offs; int cur = offs;
// Skip any whitespace or non-word chars // Skip any whitespace or non-word chars
@@ -908,13 +905,12 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Overridden to not suggest word completions if the text right before * Overridden to not suggest word completions if the text right before the caret
* the caret contains non-word characters, such as '/' or '%'. * contains non-word characters, such as '/' or '%'.
* *
* @param prefix * @param prefix The prefix characters before the caret.
* The prefix characters before the caret. * @return Whether the prefix could be part of a "word" in the context of the
* @return Whether the prefix could be part of a "word" in the context * text area's current content.
* of the text area's current content.
*/ */
@Override @Override
protected boolean isAcceptablePrefix(String prefix) { protected boolean isAcceptablePrefix(String prefix) {
@@ -922,11 +918,10 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Returns whether the specified character should be considered part * Returns whether the specified character should be considered part of an
* of an identifier. * identifier.
* *
* @param ch * @param ch The character.
* The character.
* @return Whether the character is part of an identifier. * @return Whether the character is part of an identifier.
*/ */
private static boolean isIdentifierChar(char ch) { private static boolean isIdentifierChar(char ch) {
@@ -936,8 +931,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Positions the caret at the end of the word. This class is here to * Positions the caret at the end of the word. This class is here to better
* better handle finding the "end of the word" in programming languages. * handle finding the "end of the word" in programming languages.
*/ */
protected static class EndWordAction extends RTextAreaEditorKit.EndWordAction { protected static class EndWordAction extends RTextAreaEditorKit.EndWordAction {
@@ -1061,14 +1056,13 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action for moving the caret to the "matching bracket" of the bracket * Action for moving the caret to the "matching bracket" of the bracket at the
* at the caret position (either before or after). * caret position (either before or after).
*/ */
public static class GoToMatchingBracketAction extends RecordableTextAction { public static class GoToMatchingBracketAction extends RecordableTextAction {
/** /**
* Moves the caret to the end of the document, taking into account code * Moves the caret to the end of the document, taking into account code folding.
* folding.
*/ */
public static class EndAction extends RTextAreaEditorKit.EndAction { public static class EndAction extends RTextAreaEditorKit.EndAction {
@@ -1199,8 +1193,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action for when the user presses the Enter key. This is here so we can * Action for when the user presses the Enter key. This is here so we can be
* be smart and "auto-indent" for programming languages. * smart and "auto-indent" for programming languages.
*/ */
public static class InsertBreakAction extends RTextAreaEditorKit.InsertBreakAction { public static class InsertBreakAction extends RTextAreaEditorKit.InsertBreakAction {
@@ -1228,10 +1222,9 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* @return The first location in the string past <code>pos</code> that * @return The first location in the string past <code>pos</code> that is NOT a
* is NOT a whitespace char, or <code>-1</code> if only * whitespace char, or <code>-1</code> if only whitespace chars follow
* whitespace chars follow <code>pos</code> (or it is the end * <code>pos</code> (or it is the end position in the string).
* position in the string).
*/ */
private static int atEndOfLine(int pos, String s, int sLen) { private static int atEndOfLine(int pos, String s, int sLen) {
for (int i = pos; i < sLen; i++) { for (int i = pos; i < sLen; i++) {
@@ -1258,13 +1251,12 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Actually inserts the newline into the document, and auto-indents * Actually inserts the newline into the document, and auto-indents if
* if appropriate. This method can be called by token makers who * appropriate. This method can be called by token makers who implement a custom
* implement a custom action for inserting newlines. * action for inserting newlines.
* *
* @param textArea * @param textArea
* @param noSelection * @param noSelection Whether there is no selection.
* Whether there is no selection.
*/ */
protected void handleInsertBreak(RSyntaxTextArea textArea, boolean noSelection) { protected void handleInsertBreak(RSyntaxTextArea textArea, boolean noSelection) {
// If we're auto-indenting... // If we're auto-indenting...
@@ -1337,7 +1329,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
t = t.getLastNonCommentNonWhitespaceToken(); t = t.getLastNonCommentNonWhitespaceToken();
if (t != null && t.isLeftCurly()) { if (t != null && t.isLeftCurly()) {
int languageIndex = t.getLanguageIndex(); int languageIndex = t.getLanguageIndex();
if (doc.getCurlyBracesDenoteCodeBlocks(languageIndex) && getOpenBraceCount(doc, languageIndex) > 0) { if (doc.getCurlyBracesDenoteCodeBlocks(languageIndex)
&& getOpenBraceCount(doc, languageIndex) > 0) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (line == textArea.getLineCount() - 1) { if (line == textArea.getLineCount() - 1) {
sb.append('\n'); sb.append('\n');
@@ -1361,8 +1354,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action for inserting tabs. This is extended to "block indent" a * Action for inserting tabs. This is extended to "block indent" a group of
* group of contiguous lines if they are selected. * contiguous lines if they are selected.
*/ */
public static class InsertTabAction extends RecordableTextAction { public static class InsertTabAction extends RecordableTextAction {
@@ -1441,9 +1434,9 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action to move the selection and/or caret. Constructor indicates * Action to move the selection and/or caret. Constructor indicates direction to
* direction to use. This class overrides the behavior defined in * use. This class overrides the behavior defined in {@link RTextAreaEditorKit}
* {@link RTextAreaEditorKit} to better skip "words" in source code. * to better skip "words" in source code.
*/ */
public static class NextWordAction extends RTextAreaEditorKit.NextWordAction { public static class NextWordAction extends RTextAreaEditorKit.NextWordAction {
@@ -1471,7 +1464,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
if (rsta.isCodeFoldingEnabled()) { // Start of next visible line if (rsta.isCodeFoldingEnabled()) { // Start of next visible line
FoldManager fm = rsta.getFoldManager(); FoldManager fm = rsta.getFoldManager();
int lineCount = root.getElementCount(); int lineCount = root.getElementCount();
while (++line < lineCount && fm.isLineHidden(line)); while (++line < lineCount && fm.isLineHidden(line))
;
if (line < lineCount) { // Found a lower visible line if (line < lineCount) { // Found a lower visible line
offs = root.getElement(line).getStartOffset(); offs = root.getElement(line).getStartOffset();
} }
@@ -1497,7 +1491,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
else if (!Character.isWhitespace(ch)) { else if (!Character.isWhitespace(ch)) {
do { do {
ch = seg.next(); ch = seg.next();
} while (ch != Segment.DONE && !(doc.isIdentifierChar(languageIndex, ch) || Character.isWhitespace(ch))); } while (ch != Segment.DONE
&& !(doc.isIdentifierChar(languageIndex, ch) || Character.isWhitespace(ch)));
} }
// Skip any trailing whitespace // Skip any trailing whitespace
while (Character.isWhitespace(ch)) { while (Character.isWhitespace(ch)) {
@@ -1509,9 +1504,9 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action for when the user tries to insert a template (that is, * Action for when the user tries to insert a template (that is, they've typed a
* they've typed a template ID and pressed the trigger character * template ID and pressed the trigger character (a space) in an attempt to do
* (a space) in an attempt to do the substitution). * the substitution).
*/ */
public static class PossiblyInsertTemplateAction extends RecordableTextAction { public static class PossiblyInsertTemplateAction extends RecordableTextAction {
@@ -1578,9 +1573,9 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action to move the selection and/or caret. Constructor indicates * Action to move the selection and/or caret. Constructor indicates direction to
* direction to use. This class overrides the behavior defined in * use. This class overrides the behavior defined in {@link RTextAreaEditorKit}
* {@link RTextAreaEditorKit} to better skip "words" in source code. * to better skip "words" in source code.
*/ */
public static class PreviousWordAction extends RTextAreaEditorKit.PreviousWordAction { public static class PreviousWordAction extends RTextAreaEditorKit.PreviousWordAction {
@@ -1607,7 +1602,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
RSyntaxTextArea rsta = (RSyntaxTextArea) textArea; RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
if (rsta.isCodeFoldingEnabled()) { // End of next visible line if (rsta.isCodeFoldingEnabled()) { // End of next visible line
FoldManager fm = rsta.getFoldManager(); FoldManager fm = rsta.getFoldManager();
while (--line >= 0 && fm.isLineHidden(line)); while (--line >= 0 && fm.isLineHidden(line))
;
if (line >= 0) { // Found an earlier visible line if (line >= 0) { // Found an earlier visible line
offs = root.getElement(line).getEndOffset() - 1; offs = root.getElement(line).getEndOffset() - 1;
} }
@@ -1636,7 +1632,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
else if (!Character.isWhitespace(ch)) { else if (!Character.isWhitespace(ch)) {
do { do {
ch = seg.previous(); ch = seg.previous();
} while (ch != Segment.DONE && !(doc.isIdentifierChar(languageIndex, ch) || Character.isWhitespace(ch))); } while (ch != Segment.DONE
&& !(doc.isIdentifierChar(languageIndex, ch) || Character.isWhitespace(ch)));
} }
offs -= seg.getEndIndex() - seg.getIndex(); offs -= seg.getEndIndex() - seg.getIndex();
if (ch != Segment.DONE) { if (ch != Segment.DONE) {
@@ -1647,8 +1644,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Selects the word around the caret. This class is here to better * Selects the word around the caret. This class is here to better handle
* handle selecting "words" in programming languages. * selecting "words" in programming languages.
*/ */
public static class SelectWordAction extends RTextAreaEditorKit.SelectWordAction { public static class SelectWordAction extends RTextAreaEditorKit.SelectWordAction {
@@ -1660,8 +1657,7 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
/** /**
* Action that toggles whether the currently selected lines are * Action that toggles whether the currently selected lines are commented.
* commented.
*/ */
public static class ToggleCommentAction extends RecordableTextAction { public static class ToggleCommentAction extends RecordableTextAction {
@@ -1714,7 +1710,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
} }
} }
private boolean getDoAdd(Document doc, Element map, int startLine, int endLine, String[] startEnd) throws BadLocationException { private boolean getDoAdd(Document doc, Element map, int startLine, int endLine, String[] startEnd)
throws BadLocationException {
boolean doAdd = false; boolean doAdd = false;
for (int i = startLine; i <= endLine; i++) { for (int i = startLine; i <= endLine; i++) {
Element elem = map.getElement(i); Element elem = map.getElement(i);
@@ -1728,7 +1725,8 @@ public class RSyntaxTextAreaEditorKit extends RTextAreaEditorKit {
return doAdd; return doAdd;
} }
private void handleToggleComment(Element elem, Document doc, String[] startEnd, boolean add) throws BadLocationException { private void handleToggleComment(Element elem, Document doc, String[] startEnd, boolean add)
throws BadLocationException {
int start = elem.getStartOffset(); int start = elem.getStartOffset();
int end = elem.getEndOffset() - 1; int end = elem.getEndOffset() - 1;
if (add) { if (add) {
+23 -36
View File
@@ -28,7 +28,6 @@ import javax.swing.JPanel;
* @author Robert Futrell * @author Robert Futrell
* @version 0.6 * @version 0.6
*/ */
@SuppressWarnings({ "checkstyle:visibilitymodifier" })
public class Style implements Cloneable { public class Style implements Cloneable {
public static final Color DEFAULT_FOREGROUND = Color.BLACK; public static final Color DEFAULT_FOREGROUND = Color.BLACK;
@@ -41,8 +40,8 @@ public class Style implements Cloneable {
public FontMetrics fontMetrics; public FontMetrics fontMetrics;
/** /**
* Creates a new style defaulting to black foreground, no * Creates a new style defaulting to black foreground, no background, and no
* background, and no styling. * styling.
*/ */
public Style() { public Style() {
this(DEFAULT_FOREGROUND); this(DEFAULT_FOREGROUND);
@@ -51,8 +50,7 @@ public class Style implements Cloneable {
/** /**
* Creates a new style with the specified foreground and no styling. * Creates a new style with the specified foreground and no styling.
* *
* @param fg * @param fg The foreground color to use.
* The foreground color to use.
*/ */
public Style(Color fg) { public Style(Color fg) {
this(fg, DEFAULT_BACKGROUND); this(fg, DEFAULT_BACKGROUND);
@@ -61,10 +59,8 @@ public class Style implements Cloneable {
/** /**
* Creates a new style with the specified colors and no styling. * Creates a new style with the specified colors and no styling.
* *
* @param fg * @param fg The foreground color to use.
* The foreground color to use. * @param bg The background color to use.
* @param bg
* The background color to use.
*/ */
public Style(Color fg, Color bg) { public Style(Color fg, Color bg) {
this(fg, bg, DEFAULT_FONT); this(fg, bg, DEFAULT_FONT);
@@ -73,12 +69,9 @@ public class Style implements Cloneable {
/** /**
* Creates a new style. * Creates a new style.
* *
* @param fg * @param fg The foreground color to use.
* The foreground color to use. * @param bg The background color to use.
* @param bg * @param font The font for this syntax scheme.
* The background color to use.
* @param font
* The font for this syntax scheme.
*/ */
public Style(Color fg, Color bg, Font font) { public Style(Color fg, Color bg, Font font) {
this(fg, bg, font, false); this(fg, bg, font, false);
@@ -87,14 +80,10 @@ public class Style implements Cloneable {
/** /**
* Creates a new style. * Creates a new style.
* *
* @param fg * @param fg The foreground color to use.
* The foreground color to use. * @param bg The background color to use.
* @param bg * @param font The font for this syntax scheme.
* The background color to use. * @param underline Whether or not to underline tokens with this style.
* @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) { public Style(Color fg, Color bg, Font font, boolean underline) {
foreground = fg; foreground = fg;
@@ -108,8 +97,7 @@ public class Style implements Cloneable {
} }
/** /**
* Returns whether or not two (possibly <code>null</code>) objects are * Returns whether or not two (possibly <code>null</code>) objects are equal.
* equal.
*/ */
private boolean areEqual(Object o1, Object o2) { private boolean areEqual(Object o1, Object o2) {
return (o1 == null && o2 == null) || (o1 != null && o1.equals(o2)); return (o1 == null && o2 == null) || (o1 != null && o1.equals(o2));
@@ -140,17 +128,16 @@ public class Style implements Cloneable {
/** /**
* Returns whether or not two syntax schemes are equal. * Returns whether or not two syntax schemes are equal.
* *
* @param o2 * @param o2 The object with which to compare this syntax scheme.
* The object with which to compare this syntax scheme. * @return Whether or not these two syntax schemes represent the same scheme.
* @return Whether or not these two syntax schemes represent the same
* scheme.
*/ */
@Override @Override
public boolean equals(Object o2) { public boolean equals(Object o2) {
if (o2 instanceof Style) { if (o2 instanceof Style) {
Style ss2 = (Style) o2; Style ss2 = (Style) o2;
if (this.underline == ss2.underline && areEqual(foreground, ss2.foreground) && areEqual(background, ss2.background) if (this.underline == ss2.underline && areEqual(foreground, ss2.foreground)
&& areEqual(font, ss2.font) && areEqual(fontMetrics, ss2.fontMetrics)) { && areEqual(background, ss2.background) && areEqual(font, ss2.font)
&& areEqual(fontMetrics, ss2.fontMetrics)) {
return true; return true;
} }
} }
@@ -158,12 +145,11 @@ public class Style implements Cloneable {
} }
/** /**
* Computes the hash code to use when adding this syntax scheme to * Computes the hash code to use when adding this syntax scheme to hash tables.
* hash tables.
* <p> * <p>
* *
* This method is implemented, since {@link #equals(Object)} is implemented, * This method is implemented, since {@link #equals(Object)} is implemented, to
* to keep FindBugs happy. * keep FindBugs happy.
* *
* @return The hash code. * @return The hash code.
*/ */
@@ -186,6 +172,7 @@ public class Style implements Cloneable {
*/ */
@Override @Override
public String toString() { public String toString() {
return "[Style: foreground: " + foreground + ", background: " + background + ", underline: " + underline + ", font: " + font + "]"; return "[Style: foreground: " + foreground + ", background: " + background + ", underline: " + underline
+ ", font: " + font + "]";
} }
} }
+87 -116
View File
@@ -24,8 +24,8 @@ import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory; import org.xml.sax.helpers.XMLReaderFactory;
/** /**
* The set of colors and styles used by an <code>RSyntaxTextArea</code> to * The set of colors and styles used by an <code>RSyntaxTextArea</code> to color
* color tokens. * tokens.
* <p> * <p>
* You can use this class to programmatically set the fonts and colors used in * You can use this class to programmatically set the fonts and colors used in
* an RSyntaxTextArea, but for more powerful, externalized control, consider * an RSyntaxTextArea, but for more powerful, externalized control, consider
@@ -35,20 +35,18 @@ import org.xml.sax.helpers.XMLReaderFactory;
* @version 1.0 * @version 1.0
* @see Theme * @see Theme
*/ */
@SuppressWarnings({ "checkstyle:magicnumber" })
public class SyntaxScheme implements Cloneable, TokenTypes { public class SyntaxScheme implements Cloneable, TokenTypes {
private Style[] styles; private Style[] styles;
private static final String VERSION = "*ver1"; private static final String VERSION = "*ver1";
/** /**
* Creates a color scheme that either has all color values set to * Creates a color scheme that either has all color values set to a default
* a default value or set to <code>null</code>. * value or set to <code>null</code>.
* *
* @param useDefaults * @param useDefaults If <code>true</code>, all color values will be set to
* If <code>true</code>, all color values will * default colors; if <code>false</code>, all colors will be
* be set to default colors; if <code>false</code>, all colors * initially <code>null</code>.
* will be initially <code>null</code>.
*/ */
public SyntaxScheme(boolean useDefaults) { public SyntaxScheme(boolean useDefaults) {
styles = new Style[DEFAULT_NUM_TOKEN_TYPES]; styles = new Style[DEFAULT_NUM_TOKEN_TYPES];
@@ -60,10 +58,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Creates a default color scheme. * Creates a default color scheme.
* *
* @param baseFont * @param baseFont The base font to use. Keywords will be a bold version of this
* The base font to use. Keywords will be a bold version * font, and comments will be an italicized version of this
* of this font, and comments will be an italicized version of
* this
* font. * font.
*/ */
public SyntaxScheme(Font baseFont) { public SyntaxScheme(Font baseFont) {
@@ -73,14 +69,11 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Creates a default color scheme. * Creates a default color scheme.
* *
* @param baseFont * @param baseFont The base font to use. Keywords will be a bold version of
* The base font to use. Keywords will be a bold version * this font, and comments will be an italicized version of
* of this font, and comments will be an italicized version of * this font.
* this * @param fontStyles Whether bold and italic should be used in the scheme (vs.
* font. * all tokens using a plain 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) { public SyntaxScheme(Font baseFont, boolean fontStyles) {
styles = new Style[DEFAULT_NUM_TOKEN_TYPES]; styles = new Style[DEFAULT_NUM_TOKEN_TYPES];
@@ -90,16 +83,14 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Changes the "base font" for this syntax scheme. This is called by * Changes the "base font" for this syntax scheme. This is called by
* <code>RSyntaxTextArea</code> when its font changes via * <code>RSyntaxTextArea</code> when its font changes via
* <code>setFont()</code>. This looks for tokens that use a derivative of * <code>setFont()</code>. This looks for tokens that use a derivative of the
* the text area's old font (but bolded and/or italicized) and make them * text area's old font (but bolded and/or italicized) and make them use the new
* use the new font with those stylings instead. This is desirable because * font with those stylings instead. This is desirable because most programmers
* most programmers prefer a single font to be used in their text editor, * prefer a single font to be used in their text editor, but might want bold
* but might want bold (say for keywords) or italics. * (say for keywords) or italics.
* *
* @param old * @param old The old font of the text area.
* The old font of the text area. * @param font The new font of the text area.
* @param font
* The new font of the text area.
*/ */
void changeBaseFont(Font old, Font font) { void changeBaseFont(Font old, Font font) {
for (int i = 0; i < styles.length; i++) { for (int i = 0; i < styles.length; i++) {
@@ -141,11 +132,9 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Tests whether this color scheme is the same as another color scheme. * Tests whether this color scheme is the same as another color scheme.
* *
* @param otherScheme * @param otherScheme The color scheme to compare to.
* The color scheme to compare to. * @return <code>true</code> if this color scheme and <code>otherScheme</code>
* @return <code>true</code> if this color scheme and * are the same scheme; <code>false</code> otherwise.
* <code>otherScheme</code> are the same scheme;
* <code>false</code> otherwise.
*/ */
@Override @Override
public boolean equals(Object otherScheme) { public boolean equals(Object otherScheme) {
@@ -172,8 +161,7 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
* Returns a hex string representing an RGB color, of the form * Returns a hex string representing an RGB color, of the form
* <code>"$rrggbb"</code>. * <code>"$rrggbb"</code>.
* *
* @param c * @param c The color.
* The color.
* @return The string representation of the color. * @return The string representation of the color.
*/ */
private static String getHexString(Color c) { private static String getHexString(Color c) {
@@ -183,8 +171,7 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Returns the specified style. * Returns the specified style.
* *
* @param index * @param index The index of the style.
* The index of the style.
* @return The style. * @return The style.
* @see #setStyle(int, Style) * @see #setStyle(int, Style)
* @see #getStyleCount() * @see #getStyleCount()
@@ -204,12 +191,12 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
/** /**
* Used by third party implementors e.g. SquirreL SQL. Most applications do * Used by third party implementors e.g. SquirreL SQL. Most applications do not
* not need to call this method. * need to call this method.
* <p> * <p>
* Note that the returned array is not a copy of the style data; editing the * Note that the returned array is not a copy of the style data; editing the
* array will modify the styles used by any <code>RSyntaxTextArea</code> * array will modify the styles used by any <code>RSyntaxTextArea</code> using
* using this scheme. * this scheme.
* *
* @return The style array. * @return The style array.
* @see #setStyles(Style[]) * @see #setStyles(Style[])
@@ -219,8 +206,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
/** /**
* This is implemented to be consistent with {@link #equals(Object)}. * This is implemented to be consistent with {@link #equals(Object)}. This is a
* This is a requirement to keep FindBugs happy. * requirement to keep FindBugs happy.
* *
* @return The hash code for this object. * @return The hash code for this object.
*/ */
@@ -243,19 +230,15 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
* Loads a syntax scheme from an input stream. * Loads a syntax scheme from an input stream.
* <p> * <p>
* *
* Consider using the {@link Theme} class for saving and loading RSTA * Consider using the {@link Theme} class for saving and loading RSTA styles
* styles rather than using this API. * rather than using this API.
* *
* @param baseFont * @param baseFont The font to use as the "base" for the syntax scheme. If this
* The font to use as the "base" for the syntax scheme. * is <code>null</code>, a default monospaced font is used.
* If this is <code>null</code>, a default monospaced font is * @param in The stream to load from. It is up to the caller to close this
* used.
* @param in
* The stream to load from. It is up to the caller to close this
* stream when they are done. * stream when they are done.
* @return The syntax scheme. * @return The syntax scheme.
* @throws IOException * @throws IOException If an IO error occurs.
* If an IO error occurs.
*/ */
public static SyntaxScheme load(Font baseFont, InputStream in) throws IOException { public static SyntaxScheme load(Font baseFont, InputStream in) throws IOException {
if (baseFont == null) { if (baseFont == null) {
@@ -266,15 +249,14 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Loads a syntax highlighting color scheme from a string created from * Loads a syntax highlighting color scheme from a string created from
* <code>toCommaSeparatedString</code>. This method is useful for saving * <code>toCommaSeparatedString</code>. This method is useful for saving and
* and restoring color schemes. * restoring color schemes.
* <p> * <p>
* *
* Consider using the {@link Theme} class for saving and loading RSTA * Consider using the {@link Theme} class for saving and loading RSTA styles
* styles rather than using this API. * rather than using this API.
* *
* @param string * @param string A string generated from {@link #toCommaSeparatedString()}.
* A string generated from {@link #toCommaSeparatedString()}.
* @return A color scheme. * @return A color scheme.
* @see #toCommaSeparatedString() * @see #toCommaSeparatedString()
*/ */
@@ -284,21 +266,20 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Loads a syntax highlighting color scheme from a string created from * Loads a syntax highlighting color scheme from a string created from
* <code>toCommaSeparatedString</code>. This method is useful for saving * <code>toCommaSeparatedString</code>. This method is useful for saving and
* and restoring color schemes. * restoring color schemes.
* <p> * <p>
* *
* Consider using the {@link Theme} class for saving and loading RSTA * Consider using the {@link Theme} class for saving and loading RSTA styles
* styles rather than using this API. * rather than using this API.
* *
* @param string * @param string A string generated from
* A string generated from {@link #toCommaSeparatedString()}. * {@link #toCommaSeparatedString()}.
* @param tokenTypeCount * @param tokenTypeCount The number of token types saved in this string. This
* The number of token types saved in this string. * should be the number of token types saved by your
* This should be the number of token types saved by your custom * custom SyntaxScheme subclass, or
* SyntaxScheme subclass, * {@link TokenTypes#DEFAULT_NUM_TOKEN_TYPES} if you used
* or {@link TokenTypes#DEFAULT_NUM_TOKEN_TYPES} if you used the * the standard implementation (which most people will).
* standard implementation (which most people will).
* @return A color scheme. * @return A color scheme.
* @see #loadFromString(String) * @see #loadFromString(String)
* @see #toCommaSeparatedString() * @see #toCommaSeparatedString()
@@ -314,7 +295,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
int tokenCount = tokenTypeCount * 7 + 1; // Version string int tokenCount = tokenTypeCount * 7 + 1; // Version string
if (tokens.length != tokenCount) { if (tokens.length != tokenCount) {
throw new Exception("Not enough tokens in packed color scheme: expected " + tokenCount + ", found " + tokens.length); 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 // Use StyleContext to create fonts to get composite fonts for
// Asian glyphs. // Asian glyphs.
@@ -373,10 +355,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Restores all colors and fonts to their default values. * Restores all colors and fonts to their default values.
* *
* @param baseFont * @param baseFont The base font to use when creating this scheme. If this is
* The base font to use when creating this scheme. If * <code>null</code>, then a default monospaced font is used.
* this is <code>null</code>, then a default monospaced font is
* used.
*/ */
public void restoreDefaults(Font baseFont) { public void restoreDefaults(Font baseFont) {
restoreDefaults(baseFont, true); restoreDefaults(baseFont, true);
@@ -385,13 +365,10 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Restores all colors and fonts to their default values. * Restores all colors and fonts to their default values.
* *
* @param baseFont * @param baseFont The base font to use when creating this scheme. If this is
* The base font to use when creating this scheme. If * <code>null</code>, then a default monospaced font is used.
* this is <code>null</code>, then a default monospaced font is * @param fontStyles Whether bold and italic should be used in the scheme (vs.
* used. * all tokens using a plain font).
* @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) { public void restoreDefaults(Font baseFont, boolean fontStyles) {
// Colors used by tokens. // Colors used by tokens.
@@ -473,10 +450,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
/** /**
* Sets a style to use when rendering a token type. * Sets a style to use when rendering a token type.
* *
* @param type * @param type The token type.
* The token type. * @param style The style for the token type.
* @param style
* The style for the token type.
* @see #getStyle(int) * @see #getStyle(int)
*/ */
public void setStyle(int type, Style style) { public void setStyle(int type, Style style) {
@@ -484,14 +459,12 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
/** /**
* Used by third party implementors e.g. SquirreL SQL. Most applications do * Used by third party implementors e.g. SquirreL SQL. Most applications do not
* not need to call this method; individual styles can be set via * need to call this method; individual styles can be set via
* {@link #setStyle(int, Style)}. * {@link #setStyle(int, Style)}.
* *
* @param styles * @param styles The new array of styles to use. Note that this should have
* The new array of styles to use. Note that this should * length of at least {@link TokenTypes#DEFAULT_NUM_TOKEN_TYPES}.
* have length of at least
* {@link TokenTypes#DEFAULT_NUM_TOKEN_TYPES}.
* @see #setStyle(int, Style) * @see #setStyle(int, Style)
* @see #getStyles() * @see #getStyles()
*/ */
@@ -500,9 +473,9 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
/** /**
* Returns the color represented by a string. If the first char in the * Returns the color represented by a string. If the first char in the string is
* string is '<code>$</code>', it is assumed to be in hex, otherwise it is * '<code>$</code>', it is assumed to be in hex, otherwise it is assumed to be
* assumed to be decimal. So, for example, both of these: * decimal. So, for example, both of these:
* *
* <pre> * <pre>
* "$00ff00" * "$00ff00"
@@ -511,8 +484,7 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
* *
* will return <code>new Color(0, 255, 0)</code>. * will return <code>new Color(0, 255, 0)</code>.
* *
* @param s * @param s The string to evaluate.
* The string to evaluate.
* @return The color. * @return The color.
*/ */
private static Color stringToColor(String s) { private static Color stringToColor(String s) {
@@ -523,26 +495,24 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
} }
/** /**
* Returns this syntax highlighting scheme as a comma-separated list of * Returns this syntax highlighting scheme as a comma-separated list of values
* values as follows: * as follows:
* <ul> * <ul>
* <li>If a color is non-null, it is added as a 24-bit integer * <li>If a color is non-null, it is added as a 24-bit integer of the form
* of the form <code>((r&lt;*lt;16) | (g&lt;*lt;8) | (b))</code>; if * <code>((r&lt;*lt;16) | (g&lt;*lt;8) | (b))</code>; if it is
* it is <code>null</code>, it is added as "<i>-,</i>". * <code>null</code>, it is added as "<i>-,</i>".
* <li>The font and style (bold/italic) is added as an integer like so: * <li>The font and style (bold/italic) is added as an integer like so:
* "<i>family,</i> <i>style,</i> <i>size</i>". * "<i>family,</i> <i>style,</i> <i>size</i>".
* <li>The entire syntax highlighting scheme is thus one long string of * <li>The entire syntax highlighting scheme is thus one long string of color
* color schemes of the format "<i>i,[fg],[bg],uline,[style]</i>, * schemes of the format "<i>i,[fg],[bg],uline,[style]</i>, where:
* where:
* <ul> * <ul>
* <li><code>i</code> is the index of the syntax scheme. * <li><code>i</code> is the index of the syntax scheme.
* <li><i>fg</i> and <i>bg</i> are the foreground and background * <li><i>fg</i> and <i>bg</i> are the foreground and background colors for the
* colors for the scheme, and may be null (represented by * scheme, and may be null (represented by <code>-</code>).
* <code>-</code>). * <li><code>uline</code> is whether or not the font should be underlined, and
* <li><code>uline</code> is whether or not the font should be * is either <code>t</code> or <code>f</code>.
* underlined, and is either <code>t</code> or <code>f</code>. * <li><code>style</code> is the <code>family,style,size</code> triplet
* <li><code>style</code> is the <code>family,style,size</code> * described above.
* triplet described above.
* </ul> * </ul>
* </ul> * </ul>
* *
@@ -566,7 +536,8 @@ public class SyntaxScheme implements Cloneable, TokenTypes {
sb.append(ss.underline ? "t," : "f,"); sb.append(ss.underline ? "t," : "f,");
Font font = ss.font; Font font = ss.font;
if (font != null) { if (font != null) {
sb.append(font.getFamily()).append(',').append(font.getStyle()).append(',').append(font.getSize()).append(','); sb.append(font.getFamily()).append(',').append(font.getStyle()).append(',').append(font.getSize())
.append(',');
} else { } else {
sb.append("-,,,"); sb.append("-,,,");
} }
+35 -52
View File
@@ -62,15 +62,14 @@ import org.xml.sax.helpers.DefaultHandler;
* for various tasks. * for various tasks.
* <p> * <p>
* *
* Note that to save a <code>Theme</code> via {@link #save(OutputStream)}, * Note that to save a <code>Theme</code> via {@link #save(OutputStream)}, you
* you must currently create a <code>Theme</code> from a text area wrapped in * must currently create a <code>Theme</code> from a text area wrapped in an
* an <code>RTextScrollPane</code>, so that the color information for the * <code>RTextScrollPane</code>, so that the color information for the gutter
* gutter can be retrieved. * can be retrieved.
* *
* @author Robert Futrell * @author Robert Futrell
* @version 1.0 * @version 1.0
*/ */
@SuppressWarnings({ "checkstyle:visibilitymodifier" })
public class Theme { public class Theme {
public Font baseFont; public Font baseFont;
@@ -107,10 +106,9 @@ public class Theme {
/** /**
* Private constructor, used when loading from a stream. * Private constructor, used when loading from a stream.
* *
* @param baseFont * @param baseFont The default font to use for any "base font" properties not
* The default font to use for any "base font" properties * specified in the theme XML. If this is <code>null</code>, a
* not specified in the theme XML. If this is <code>null</code>, * default monospaced font will be used.
* a default monospaced font will be used.
*/ */
private Theme(Font baseFont) { private Theme(Font baseFont) {
// Optional fields that require a default value. // Optional fields that require a default value.
@@ -120,11 +118,10 @@ public class Theme {
} }
/** /**
* Creates a theme from an RSyntaxTextArea. It should be contained in * Creates a theme from an RSyntaxTextArea. It should be contained in an
* an <code>RTextScrollPane</code> to get all gutter color information. * <code>RTextScrollPane</code> to get all gutter color information.
* *
* @param textArea * @param textArea The text area.
* The text area.
*/ */
public Theme(RSyntaxTextArea textArea) { public Theme(RSyntaxTextArea textArea) {
baseFont = textArea.getFont(); baseFont = textArea.getFont();
@@ -169,8 +166,7 @@ public class Theme {
/** /**
* Applies this theme to a text area. * Applies this theme to a text area.
* *
* @param textArea * @param textArea The text area to apply this theme to.
* The text area to apply this theme to.
*/ */
public void apply(RSyntaxTextArea textArea) { public void apply(RSyntaxTextArea textArea) {
textArea.setFont(baseFont); textArea.setFont(baseFont);
@@ -266,8 +262,8 @@ public class Theme {
} }
/** /**
* Returns the default "selected text" color to use if "default" is * Returns the default "selected text" color to use if "default" is specified in
* specified in a theme. * a theme.
* *
* @return The default selection foreground color to use. * @return The default selection foreground color to use.
* @see #getDefaultSelectionBG() * @see #getDefaultSelectionBG()
@@ -289,12 +285,9 @@ public class Theme {
/** /**
* Returns the specified font. * Returns the specified font.
* *
* @param family * @param family The font family.
* The font family. * @param style The style of font.
* @param style * @param size The size of the font.
* The style of font.
* @param size
* The size of the font.
* @return The font. * @return The font.
*/ */
private static Font getFont(String family, int style, int size) { private static Font getFont(String family, int style, int size) {
@@ -306,12 +299,10 @@ public class Theme {
/** /**
* Loads a theme. * Loads a theme.
* *
* @param in * @param in The input stream to read from. This will be closed when this method
* The input stream to read from. This will be closed when this * returns.
* method returns.
* @return The theme. * @return The theme.
* @throws IOException * @throws IOException If an IO error occurs.
* If an IO error occurs.
* @see #save(OutputStream) * @see #save(OutputStream)
*/ */
public static Theme load(InputStream in) throws IOException { public static Theme load(InputStream in) throws IOException {
@@ -321,16 +312,13 @@ public class Theme {
/** /**
* Loads a theme. * Loads a theme.
* *
* @param in * @param in The input stream to read from. This will be closed when this
* The input stream to read from. This will be closed when this
* method returns. * method returns.
* @param baseFont * @param baseFont The default font to use for any "base font" properties not
* The default font to use for any "base font" properties * specified in the theme XML. If this is <code>null</code>, a
* not specified in the theme XML. If this is <code>null</code>, * default monospaced font will be used.
* a default monospaced font will be used.
* @return The theme. * @return The theme.
* @throws IOException * @throws IOException If an IO error occurs.
* If an IO error occurs.
* @see #save(OutputStream) * @see #save(OutputStream)
*/ */
public static Theme load(InputStream in, Font baseFont) throws IOException { public static Theme load(InputStream in, Font baseFont) throws IOException {
@@ -347,10 +335,8 @@ public class Theme {
/** /**
* Saves this theme to an output stream. * Saves this theme to an output stream.
* *
* @param out * @param out The output stream to write to.
* The output stream to write to. * @throws IOException If an IO error occurs.
* @throws IOException
* If an IO error occurs.
* @see #load(InputStream) * @see #load(InputStream)
*/ */
public void save(OutputStream out) throws IOException { public void save(OutputStream out) throws IOException {
@@ -497,9 +483,9 @@ public class Theme {
} }
/** /**
* Returns the color represented by a string. The input is expected to * Returns the color represented by a string. The input is expected to be a
* be a 6-digit hex string, optionally prefixed by a '$'. For example, * 6-digit hex string, optionally prefixed by a '$'. For example, either of the
* either of the following: * following:
* *
* <pre> * <pre>
* "$00ff00" * "$00ff00"
@@ -508,8 +494,7 @@ public class Theme {
* *
* will return <code>new Color(0, 255, 0)</code>. * will return <code>new Color(0, 255, 0)</code>.
* *
* @param s * @param s The string to evaluate.
* The string to evaluate.
* @return The color. * @return The color.
*/ */
private static Color stringToColor(String s) { private static Color stringToColor(String s) {
@@ -517,9 +502,9 @@ public class Theme {
} }
/** /**
* Returns the color represented by a string. The input is expected to * Returns the color represented by a string. The input is expected to be a
* be a 6-digit hex string, optionally prefixed by a '$'. For example, * 6-digit hex string, optionally prefixed by a '$'. For example, either of the
* either of the following: * following:
* *
* <pre> * <pre>
* "$00ff00" * "$00ff00"
@@ -528,10 +513,8 @@ public class Theme {
* *
* will return <code>new Color(0, 255, 0)</code>. * will return <code>new Color(0, 255, 0)</code>.
* *
* @param s * @param s The string to evaluate.
* The string to evaluate. * @param defaultVal The color to use if <code>s</code> is
* @param defaultVal
* The color to use if <code>s</code> is
* "<code>default</code>". * "<code>default</code>".
* @return The color. * @return The color.
*/ */
+83 -113
View File
@@ -22,19 +22,18 @@ import javax.swing.text.Utilities;
* <b>Note:</b> The instances of <code>Token</code> returned by * <b>Note:</b> The instances of <code>Token</code> returned by
* {@link RSyntaxDocument}s are pooled and should always be treated as * {@link RSyntaxDocument}s are pooled and should always be treated as
* immutable. They should not be cast to <code>TokenImpl</code> and modified. * immutable. They should not be cast to <code>TokenImpl</code> and modified.
* Modifying tokens you did not create yourself can and will result in * Modifying tokens you did not create yourself can and will result in rendering
* rendering issues and/or runtime exceptions. You have been warned! * issues and/or runtime exceptions. You have been warned!
* *
* @author Robert Futrell * @author Robert Futrell
* @version 0.3 * @version 0.3
*/ */
@SuppressWarnings({ "checkstyle:visibilitymodifier" })
public class TokenImpl implements Token { public class TokenImpl implements Token {
/** /**
* The text this token represents. This is implemented as a segment so we * The text this token represents. This is implemented as a segment so we can
* can point directly to the text in the document without having to make a * point directly to the text in the document without having to make a copy of
* copy of it. * it.
*/ */
public char[] text; public char[] text;
public int textOffset; public int textOffset;
@@ -61,9 +60,9 @@ public class TokenImpl implements Token {
private int languageIndex; private int languageIndex;
/** /**
* Creates a "null" token. The token itself is not null; rather, it * Creates a "null" token. The token itself is not null; rather, it signifies
* signifies that it is the last token in a linked list of tokens and * that it is the last token in a linked list of tokens and that it is not part
* that it is not part of a "multi-line token." * of a "multi-line token."
*/ */
public TokenImpl() { public TokenImpl() {
this.text = null; this.text = null;
@@ -78,19 +77,12 @@ public class TokenImpl implements Token {
/** /**
* Constructor. * Constructor.
* *
* @param line * @param line The segment from which to get the token.
* The segment from which to get the token. * @param beg The first character's position in <code>line</code>.
* @param beg * @param end The last character's position in <code>line</code>.
* The first character's position in <code>line</code>. * @param startOffset The offset into the document at which this token begins.
* @param end * @param type A token type listed as "generic" above.
* The last character's position in <code>line</code>. * @param languageIndex The language index for this token.
* @param startOffset
* The offset into the document at which this
* token begins.
* @param type
* A token type listed as "generic" above.
* @param languageIndex
* The language index for this token.
*/ */
public TokenImpl(Segment line, int beg, int end, int startOffset, int type, int languageIndex) { public TokenImpl(Segment line, int beg, int end, int startOffset, int type, int languageIndex) {
this(line.array, beg, end, startOffset, type, languageIndex); this(line.array, beg, end, startOffset, type, languageIndex);
@@ -99,19 +91,12 @@ public class TokenImpl implements Token {
/** /**
* Constructor. * Constructor.
* *
* @param line * @param line The segment from which to get the token.
* The segment from which to get the token. * @param beg The first character's position in <code>line</code>.
* @param beg * @param end The last character's position in <code>line</code>.
* The first character's position in <code>line</code>. * @param startOffset The offset into the document at which this token begins.
* @param end * @param type A token type listed as "generic" above.
* The last character's position in <code>line</code>. * @param languageIndex The language index for this token.
* @param startOffset
* The offset into the document at which this
* token begins.
* @param type
* A token type listed as "generic" above.
* @param languageIndex
* The language index for this token.
*/ */
public TokenImpl(char[] line, int beg, int end, int startOffset, int type, int languageIndex) { public TokenImpl(char[] line, int beg, int end, int startOffset, int type, int languageIndex) {
this(); this();
@@ -122,8 +107,7 @@ public class TokenImpl implements Token {
/** /**
* Creates this token as a copy of the passed-in token. * Creates this token as a copy of the passed-in token.
* *
* @param t2 * @param t2 The token from which to make a copy.
* The token from which to make a copy.
*/ */
public TokenImpl(Token t2) { public TokenImpl(Token t2) {
this(); this();
@@ -136,7 +120,8 @@ public class TokenImpl implements Token {
} }
@Override @Override
public StringBuilder appendHTMLRepresentation(StringBuilder sb, RSyntaxTextArea textArea, boolean fontFamily, boolean tabsToSpaces) { public StringBuilder appendHTMLRepresentation(StringBuilder sb, RSyntaxTextArea textArea, boolean fontFamily,
boolean tabsToSpaces) {
SyntaxScheme colorScheme = textArea.getSyntaxScheme(); SyntaxScheme colorScheme = textArea.getSyntaxScheme();
Style scheme = colorScheme.getStyle(getType()); Style scheme = colorScheme.getStyle(getType());
Font font = textArea.getFontForTokenType(getType());// scheme.font; Font font = textArea.getFontForTokenType(getType());// scheme.font;
@@ -179,16 +164,13 @@ public class TokenImpl implements Token {
} }
/** /**
* Appends an HTML version of the lexeme of this token (i.e. no style * Appends an HTML version of the lexeme of this token (i.e. no style HTML, but
* HTML, but replacing chars such as <code>\t</code>, <code>&lt;</code> * replacing chars such as <code>\t</code>, <code>&lt;</code> and
* and <code>&gt;</code> with their escapes). * <code>&gt;</code> with their escapes).
* *
* @param textArea * @param textArea The text area.
* The text area. * @param sb The buffer to append to.
* @param sb * @param tabsToSpaces Whether to convert tabs into spaces.
* The buffer to append to.
* @param tabsToSpaces
* Whether to convert tabs into spaces.
* @return The same buffer. * @return The same buffer.
*/ */
private StringBuilder appendHtmlLexeme(RSyntaxTextArea textArea, StringBuilder sb, boolean tabsToSpaces) { private StringBuilder appendHtmlLexeme(RSyntaxTextArea textArea, StringBuilder sb, boolean tabsToSpaces) {
@@ -277,11 +259,10 @@ public class TokenImpl implements Token {
} }
/** /**
* Makes one token point to the same text segment, and have the same value * Makes one token point to the same text segment, and have the same value as
* as another token. * another token.
* *
* @param t2 * @param t2 The token from which to copy.
* The token from which to copy.
*/ */
public void copyFrom(Token t2) { public void copyFrom(Token t2) {
text = t2.getTextArray(); text = t2.getTextArray();
@@ -322,8 +303,9 @@ public class TokenImpl implements Token {
return false; return false;
} }
Token t2 = (Token) obj; Token t2 = (Token) obj;
return offset == t2.getOffset() && type == t2.getType() && languageIndex == t2.getLanguageIndex() && hyperlink == t2.isHyperlink() return offset == t2.getOffset() && type == t2.getType() && languageIndex == t2.getLanguageIndex()
&& ((getLexeme() == null && t2.getLexeme() == null) || (getLexeme() != null && getLexeme().equals(t2.getLexeme()))); && hyperlink == t2.isHyperlink() && ((getLexeme() == null && t2.getLexeme() == null)
|| (getLexeme() != null && getLexeme().equals(t2.getLexeme())));
} }
@Override @Override
@@ -332,11 +314,10 @@ public class TokenImpl implements Token {
} }
/** /**
* Returns a <code>String</code> of the form "#xxxxxx" good for use * Returns a <code>String</code> of the form "#xxxxxx" good for use in HTML,
* in HTML, representing the given color. * representing the given color.
* *
* @param color * @param color The color to get a string for.
* The color to get a string for.
* @return The HTML form of the color. If <code>color</code> is * @return The HTML form of the color. If <code>color</code> is
* <code>null</code>, <code>#000000</code> is returned. * <code>null</code>, <code>#000000</code> is returned.
*/ */
@@ -683,23 +664,22 @@ public class TokenImpl implements Token {
* Makes this token start at the specified offset into the document. * Makes this token start at the specified offset into the document.
* <p> * <p>
* *
* <b>Note:</b> You should not modify <code>Token</code> instances you * <b>Note:</b> You should not modify <code>Token</code> instances you did not
* did not create yourself (e.g., came from an * create yourself (e.g., came from an <code>RSyntaxDocument</code>). If you do,
* <code>RSyntaxDocument</code>). If you do, rendering issues and/or * rendering issues and/or runtime exceptions will likely occur. You have been
* runtime exceptions will likely occur. You have been warned! * warned!
* *
* @param pos * @param pos The offset into the document this token should start at. Note that
* The offset into the document this token should start at. * this token must already contain this position; if it doesn't, an
* Note that this token must already contain this position; if * exception is thrown.
* it doesn't, an exception is thrown. * @throws IllegalArgumentException If pos is not already contained by this
* @throws IllegalArgumentException * token.
* If pos is not already contained by
* this token.
* @see #moveOffset(int) * @see #moveOffset(int)
*/ */
public void makeStartAt(int pos) { public void makeStartAt(int pos) {
if (pos < getOffset() || pos >= (getOffset() + textCount)) { if (pos < getOffset() || pos >= (getOffset() + textCount)) {
throw new IllegalArgumentException("pos " + pos + " is not in range " + getOffset() + "-" + (getOffset() + textCount - 1)); throw new IllegalArgumentException(
"pos " + pos + " is not in range " + getOffset() + "-" + (getOffset() + textCount - 1));
} }
int shift = pos - getOffset(); int shift = pos - getOffset();
setOffset(pos); setOffset(pos);
@@ -711,16 +691,14 @@ public class TokenImpl implements Token {
* Moves the starting offset of this token. * Moves the starting offset of this token.
* <p> * <p>
* *
* <b>Note:</b> You should not modify <code>Token</code> instances you * <b>Note:</b> You should not modify <code>Token</code> instances you did not
* did not create yourself (e.g., came from an * create yourself (e.g., came from an <code>RSyntaxDocument</code>). If you do,
* <code>RSyntaxDocument</code>). If you do, rendering issues and/or * rendering issues and/or runtime exceptions will likely occur. You have been
* runtime exceptions will likely occur. You have been warned! * warned!
* *
* @param amt * @param amt The amount to move the starting offset. This should be between
* The amount to move the starting offset. This should be * <code>0</code> and <code>textCount</code>, inclusive.
* between <code>0</code> and <code>textCount</code>, inclusive. * @throws IllegalArgumentException If <code>amt</code> is an invalid value.
* @throws IllegalArgumentException
* If <code>amt</code> is an invalid value.
* @see #makeStartAt(int) * @see #makeStartAt(int)
*/ */
public void moveOffset(int amt) { public void moveOffset(int amt) {
@@ -733,19 +711,14 @@ public class TokenImpl implements Token {
} }
/** /**
* Sets the value of this token to a particular segment of a document. * Sets the value of this token to a particular segment of a document. The "next
* The "next token" value is cleared. * token" value is cleared.
* *
* @param line * @param line The segment from which to get the token.
* The segment from which to get the token. * @param beg The first character's position in <code>line</code>.
* @param beg * @param end The last character's position in <code>line</code>.
* The first character's position in <code>line</code>. * @param offset The offset into the document at which this token begins.
* @param end * @param type A token type listed as "generic" above.
* The last character's position in <code>line</code>.
* @param offset
* The offset into the document at which this token begins.
* @param type
* A token type listed as "generic" above.
*/ */
public void set(final char[] line, final int beg, final int end, final int offset, final int type) { public void set(final char[] line, final int beg, final int end, final int offset, final int type) {
this.text = line; this.text = line;
@@ -759,8 +732,7 @@ public class TokenImpl implements Token {
/** /**
* Sets whether this token is a hyperlink. * Sets whether this token is a hyperlink.
* *
* @param hyperlink * @param hyperlink Whether this token is a hyperlink.
* Whether this token is a hyperlink.
* @see #isHyperlink() * @see #isHyperlink()
*/ */
@Override @Override
@@ -769,17 +741,16 @@ public class TokenImpl implements Token {
} }
/** /**
* Sets the language index for this token. If this value is positive, it * Sets the language index for this token. If this value is positive, it denotes
* denotes a specific "secondary" language this token represents (such as * a specific "secondary" language this token represents (such as JavaScript
* JavaScript code or CSS embedded in an HTML file). If this value is * code or CSS embedded in an HTML file). If this value is <code>0</code>, this
* <code>0</code>, this token is in the "main" language being edited. * token is in the "main" language being edited. Negative values are invalid and
* Negative values are invalid and treated as <code>0</code>. * treated as <code>0</code>.
* *
* @param languageIndex * @param languageIndex The new language index. A value of <code>0</code>
* The new language index. A value of * denotes the "main" language, any positive value denotes
* <code>0</code> denotes the "main" language, any positive value * a specific secondary language. Negative values will be
* denotes a specific secondary language. Negative values will * treated as <code>0</code>.
* be treated as <code>0</code>.
* @see #getLanguageIndex() * @see #getLanguageIndex()
*/ */
@Override @Override
@@ -788,11 +759,9 @@ public class TokenImpl implements Token {
} }
/** /**
* Sets the "next token" pointer of this token to point to the specified * Sets the "next token" pointer of this token to point to the specified token.
* token.
* *
* @param nextToken * @param nextToken The new next token.
* The new next token.
* @see #getNextToken() * @see #getNextToken()
*/ */
public void setNextToken(Token nextToken) { public void setNextToken(Token nextToken) {
@@ -802,8 +771,7 @@ public class TokenImpl implements Token {
/** /**
* Sets the offset into the document at which this token resides. * Sets the offset into the document at which this token resides.
* *
* @param offset * @param offset The new offset into the document.
* The new offset into the document.
* @see #getOffset() * @see #getOffset()
*/ */
public void setOffset(int offset) { public void setOffset(int offset) {
@@ -843,16 +811,18 @@ public class TokenImpl implements Token {
} }
/** /**
* Returns this token as a <code>String</code>, which is useful for * Returns this token as a <code>String</code>, which is useful for debugging.
* debugging.
* *
* @return A string describing this token. * @return A string describing this token.
*/ */
@Override @Override
public String toString() { public String toString() {
return "[Token: " + (getType() == Token.NULL ? "<null token>" return "[Token: "
: "text: '" + (text == null ? "<null>" : getLexeme() + "'; " + "offset: " + getOffset() + "; type: " + getType() + "; " + (getType() == Token.NULL ? "<null token>"
+ "isPaintable: " + isPaintable() + "; nextToken==null: " + (nextToken == null))) : "text: '" + (text == null ? "<null>"
: getLexeme() + "'; " + "offset: " + getOffset() + "; type: " + getType() + "; "
+ "isPaintable: " + isPaintable() + "; nextToken==null: "
+ (nextToken == null)))
+ "]"; + "]";
} }
} }
+49 -59
View File
@@ -10,11 +10,12 @@ import javax.swing.text.TabExpander;
*/ */
public final class TokenUtils { public final class TokenUtils {
private TokenUtils() {} private TokenUtils() {
}
/** /**
* Modifies the passed-in token list to start at the specified offset. * Modifies the passed-in token list to start at the specified offset. For
* For example, if the token list covered positions 20-60 in the document * example, if the token list covered positions 20-60 in the document
* (inclusive) like so: * (inclusive) like so:
* *
* <pre> * <pre>
@@ -22,50 +23,46 @@ public final class TokenUtils {
* 20 30 31 40 41 50 51 60 * 20 30 31 40 41 50 51 60
* </pre> * </pre>
* *
* and you used this method to make the token list start at position 44, * and you used this method to make the token list start at position 44, then
* then the token list would be modified to be the following: * the token list would be modified to be the following:
* *
* <pre> * <pre>
* [part-of-old-token3] -&gt; [token4] * [part-of-old-token3] -&gt; [token4]
* 44 50 51 60 * 44 50 51 60
* </pre> * </pre>
* *
* Tokens that come before the specified position are forever lost, and * Tokens that come before the specified position are forever lost, and the
* the token containing that position is made to begin at that position if * token containing that position is made to begin at that position if
* necessary. All token types remain the same as they were originally. * necessary. All token types remain the same as they were originally.
* <p> * <p>
* *
* This method can be useful if you are only interested in part of a token * This method can be useful if you are only interested in part of a token list
* list (i.e., the line it represents), but you don't want to modify the * (i.e., the line it represents), but you don't want to modify the token list
* token list yourself. * yourself.
* *
* @param tokenList * @param tokenList The list to make start at the specified position. This
* The list to make start at the specified position. * parameter is modified.
* This parameter is modified. * @param pos The position at which the new token list is to start. If
* @param pos * this position is not in the passed-in token list, returned
* The position at which the new token list is to start. If * token list will either be <code>null</code> or the
* this position is not in the passed-in token list,
* returned token list will either be <code>null</code> or the
* unpaintable token(s) at the end of the passed-in token list. * unpaintable token(s) at the end of the passed-in token list.
* @param e * @param e How to expand tabs.
* How to expand tabs. * @param textArea The text area from which the token list came.
* @param textArea * @param x0 The initial x-pixel position of the old token list.
* The text area from which the token list came.
* @param x0
* The initial x-pixel position of the old token list.
* @return Information about the "sub" token list. This will be * @return Information about the "sub" token list. This will be
* <code>null</code> if <code>pos</code> was not a valid offset * <code>null</code> if <code>pos</code> was not a valid offset into the
* into the token list. * token list.
* @see #getSubTokenList(Token, int, TabExpander, RSyntaxTextArea, float, * @see #getSubTokenList(Token, int, TabExpander, RSyntaxTextArea, float,
* TokenImpl) * TokenImpl)
*/ */
public static TokenSubList getSubTokenList(Token tokenList, int pos, TabExpander e, final RSyntaxTextArea textArea, float x0) { public static TokenSubList getSubTokenList(Token tokenList, int pos, TabExpander e, final RSyntaxTextArea textArea,
float x0) {
return getSubTokenList(tokenList, pos, e, textArea, x0, null); return getSubTokenList(tokenList, pos, e, textArea, x0, null);
} }
/** /**
* Modifies the passed-in token list to start at the specified offset. * Modifies the passed-in token list to start at the specified offset. For
* For example, if the token list covered positions 20-60 in the document * example, if the token list covered positions 20-60 in the document
* (inclusive) like so: * (inclusive) like so:
* *
* <pre> * <pre>
@@ -73,48 +70,42 @@ public final class TokenUtils {
* 20 30 31 40 41 50 51 60 * 20 30 31 40 41 50 51 60
* </pre> * </pre>
* *
* and you used this method to make the token list start at position 44, * and you used this method to make the token list start at position 44, then
* then the token list would be modified to be the following: * the token list would be modified to be the following:
* *
* <pre> * <pre>
* [part-of-old-token3] -&gt; [token4] * [part-of-old-token3] -&gt; [token4]
* 44 50 51 60 * 44 50 51 60
* </pre> * </pre>
* *
* Tokens that come before the specified position are forever lost, and * Tokens that come before the specified position are forever lost, and the
* the token containing that position is made to begin at that position if * token containing that position is made to begin at that position if
* necessary. All token types remain the same as they were originally. * necessary. All token types remain the same as they were originally.
* <p> * <p>
* *
* This method can be useful if you are only interested in part of a token * This method can be useful if you are only interested in part of a token list
* list (i.e., the line it represents), but you don't want to modify the * (i.e., the line it represents), but you don't want to modify the token list
* token list yourself. * yourself.
* *
* @param tokenList * @param tokenList The list to make start at the specified position. This
* The list to make start at the specified position. * parameter is modified.
* This parameter is modified. * @param pos The position at which the new token list is to start. If
* @param pos * this position is not in the passed-in token list, returned
* The position at which the new token list is to start. If * token list will either be <code>null</code> or the
* this position is not in the passed-in token list,
* returned token list will either be <code>null</code> or the
* unpaintable token(s) at the end of the passed-in token list. * unpaintable token(s) at the end of the passed-in token list.
* @param e * @param e How to expand tabs.
* How to expand tabs. * @param textArea The text area from which the token list came.
* @param textArea * @param x0 The initial x-pixel position of the old token list.
* The text area from which the token list came. * @param tempToken A temporary token to use when creating the token list
* @param x0 * result. This may be <code>null</code> but callers can pass
* The initial x-pixel position of the old token list. * in a "buffer" token for performance if desired.
* @param tempToken
* A temporary token to use when creating the token list
* result. This may be <code>null</code> but callers can pass in
* a "buffer" token for performance if desired.
* @return Information about the "sub" token list. This will be * @return Information about the "sub" token list. This will be
* <code>null</code> if <code>pos</code> was not a valid offset * <code>null</code> if <code>pos</code> was not a valid offset into the
* into the token list. * token list.
* @see #getSubTokenList(Token, int, TabExpander, RSyntaxTextArea, float) * @see #getSubTokenList(Token, int, TabExpander, RSyntaxTextArea, float)
*/ */
public static TokenSubList getSubTokenList(Token tokenList, int pos, TabExpander e, final RSyntaxTextArea textArea, float x0, public static TokenSubList getSubTokenList(Token tokenList, int pos, TabExpander e, final RSyntaxTextArea textArea,
TokenImpl tempToken) { float x0, TokenImpl tempToken) {
if (tempToken == null) { if (tempToken == null) {
tempToken = new TokenImpl(); tempToken = new TokenImpl();
} }
@@ -146,7 +137,6 @@ public final class TokenUtils {
/** /**
* A sub-list of tokens. * A sub-list of tokens.
*/ */
@SuppressWarnings({ "checkstyle:visibilitymodifier" })
public static class TokenSubList { public static class TokenSubList {
/** /**
@@ -154,8 +144,8 @@ public final class TokenUtils {
*/ */
public Token tokenList; public Token tokenList;
/** /**
* The width, in pixels, of the part of the token list "removed from * The width, in pixels, of the part of the token list "removed from the front."
* the front." This way, you know the x-offset of the "new" token list. * This way, you know the x-offset of the "new" token list.
*/ */
public float x; public float x;
@@ -34,7 +34,6 @@ import javax.swing.event.MouseInputAdapter;
* @author Robert Futrell * @author Robert Futrell
* @version 1.0 * @version 1.0
*/ */
@SuppressWarnings({ "checkstyle:magicnumber" })
class SizeGrip extends JPanel { class SizeGrip extends JPanel {
/** /**
@@ -50,11 +49,10 @@ class SizeGrip extends JPanel {
} }
/** /**
* Overridden to ensure that the cursor for this component is appropriate * Overridden to ensure that the cursor for this component is appropriate for
* for the orientation. * the orientation.
* *
* @param o * @param o The new orientation.
* The new orientation.
*/ */
@Override @Override
public void applyComponentOrientation(ComponentOrientation o) { public void applyComponentOrientation(ComponentOrientation o) {
@@ -97,8 +95,7 @@ class SizeGrip extends JPanel {
/** /**
* Paints this panel. * Paints this panel.
* *
* @param g * @param g The graphics context.
* The graphics context.
*/ */
@Override @Override
protected void paintComponent(Graphics g) { protected void paintComponent(Graphics g) {
@@ -151,8 +148,7 @@ class SizeGrip extends JPanel {
* Ensures that the cursor for this component is appropriate for the * Ensures that the cursor for this component is appropriate for the
* orientation. * orientation.
* *
* @param ltr * @param ltr Whether the current component orientation is LTR.
* Whether the current component orientation is LTR.
*/ */
protected void possiblyFixCursor(boolean ltr) { protected void possiblyFixCursor(boolean ltr) {
int cursor = Cursor.NE_RESIZE_CURSOR; int cursor = Cursor.NE_RESIZE_CURSOR;
@@ -185,12 +181,10 @@ class SizeGrip extends JPanel {
private class MouseHandler extends MouseInputAdapter { private class MouseHandler extends MouseInputAdapter {
/* /*
* NOTE: We use SwingUtilities.convertPointToScreen() instead of just * NOTE: We use SwingUtilities.convertPointToScreen() instead of just using the
* using * locations relative to the corner component because the latter proved buggy -
* the locations relative to the corner component because the latter * stretch the window too wide and some kind of arithmetic error started
* proved * happening somewhere - our window would grow way too large.
* buggy - stretch the window too wide and some kind of arithmetic error
* started happening somewhere - our window would grow way too large.
*/ */
private Point origPos; private Point origPos;
@@ -24,19 +24,17 @@ import javax.swing.text.DefaultEditorKit;
* <li>INSERT key toggles between insert and overwrite modes. * <li>INSERT key toggles between insert and overwrite modes.
* <li>Ctrl+DELETE key deletes all text between the caret and the end of the * <li>Ctrl+DELETE key deletes all text between the caret and the end of the
* current line. * current line.
* <li>Ctrl+Shift+Up and Ctrl+Shift+Down move the current line up and * <li>Ctrl+Shift+Up and Ctrl+Shift+Down move the current line up and down,
* down, respectively. * respectively.
* <li>Ctrl+J joins lines. * <li>Ctrl+J joins lines.
* <li>Ctrl+Z is undo and Ctrl+Y is redo. * <li>Ctrl+Z is undo and Ctrl+Y is redo.
* <li>Ctrl+Up and Ctrl+Down shift the visible area of the text area up and * <li>Ctrl+Up and Ctrl+Down shift the visible area of the text area up and down
* down one line, respectively. * one line, respectively.
* <li>F2 and Shift+F2 moves to the next and previous bookmarks, * <li>F2 and Shift+F2 moves to the next and previous bookmarks, respectively.
* respectively.
* <li>Ctrl+F2 toggles whether a bookmark is on the current line. * <li>Ctrl+F2 toggles whether a bookmark is on the current line.
* <li>etc. * <li>etc.
* </ul> * </ul>
*/ */
@SuppressWarnings({ "checkstyle:linelength" })
public class RTADefaultInputMap extends InputMap { public class RTADefaultInputMap extends InputMap {
/** /**
@@ -50,12 +48,14 @@ public class RTADefaultInputMap extends InputMap {
int shift = InputEvent.SHIFT_MASK; int shift = InputEvent.SHIFT_MASK;
boolean isOSX = RTextArea.isOSX(); boolean isOSX = RTextArea.isOSX();
int moveByWordMod = isOSX ? alt : defaultModifier; int moveByWordMod = isOSX ? alt : defaultModifier;
put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), isOSX ? DefaultEditorKit.beginAction : DefaultEditorKit.beginLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
isOSX ? DefaultEditorKit.beginAction : DefaultEditorKit.beginLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, shift), put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, shift),
isOSX ? DefaultEditorKit.selectionBeginAction : DefaultEditorKit.selectionBeginLineAction); isOSX ? DefaultEditorKit.selectionBeginAction : DefaultEditorKit.selectionBeginLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, defaultModifier), DefaultEditorKit.beginAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, defaultModifier), DefaultEditorKit.beginAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, defaultModifier | shift), DefaultEditorKit.selectionBeginAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, defaultModifier | shift), DefaultEditorKit.selectionBeginAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), isOSX ? DefaultEditorKit.endAction : DefaultEditorKit.endLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
isOSX ? DefaultEditorKit.endAction : DefaultEditorKit.endLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_END, shift), put(KeyStroke.getKeyStroke(KeyEvent.VK_END, shift),
isOSX ? DefaultEditorKit.selectionEndAction : DefaultEditorKit.selectionEndLineAction); isOSX ? DefaultEditorKit.selectionEndAction : DefaultEditorKit.selectionEndLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_END, defaultModifier), DefaultEditorKit.endAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_END, defaultModifier), DefaultEditorKit.endAction);
@@ -63,7 +63,8 @@ public class RTADefaultInputMap extends InputMap {
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), DefaultEditorKit.backwardAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, shift), DefaultEditorKit.selectionBackwardAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, shift), DefaultEditorKit.selectionBackwardAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, moveByWordMod), DefaultEditorKit.previousWordAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, moveByWordMod), DefaultEditorKit.previousWordAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, moveByWordMod | shift), DefaultEditorKit.selectionPreviousWordAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, moveByWordMod | shift),
DefaultEditorKit.selectionPreviousWordAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DefaultEditorKit.downAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DefaultEditorKit.downAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, shift), DefaultEditorKit.selectionDownAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, shift), DefaultEditorKit.selectionDownAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, defaultModifier), RTextAreaEditorKit.rtaScrollDownAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, defaultModifier), RTextAreaEditorKit.rtaScrollDownAction);
@@ -78,10 +79,12 @@ public class RTADefaultInputMap extends InputMap {
put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt), RTextAreaEditorKit.rtaLineUpAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt), RTextAreaEditorKit.rtaLineUpAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), DefaultEditorKit.pageUpAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), DefaultEditorKit.pageUpAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, shift), RTextAreaEditorKit.rtaSelectionPageUpAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, shift), RTextAreaEditorKit.rtaSelectionPageUpAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, defaultModifier | shift), RTextAreaEditorKit.rtaSelectionPageLeftAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, defaultModifier | shift),
RTextAreaEditorKit.rtaSelectionPageLeftAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), DefaultEditorKit.pageDownAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), DefaultEditorKit.pageDownAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, shift), RTextAreaEditorKit.rtaSelectionPageDownAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, shift), RTextAreaEditorKit.rtaSelectionPageDownAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, defaultModifier | shift), RTextAreaEditorKit.rtaSelectionPageRightAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, defaultModifier | shift),
RTextAreaEditorKit.rtaSelectionPageRightAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_CUT, 0), DefaultEditorKit.cutAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_CUT, 0), DefaultEditorKit.cutAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_COPY, 0), DefaultEditorKit.copyAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_COPY, 0), DefaultEditorKit.copyAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_PASTE, 0), DefaultEditorKit.pasteAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_PASTE, 0), DefaultEditorKit.pasteAction);
@@ -99,7 +102,8 @@ public class RTADefaultInputMap extends InputMap {
put(KeyStroke.getKeyStroke(KeyEvent.VK_D, defaultModifier), RTextAreaEditorKit.rtaDeleteLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_D, defaultModifier), RTextAreaEditorKit.rtaDeleteLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_J, defaultModifier), RTextAreaEditorKit.rtaJoinLinesAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_J, defaultModifier), RTextAreaEditorKit.rtaJoinLinesAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, shift), DefaultEditorKit.deletePrevCharAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, shift), DefaultEditorKit.deletePrevCharAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier), RTextAreaEditorKit.rtaDeletePrevWordAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier),
RTextAreaEditorKit.rtaDeletePrevWordAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), DefaultEditorKit.insertTabAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), DefaultEditorKit.insertTabAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), DefaultEditorKit.insertBreakAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), DefaultEditorKit.insertBreakAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, shift), DefaultEditorKit.insertBreakAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, shift), DefaultEditorKit.insertBreakAction);
@@ -114,8 +118,10 @@ public class RTADefaultInputMap extends InputMap {
if (isOSX) { if (isOSX) {
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, defaultModifier), DefaultEditorKit.beginLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, defaultModifier), DefaultEditorKit.beginLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, defaultModifier), DefaultEditorKit.endLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, defaultModifier), DefaultEditorKit.endLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, defaultModifier | shift), DefaultEditorKit.selectionBeginLineAction); put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, defaultModifier | shift),
put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, defaultModifier | shift), DefaultEditorKit.selectionEndLineAction); DefaultEditorKit.selectionBeginLineAction);
put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, defaultModifier | shift),
DefaultEditorKit.selectionEndLineAction);
} }
/* NOTE: Currently, macros aren't part of the default input map for */ /* NOTE: Currently, macros aren't part of the default input map for */
/* RTextArea, as they display their own popup windows, etc. which */ /* RTextArea, as they display their own popup windows, etc. which */
@@ -134,8 +140,8 @@ public class RTADefaultInputMap extends InputMap {
} }
/** /**
* Returns the default modifier key for a system. For example, on Windows * Returns the default modifier key for a system. For example, on Windows this
* this would be the CTRL key (<code>InputEvent.CTRL_MASK</code>). * would be the CTRL key (<code>InputEvent.CTRL_MASK</code>).
* *
* @return The default modifier key. * @return The default modifier key.
*/ */
@@ -37,7 +37,6 @@ import javax.swing.text.Position;
* @author Robert Futrell * @author Robert Futrell
* @version 0.1 * @version 0.1
*/ */
@SuppressWarnings("deprecation")
public class RTATextTransferHandler extends TransferHandler { public class RTATextTransferHandler extends TransferHandler {
private JTextComponent exportComp; private JTextComponent exportComp;
@@ -47,22 +46,19 @@ public class RTATextTransferHandler extends TransferHandler {
private boolean withinSameComponent; private boolean withinSameComponent;
/** /**
* Try to find a flavor that can be used to import a Transferable to a * Try to find a flavor that can be used to import a Transferable to a specified
* specified text component. * text component. The set of usable flavors are tried in the following order:
* The set of usable flavors are tried in the following order:
* <ol> * <ol>
* <li>First, an attempt is made to find a flavor matching the content * <li>First, an attempt is made to find a flavor matching the content tyep of
* tyep of the EditorKit for the component. * the EditorKit for the component.
* <li>Second, an attempt to find a text/plain flavor is made. * <li>Second, an attempt to find a text/plain flavor is made.
* <li>Third, an attempt to find a flavor representing a String * <li>Third, an attempt to find a flavor representing a String reference in the
* reference in the same VM is made. * same VM is made.
* <li>Lastly, DataFlavor.stringFlavor is searched for. * <li>Lastly, DataFlavor.stringFlavor is searched for.
* </ol> * </ol>
* *
* @param flavors * @param flavors The flavors to check if c will accept them.
* The flavors to check if c will accept them. * @param c The text component to see whether it will accept any of the
* @param c
* The text component to see whether it will accept any of the
* specified data flavors as input. * specified data flavors as input.
*/ */
protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent c) { protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent c) {
@@ -159,14 +155,13 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* This is the type of transfer actions supported by the source. Some * This is the type of transfer actions supported by the source. Some models are
* models are not mutable, so a transfer operation of COPY only should * not mutable, so a transfer operation of COPY only should be advertised in
* be advertised in that case. * that case.
* *
* @param c * @param c The component holding the data to be transfered. This argument is
* The component holding the data to be transfered. This * provided to enable sharing of TransferHandlers by multiple
* argument is provided to enable sharing of TransferHandlers by * components.
* multiple components.
* @return If the text component is editable, COPY_OR_MOVE is returned, * @return If the text component is editable, COPY_OR_MOVE is returned,
* otherwise just COPY is allowed. * otherwise just COPY is allowed.
*/ */
@@ -182,10 +177,9 @@ public class RTATextTransferHandler extends TransferHandler {
/** /**
* Create a Transferable to use as the source for a data transfer. * Create a Transferable to use as the source for a data transfer.
* *
* @param comp * @param comp The component holding the data to be transfered. This argument is
* The component holding the data to be transfered. This * provided to enable sharing of TransferHandlers by multiple
* argument is provided to enable sharing of TransferHandlers by * components.
* multiple components.
* @return The representation of the data to be transfered. * @return The representation of the data to be transfered.
* *
*/ */
@@ -199,16 +193,13 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* This method is called after data has been exported. This method should * This method is called after data has been exported. This method should remove
* remove the data that was transfered if the action was MOVE. * the data that was transfered if the action was MOVE.
* *
* @param source * @param source The component that was the source of the data.
* The component that was the source of the data. * @param data The data that was transferred or possibly null if the action is
* @param data * <code>NONE</code>.
* The data that was transferred or possibly null * @param action The actual action that was performed.
* if the action is <code>NONE</code>.
* @param action
* The actual action that was performed.
*/ */
@Override @Override
protected void exportDone(JComponent source, Transferable data, int action) { protected void exportDone(JComponent source, Transferable data, int action) {
@@ -229,16 +220,13 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* This method causes a transfer to a component from a clipboard or a * This method causes a transfer to a component from a clipboard or a DND drop
* DND drop operation. The Transferable represents the data to be * operation. The Transferable represents the data to be imported into the
* imported into the component. * component.
* *
* @param comp * @param comp The component to receive the transfer. This argument is provided
* The component to receive the transfer. This * to enable sharing of TransferHandlers by multiple components.
* argument is provided to enable sharing of TransferHandlers by * @param t The data to import
* multiple components.
* @param t
* The data to import
* @return <code>true</code> iff the data was inserted into the component. * @return <code>true</code> iff the data was inserted into the component.
*/ */
@Override @Override
@@ -274,15 +262,13 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* This method indicates if a component would accept an import of the * This method indicates if a component would accept an import of the given set
* given set of data flavors prior to actually attempting to import it. * of data flavors prior to actually attempting to import it.
* *
* @param comp * @param comp The component to receive the transfer. This argument is
* The component to receive the transfer. This argument is
* provided to enable sharing of TransferHandlers by multiple * provided to enable sharing of TransferHandlers by multiple
* components. * components.
* @param flavors * @param flavors The data formats available.
* The data formats available.
* @return <code>true</code> iff the data can be inserted. * @return <code>true</code> iff the data can be inserted.
*/ */
@Override @Override
@@ -313,7 +299,8 @@ public class RTATextTransferHandler extends TransferHandler {
p0 = doc.createPosition(start); p0 = doc.createPosition(start);
p1 = doc.createPosition(end); p1 = doc.createPosition(end);
plainData = c.getSelectedText(); plainData = c.getSelectedText();
} catch (BadLocationException ble) {} } catch (BadLocationException ble) {
}
} }
/** /**
@@ -324,20 +311,15 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* Returns an object which represents the data to be transferred. The * Returns an object which represents the data to be transferred. The class of
* class * the object returned is defined by the representation class of the flavor.
* of the object returned is defined by the representation class of the
* flavor.
* *
* @param flavor * @param flavor the requested flavor for the data
* the requested flavor for the data
* @see DataFlavor#getRepresentationClass * @see DataFlavor#getRepresentationClass
* @exception IOException * @exception IOException if the data is no longer available in
* if the data is no longer available * the requested flavor.
* in the requested flavor. * @exception UnsupportedFlavorException if the requested data flavor is not
* @exception UnsupportedFlavorException * supported.
* if the requested data flavor is
* not supported.
*/ */
@Override @Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
@@ -361,15 +343,11 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* Returns an array of DataFlavor objects indicating the flavors the * Returns an array of DataFlavor objects indicating the flavors the data can be
* data * provided in. The array should be ordered according to preference for
* can be provided in. The array should be ordered according to * providing the data (from most richly descriptive to least descriptive).
* preference
* for providing the data (from most richly descriptive to least
* descriptive).
* *
* @return an array of data flavors in which this data can be * @return an array of data flavors in which this data can be transferred
* transferred
*/ */
@Override @Override
public DataFlavor[] getTransferDataFlavors() { public DataFlavor[] getTransferDataFlavors() {
@@ -391,13 +369,11 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* Returns whether or not the specified data flavor is supported for * Returns whether or not the specified data flavor is supported for this
* this object. * object.
* *
* @param flavor * @param flavor the requested flavor for the data
* the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported
* @return boolean indicating whether or not the data flavor is
* supported
*/ */
@Override @Override
public boolean isDataFlavorSupported(DataFlavor flavor) { public boolean isDataFlavorSupported(DataFlavor flavor) {
@@ -411,14 +387,11 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* Returns whether or not the specified data flavor is an plain flavor * Returns whether or not the specified data flavor is an plain flavor that is
* that * supported.
* is supported.
* *
* @param flavor * @param flavor the requested flavor for the data
* the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported
* @return boolean indicating whether or not the data flavor is
* supported
*/ */
protected boolean isPlainFlavor(DataFlavor flavor) { protected boolean isPlainFlavor(DataFlavor flavor) {
DataFlavor[] flavors = plainFlavors; DataFlavor[] flavors = plainFlavors;
@@ -431,22 +404,19 @@ public class RTATextTransferHandler extends TransferHandler {
} }
/** /**
* Should the plain text flavors be offered? If so, the method * Should the plain text flavors be offered? If so, the method getPlainData
* getPlainData should be implemented to provide something reasonable. * should be implemented to provide something reasonable.
*/ */
protected boolean isPlainSupported() { protected boolean isPlainSupported() {
return plainData != null; return plainData != null;
} }
/** /**
* Returns whether or not the specified data flavor is a String flavor * Returns whether or not the specified data flavor is a String flavor that is
* that * supported.
* is supported.
* *
* @param flavor * @param flavor the requested flavor for the data
* the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported
* @return boolean indicating whether or not the data flavor is
* supported
*/ */
protected boolean isStringFlavor(DataFlavor flavor) { protected boolean isStringFlavor(DataFlavor flavor) {
DataFlavor[] flavors = stringFlavors; DataFlavor[] flavors = stringFlavors;
@@ -463,7 +433,8 @@ public class RTATextTransferHandler extends TransferHandler {
try { try {
Document doc = c.getDocument(); Document doc = c.getDocument();
doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
} catch (BadLocationException e) {} } catch (BadLocationException e) {
}
} }
} }
@@ -49,7 +49,6 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
// FIXME: Replace Utilities calls with custom versions (in RSyntaxUtilities) to // FIXME: Replace Utilities calls with custom versions (in RSyntaxUtilities) to
// cut down on all of the modelToViews, as each call causes // cut down on all of the modelToViews, as each call causes
// a getTokenList => expensive! // a getTokenList => expensive!
@SuppressWarnings({ "checkstyle:constantname" })
public class RTextAreaEditorKit extends DefaultEditorKit { public class RTextAreaEditorKit extends DefaultEditorKit {
/** /**
@@ -69,14 +68,13 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
*/ */
public static final String rtaDeletePrevWordAction = "RTA.DeletePrevWordAction"; public static final String rtaDeletePrevWordAction = "RTA.DeletePrevWordAction";
/** /**
* The name of the action taken to delete the remainder of the line (from * The name of the action taken to delete the remainder of the line (from the
* the caret position to the end of the line). * caret position to the end of the line).
*/ */
public static final String rtaDeleteRestOfLineAction = "RTA.DeleteRestOfLineAction"; public static final String rtaDeleteRestOfLineAction = "RTA.DeleteRestOfLineAction";
/** /**
* The name of the action that completes the word at the caret position * The name of the action that completes the word at the caret position with the
* with the last word in the document that starts with the text up to the * last word in the document that starts with the text up to the caret.
* caret.
*/ */
public static final String rtaDumbCompleteWordAction = "RTA.DumbCompleteWordAction"; public static final String rtaDumbCompleteWordAction = "RTA.DumbCompleteWordAction";
/** /**
@@ -136,13 +134,13 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
*/ */
public static final String rtaRedoAction = "RTA.RedoAction"; public static final String rtaRedoAction = "RTA.RedoAction";
/** /**
* The name of the action to scroll the text area down one line * The name of the action to scroll the text area down one line without changing
* without changing the caret's position. * the caret's position.
*/ */
public static final String rtaScrollDownAction = "RTA.ScrollDownAction"; public static final String rtaScrollDownAction = "RTA.ScrollDownAction";
/** /**
* The name of the action to scroll the text area up one line * The name of the action to scroll the text area up one line without changing
* without changing the caret's position. * the caret's position.
*/ */
public static final String rtaScrollUpAction = "RTA.ScrollUpAction"; public static final String rtaScrollUpAction = "RTA.ScrollUpAction";
/** /**
@@ -166,13 +164,13 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
*/ */
public static final String rtaTimeDateAction = "RTA.TimeDateAction"; public static final String rtaTimeDateAction = "RTA.TimeDateAction";
/** /**
* Toggles whether the current line has a bookmark, if this text area * Toggles whether the current line has a bookmark, if this text area is in an
* is in an {@link RTextScrollPane}. * {@link RTextScrollPane}.
*/ */
public static final String rtaToggleBookmarkAction = "RTA.ToggleBookmarkAction"; public static final String rtaToggleBookmarkAction = "RTA.ToggleBookmarkAction";
/** /**
* The name of the action taken when the user hits the Insert key (thus * The name of the action taken when the user hits the Insert key (thus toggling
* toggling between insert and overwrite modes). * between insert and overwrite modes).
*/ */
public static final String rtaToggleTextModeAction = "RTA.ToggleTextModeAction"; public static final String rtaToggleTextModeAction = "RTA.ToggleTextModeAction";
/** /**
@@ -180,8 +178,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
*/ */
public static final String rtaUndoAction = "RTA.UndoAction"; public static final String rtaUndoAction = "RTA.UndoAction";
/** /**
* The name of the action for unselecting any selected text in the text * The name of the action for unselecting any selected text in the text area.
* area.
*/ */
public static final String rtaUnselectAction = "RTA.UnselectAction"; public static final String rtaUnselectAction = "RTA.UnselectAction";
/** /**
@@ -189,21 +186,24 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
*/ */
public static final String rtaUpperSelectionCaseAction = "RTA.UpperCaseAction"; public static final String rtaUpperSelectionCaseAction = "RTA.UpperCaseAction";
/** /**
* The actions that <code>RTextAreaEditorKit</code> adds to those of * The actions that <code>RTextAreaEditorKit</code> adds to those of the default
* the default editor kit. * editor kit.
*/ */
private static final RecordableTextAction[] defaultActions = { new BeginAction(beginAction, false), private static final RecordableTextAction[] defaultActions = { new BeginAction(beginAction, false),
new BeginAction(selectionBeginAction, true), new BeginLineAction(beginLineAction, false), new BeginAction(selectionBeginAction, true), new BeginLineAction(beginLineAction, false),
new BeginLineAction(selectionBeginLineAction, true), new BeginRecordingMacroAction(), new BeginLineAction(selectionBeginLineAction, true), new BeginRecordingMacroAction(),
new BeginWordAction(beginWordAction, false), new BeginWordAction(selectionBeginWordAction, true), new ClipboardHistoryAction(), new BeginWordAction(beginWordAction, false), new BeginWordAction(selectionBeginWordAction, true),
new CopyAction(), new CutAction(), new DefaultKeyTypedAction(), new DeleteLineAction(), new DeleteNextCharAction(), new ClipboardHistoryAction(), new CopyAction(), new CutAction(), new DefaultKeyTypedAction(),
new DeletePrevCharAction(), new DeletePrevWordAction(), new DeleteRestOfLineAction(), new DumbCompleteWordAction(), new DeleteLineAction(), new DeleteNextCharAction(), new DeletePrevCharAction(), new DeletePrevWordAction(),
new EndAction(endAction, false), new EndAction(selectionEndAction, true), new EndLineAction(endLineAction, false), new DeleteRestOfLineAction(), new DumbCompleteWordAction(), new EndAction(endAction, false),
new EndLineAction(selectionEndLineAction, true), new EndRecordingMacroAction(), new EndWordAction(endWordAction, false), new EndAction(selectionEndAction, true), new EndLineAction(endLineAction, false),
new EndWordAction(endWordAction, true), new InsertBreakAction(), new InsertContentAction(), new InsertTabAction(), new EndLineAction(selectionEndLineAction, true), new EndRecordingMacroAction(),
new InvertSelectionCaseAction(), new JoinLinesAction(), new LowerSelectionCaseAction(), new LineMoveAction(rtaLineUpAction, -1), new EndWordAction(endWordAction, false), new EndWordAction(endWordAction, true), new InsertBreakAction(),
new InsertContentAction(), new InsertTabAction(), new InvertSelectionCaseAction(), new JoinLinesAction(),
new LowerSelectionCaseAction(), new LineMoveAction(rtaLineUpAction, -1),
new LineMoveAction(rtaLineDownAction, 1), new NextBookmarkAction(rtaNextBookmarkAction, true), new LineMoveAction(rtaLineDownAction, 1), new NextBookmarkAction(rtaNextBookmarkAction, true),
new NextBookmarkAction(rtaPrevBookmarkAction, false), new NextVisualPositionAction(forwardAction, false, SwingConstants.EAST), new NextBookmarkAction(rtaPrevBookmarkAction, false),
new NextVisualPositionAction(forwardAction, false, SwingConstants.EAST),
new NextVisualPositionAction(backwardAction, false, SwingConstants.WEST), new NextVisualPositionAction(backwardAction, false, SwingConstants.WEST),
new NextVisualPositionAction(selectionForwardAction, true, SwingConstants.EAST), new NextVisualPositionAction(selectionForwardAction, true, SwingConstants.EAST),
new NextVisualPositionAction(selectionBackwardAction, true, SwingConstants.WEST), new NextVisualPositionAction(selectionBackwardAction, true, SwingConstants.WEST),
@@ -213,13 +213,16 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
new NextVisualPositionAction(selectionDownAction, true, SwingConstants.SOUTH), new NextVisualPositionAction(selectionDownAction, true, SwingConstants.SOUTH),
new NextOccurrenceAction(rtaNextOccurrenceAction), new PreviousOccurrenceAction(rtaPrevOccurrenceAction), new NextOccurrenceAction(rtaNextOccurrenceAction), new PreviousOccurrenceAction(rtaPrevOccurrenceAction),
new NextWordAction(nextWordAction, false), new NextWordAction(selectionNextWordAction, true), new NextWordAction(nextWordAction, false), new NextWordAction(selectionNextWordAction, true),
new PageAction(rtaSelectionPageLeftAction, true, true), new PageAction(rtaSelectionPageRightAction, false, true), new PageAction(rtaSelectionPageLeftAction, true, true),
new PasteAction(), new PlaybackLastMacroAction(), new PreviousWordAction(previousWordAction, false), new PageAction(rtaSelectionPageRightAction, false, true), new PasteAction(), new PlaybackLastMacroAction(),
new PreviousWordAction(selectionPreviousWordAction, true), new RedoAction(), new ScrollAction(rtaScrollUpAction, -1), new PreviousWordAction(previousWordAction, false),
new ScrollAction(rtaScrollDownAction, 1), new SelectAllAction(), new SelectLineAction(), new SelectWordAction(), new PreviousWordAction(selectionPreviousWordAction, true), new RedoAction(),
new SetReadOnlyAction(), new SetWritableAction(), new ToggleBookmarkAction(), new ToggleTextModeAction(), new UndoAction(), new ScrollAction(rtaScrollUpAction, -1), new ScrollAction(rtaScrollDownAction, 1), new SelectAllAction(),
new UnselectAction(), new UpperSelectionCaseAction(), new VerticalPageAction(pageUpAction, -1, false), new SelectLineAction(), new SelectWordAction(), new SetReadOnlyAction(), new SetWritableAction(),
new VerticalPageAction(pageDownAction, 1, false), new VerticalPageAction(rtaSelectionPageUpAction, -1, true), new ToggleBookmarkAction(), new ToggleTextModeAction(), new UndoAction(), new UnselectAction(),
new UpperSelectionCaseAction(), new VerticalPageAction(pageUpAction, -1, false),
new VerticalPageAction(pageDownAction, 1, false),
new VerticalPageAction(rtaSelectionPageUpAction, -1, true),
new VerticalPageAction(rtaSelectionPageDownAction, 1, true) }; new VerticalPageAction(rtaSelectionPageDownAction, 1, true) };
/** /**
* The amount of characters read at a time when reading a file. * The amount of characters read at a time when reading a file.
@@ -236,8 +239,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
/** /**
* Creates an icon row header to use in the gutter for a text area. * Creates an icon row header to use in the gutter for a text area.
* *
* @param textArea * @param textArea The text area.
* The text area.
* @return The icon row header. * @return The icon row header.
*/ */
public IconRowHeader createIconRowHeader(RTextArea textArea) { public IconRowHeader createIconRowHeader(RTextArea textArea) {
@@ -247,8 +249,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
/** /**
* Creates a line number list to use in the gutter for a text area. * Creates a line number list to use in the gutter for a text area.
* *
* @param textArea * @param textArea The text area.
* The text area.
* @return The line number list. * @return The line number list.
*/ */
public LineNumberList createLineNumberList(RTextArea textArea) { public LineNumberList createLineNumberList(RTextArea textArea) {
@@ -256,9 +257,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Fetches the set of commands that can be used * Fetches the set of commands that can be used on a text component that is
* on a text component that is using a model and * using a model and view produced by this kit.
* view produced by this kit.
* *
* @return the command list * @return the command list
*/ */
@@ -268,22 +268,16 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Inserts content from the given stream, which will be * Inserts content from the given stream, which will be treated as plain text.
* treated as plain text. This method is overridden merely * This method is overridden merely so we can increase the number of characters
* so we can increase the number of characters read at a time. * read at a time.
* *
* @param in * @param in The stream to read from
* The stream to read from * @param doc The destination for the insertion.
* @param doc * @param pos The location in the document to place the content &gt;= 0.
* The destination for the insertion. * @exception IOException on any I/O error
* @param pos * @exception BadLocationException if pos represents an invalid location within
* The location in the document to place the * the document.
* content &gt;= 0.
* @exception IOException
* on any I/O error
* @exception BadLocationException
* if pos represents an invalid
* location within the document.
*/ */
@Override @Override
public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
@@ -418,8 +412,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Toggles the position of the caret between the beginning of the line, * Toggles the position of the caret between the beginning of the line, and the
* and the first non-whitespace character on the line. * first non-whitespace character on the line.
*/ */
public static class BeginLineAction extends RecordableTextAction { public static class BeginLineAction extends RecordableTextAction {
@@ -571,8 +565,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Action for displaying a popup with a list of recently pasted text * Action for displaying a popup with a list of recently pasted text snippets.
* snippets.
*/ */
public static class ClipboardHistoryAction extends RecordableTextAction { public static class ClipboardHistoryAction extends RecordableTextAction {
@@ -772,8 +765,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Deletes the character of content that follows the current caret * Deletes the character of content that follows the current caret position.
* position.
*/ */
public static class DeleteNextCharAction extends RecordableTextAction { public static class DeleteNextCharAction extends RecordableTextAction {
@@ -810,7 +802,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
doc.remove(dot, delChars); doc.remove(dot, delChars);
beep = false; beep = false;
} }
} catch (BadLocationException bl) {} } catch (BadLocationException bl) {
}
} }
if (beep) { if (beep) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea); UIManager.getLookAndFeel().provideErrorFeedback(textArea);
@@ -827,8 +820,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Deletes the character of content that precedes the current caret * Deletes the character of content that precedes the current caret position.
* position.
*/ */
public static class DeletePrevCharAction extends RecordableTextAction { public static class DeletePrevCharAction extends RecordableTextAction {
@@ -861,7 +853,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
doc.remove(dot - delChars, delChars); doc.remove(dot - delChars, delChars);
beep = false; beep = false;
} }
} catch (BadLocationException bl) {} } catch (BadLocationException bl) {
}
} }
if (beep) { if (beep) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea); UIManager.getLookAndFeel().provideErrorFeedback(textArea);
@@ -906,8 +899,7 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Returns the starting offset to delete. Exists so subclasses can * Returns the starting offset to delete. Exists so subclasses can override.
* override.
*/ */
protected int getPreviousWordStart(RTextArea textArea, int end) throws BadLocationException { protected int getPreviousWordStart(RTextArea textArea, int end) throws BadLocationException {
return Utilities.getPreviousWord(textArea, end); return Utilities.getPreviousWord(textArea, end);
@@ -951,10 +943,10 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Finds the most recent word in the document that matches the "word" up * Finds the most recent word in the document that matches the "word" up to the
* to the current caret position, and auto-completes the rest. Repeatedly * current caret position, and auto-completes the rest. Repeatedly calling this
* calling this action at the same location in the document goes one * action at the same location in the document goes one match back each time it
* match back each time it is called. * is called.
*/ */
public static class DumbCompleteWordAction extends RecordableTextAction { public static class DumbCompleteWordAction extends RecordableTextAction {
@@ -1038,15 +1030,13 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* <code>Utilities.getWordStart()</code> treats spans of whitespace and * <code>Utilities.getWordStart()</code> treats spans of whitespace and single
* single non-letter chars as "words." This method is used to filter * non-letter chars as "words." This method is used to filter that kind of thing
* that kind of thing out - non-words should not be suggested by this * out - non-words should not be suggested by this action.
* action.
* *
* @param prefix * @param prefix The prefix characters before the caret.
* The prefix characters before the caret. * @return Whether the prefix could be part of a "word" in the context of the
* @return Whether the prefix could be part of a "word" in the context * text area's current content.
* of the text area's current content.
*/ */
protected boolean isAcceptablePrefix(String prefix) { protected boolean isAcceptablePrefix(String prefix) {
return prefix.length() > 0 && Character.isLetter(prefix.charAt(prefix.length() - 1)); return prefix.length() > 0 && Character.isLetter(prefix.charAt(prefix.length() - 1));
@@ -1269,8 +1259,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/* /*
* Overridden for Sun bug 4515750. Sun fixed this in a more complicated * Overridden for Sun bug 4515750. Sun fixed this in a more complicated way, but
* way, but I'm not sure why. See BasicTextUI#getActionMap() and * I'm not sure why. See BasicTextUI#getActionMap() and
* BasicTextUI.TextActionWrapper. * BasicTextUI.TextActionWrapper.
*/ */
@Override @Override
@@ -1310,8 +1300,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Places a tab character into the document. If there is a selection, it * Places a tab character into the document. If there is a selection, it is
* is removed before the tab is added. * removed before the tab is added.
*/ */
public static class InsertTabAction extends RecordableTextAction { public static class InsertTabAction extends RecordableTextAction {
@@ -1681,8 +1671,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Action to move the selection and/or caret. Constructor indicates * Action to move the selection and/or caret. Constructor indicates direction to
* direction to use. * use.
*/ */
public static class NextVisualPositionAction extends RecordableTextAction { public static class NextVisualPositionAction extends RecordableTextAction {
@@ -1700,10 +1690,9 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
Caret caret = textArea.getCaret(); Caret caret = textArea.getCaret();
int dot = caret.getDot(); int dot = caret.getDot();
/* /*
* Move to the beginning/end of selection on a "non-shifted" * Move to the beginning/end of selection on a "non-shifted" left- or
* left- or right-keypress. We shouldn't have to worry about * right-keypress. We shouldn't have to worry about navigation filters as, if
* navigation filters as, if one is being used, it let us get * one is being used, it let us get to that position before.
* to that position before.
*/ */
if (!select) { if (!select) {
switch (direction) { switch (direction) {
@@ -1735,7 +1724,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
if (filter != null) { if (filter != null) {
dot = filter.getNextVisualPositionFrom(textArea, dot, Position.Bias.Forward, direction, bias); dot = filter.getNextVisualPositionFrom(textArea, dot, Position.Bias.Forward, direction, bias);
} else { } else {
dot = textArea.getUI().getNextVisualPositionFrom(textArea, dot, Position.Bias.Forward, direction, bias); dot = textArea.getUI().getNextVisualPositionFrom(textArea, dot, Position.Bias.Forward, direction,
bias);
} }
if (select) { if (select) {
caret.moveDot(dot); caret.moveDot(dot);
@@ -1836,7 +1826,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
if (left) { if (left) {
selectedIndex = textArea.viewToModel(new Point(visible.x, visible.y)); selectedIndex = textArea.viewToModel(new Point(visible.x, visible.y));
} else { } else {
selectedIndex = textArea.viewToModel(new Point(visible.x + visible.width - 1, visible.y + visible.height - 1)); selectedIndex = textArea
.viewToModel(new Point(visible.x + visible.width - 1, visible.y + visible.height - 1));
} }
Document doc = textArea.getDocument(); Document doc = textArea.getDocument();
if ((selectedIndex != 0) && (selectedIndex > (doc.getLength() - 1))) { if ((selectedIndex != 0) && (selectedIndex > (doc.getLength() - 1))) {
@@ -2026,8 +2017,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Scrolls the text area one line up or down, without changing * Scrolls the text area one line up or down, without changing the caret
* the caret position. * position.
*/ */
public static class ScrollAction extends RecordableTextAction { public static class ScrollAction extends RecordableTextAction {
@@ -2357,8 +2348,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
} }
/** /**
* Scrolls up/down vertically. The select version of this action extends * Scrolls up/down vertically. The select version of this action extends the
* the selection, instead of simply moving the caret. * selection, instead of simply moving the caret.
*/ */
public static class VerticalPageAction extends RecordableTextAction { public static class VerticalPageAction extends RecordableTextAction {
@@ -2392,7 +2383,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
if (visible.contains(dotBounds.x, dotBounds.y)) { if (visible.contains(dotBounds.x, dotBounds.y)) {
// Dot is currently visible, base the new // Dot is currently visible, base the new
// location off the old, or // location off the old, or
newIndex = textArea.viewToModel(new Point(x, constrainY(textArea, dotBounds.y + yOffset, 0, 0))); newIndex = textArea
.viewToModel(new Point(x, constrainY(textArea, dotBounds.y + yOffset, 0, 0)));
} else { } else {
// Dot isn't visible, choose the top or the bottom // Dot isn't visible, choose the top or the bottom
// for the new location. // for the new location.
@@ -2414,7 +2406,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
textArea.setCaretPosition(newIndex); textArea.setCaretPosition(newIndex);
} }
} }
} catch (BadLocationException ble) {} } catch (BadLocationException ble) {
}
} // End of if (selectedIndex!=-1). } // End of if (selectedIndex!=-1).
else { else {
yOffset = direction * scrollAmount; yOffset = direction * scrollAmount;
@@ -2463,7 +2456,8 @@ public class RTextAreaEditorKit extends DefaultEditorKit {
visible.y = y; visible.y = y;
} }
} }
} catch (BadLocationException ble) {} } catch (BadLocationException ble) {
}
} }
@Override @Override
@@ -26,8 +26,8 @@ import javax.swing.text.View;
import org.fife.ui.rsyntaxtextarea.DocumentRange; import org.fife.ui.rsyntaxtextarea.DocumentRange;
/** /**
* The highlighter implementation used by {@link RTextArea}s. It knows to * The highlighter implementation used by {@link RTextArea}s. It knows to always
* always paint "mark all" highlights below selection highlights. * paint "mark all" highlights below selection highlights.
* <p> * <p>
* *
* Most of this code is copied from javax.swing.text.DefaultHighlighter; * Most of this code is copied from javax.swing.text.DefaultHighlighter;
@@ -43,8 +43,7 @@ public class RTextAreaHighlighter extends BasicHighlighter {
*/ */
protected RTextArea textArea; protected RTextArea textArea;
/** /**
* The "mark all" highlights (to be painted separately from other * The "mark all" highlights (to be painted separately from other highlights).
* highlights).
*/ */
private List<HighlightInfo> markAllHighlights; private List<HighlightInfo> markAllHighlights;
@@ -106,8 +105,7 @@ public class RTextAreaHighlighter extends BasicHighlighter {
} }
/** /**
* Returns the number of "mark all" highlights currently shown in the * Returns the number of "mark all" highlights currently shown in the editor.
* editor.
* *
* @return The "mark all" highlight count. * @return The "mark all" highlight count.
*/ */
@@ -116,8 +114,8 @@ public class RTextAreaHighlighter extends BasicHighlighter {
} }
/** /**
* Returns a list of "mark all" highlights in the text area. If there are * Returns a list of "mark all" highlights in the text area. If there are no
* no such highlights, this will be an empty list. * such highlights, this will be an empty list.
* *
* @return The list of "mark all" highlight ranges. * @return The list of "mark all" highlight ranges.
*/ */
@@ -142,31 +140,25 @@ public class RTextAreaHighlighter extends BasicHighlighter {
} }
/** /**
* When leaf Views (such as LabelView) are rendering they should * When leaf Views (such as LabelView) are rendering they should call into this
* call into this method. If a highlight is in the given region it will * method. If a highlight is in the given region it will be drawn immediately.
* be drawn immediately.
* *
* @param g * @param g Graphics used to draw
* Graphics used to draw * @param lineStart starting offset of view
* @param lineStart * @param lineEnd ending offset of view
* starting offset of view * @param viewBounds Bounds of View
* @param lineEnd * @param editor JTextComponent
* ending offset of view * @param view View instance being rendered
* @param viewBounds
* Bounds of View
* @param editor
* JTextComponent
* @param view
* View instance being rendered
*/ */
@Override @Override
public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor, View view) { public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor,
View view) {
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markAllHighlights); paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markAllHighlights);
super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view); super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
} }
protected void paintListLayered(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor, View view, protected void paintListLayered(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor,
List<? extends HighlightInfo> highlights) { View view, List<? extends HighlightInfo> highlights) {
for (int i = highlights.size() - 1; i >= 0; i--) { for (int i = highlights.size() - 1; i >= 0; i--) {
HighlightInfo tag = highlights.get(i); HighlightInfo tag = highlights.get(i);
if (tag instanceof LayeredHighlightInfo) { if (tag instanceof LayeredHighlightInfo) {
@@ -175,7 +167,8 @@ public class RTextAreaHighlighter extends BasicHighlighter {
int highlightEnd = lhi.getEndOffset() + 1; // "+1" workaround int highlightEnd = lhi.getEndOffset() + 1; // "+1" workaround
// for Java // for Java
// highlight issues // highlight issues
if ((lineStart < highlightStart && lineEnd > highlightStart) || (lineStart >= highlightStart && lineStart < highlightEnd)) { if ((lineStart < highlightStart && lineEnd > highlightStart)
|| (lineStart >= highlightStart && lineStart < highlightEnd)) {
lhi.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view); lhi.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
} }
} }
@@ -199,7 +192,8 @@ public class RTextAreaHighlighter extends BasicHighlighter {
/** /**
* Information about a highlight being painted by this highlighter. * Information about a highlight being painted by this highlighter.
*/ */
public interface HighlightInfo extends Highlighter.Highlight {} public interface HighlightInfo extends Highlighter.Highlight {
}
/** /**
* Information about a layered highlight being painted by this highlighter. * Information about a layered highlight being painted by this highlighter.
@@ -207,8 +201,8 @@ public class RTextAreaHighlighter extends BasicHighlighter {
public interface LayeredHighlightInfo extends HighlightInfo { public interface LayeredHighlightInfo extends HighlightInfo {
/** /**
* Restricts the region based on the receivers offsets and messages * Restricts the region based on the receivers offsets and messages the painter
* the painter to paint the region. * to paint the region.
*/ */
void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view); void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view);
} }
@@ -256,21 +250,16 @@ public class RTextAreaHighlighter extends BasicHighlighter {
} }
/** /**
* A straightforward implementation of <code>HighlightInfo</code> for * A straightforward implementation of <code>HighlightInfo</code> for painting
* painting layered highlights. * layered highlights.
*/ */
@SuppressWarnings({ "checkstyle:visibilitymodifier" })
protected static class LayeredHighlightInfoImpl extends HighlightInfoImpl implements LayeredHighlightInfo { protected static class LayeredHighlightInfoImpl extends HighlightInfoImpl implements LayeredHighlightInfo {
/* /*
* NOTE: This implementation is a "hack" so typing at the "end" of the * NOTE: This implementation is a "hack" so typing at the "end" of the highlight
* highlight * does not extend it to include the newly-typed chars, which is the standard
* does not extend it to include the newly-typed chars, which is the * behavior of Swing Highlights. It assumes that the "p1" Position set is
* standard * actually 1 char too short, and will render the selection as if that "extra"
* behavior of Swing Highlights. It assumes that the "p1" Position set
* is
* actually 1 char too short, and will render the selection as if that
* "extra"
* char should be highlighted. * char should be highlighted.
*/ */
public int x; public int x;
@@ -302,7 +291,8 @@ public class RTextAreaHighlighter extends BasicHighlighter {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view) { public void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor,
View view) {
int start = getStartOffset(); int start = getStartOffset();
int end = getEndOffset(); int end = getEndOffset();
end++; // Workaround for Java highlight issues end++; // Workaround for Java highlight issues
+198 -266
View File
@@ -22,9 +22,9 @@ import org.fife.ui.rsyntaxtextarea.DocumentRange;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
/** /**
* A singleton class that can perform advanced find/replace operations * A singleton class that can perform advanced find/replace operations in an
* in an {@link RTextArea}. Simply create a {@link SearchContext} and call * {@link RTextArea}. Simply create a {@link SearchContext} and call one of the
* one of the following methods: * following methods:
* *
* <ul> * <ul>
* <li>{@link #find(JTextArea, SearchContext)} * <li>{@link #find(JTextArea, SearchContext)}
@@ -42,21 +42,18 @@ public final class SearchEngine {
/** /**
* Private constructor to prevent instantiation. * Private constructor to prevent instantiation.
*/ */
private SearchEngine() {} private SearchEngine() {
}
/** /**
* Finds the next instance of the string/regular expression specified * Finds the next instance of the string/regular expression specified from the
* from the caret position. If a match is found, it is selected in this * caret position. If a match is found, it is selected in this text area.
* text area.
* *
* @param textArea * @param textArea The text area in which to search.
* The text area in which to search. * @param context What to search for and all search options.
* @param context
* What to search for and all search options.
* @return The result of the operation. * @return The result of the operation.
* @throws PatternSyntaxException * @throws PatternSyntaxException If this is a regular expression search but the
* If this is a regular expression search * search text is an invalid regular expression.
* but the search text is an invalid regular expression.
* @see #replace(RTextArea, SearchContext) * @see #replace(RTextArea, SearchContext)
* @see #replaceAll(RTextArea, SearchContext) * @see #replaceAll(RTextArea, SearchContext)
*/ */
@@ -108,19 +105,15 @@ public final class SearchEngine {
} }
/** /**
* Finds the next instance of the string/regular expression specified * Finds the next instance of the string/regular expression specified from the
* from the caret position. If a match is found, it is selected in this * caret position. If a match is found, it is selected in this text area.
* text area.
* *
* @param findIn * @param findIn The text to search in.
* The text to search in. * @param context The search context.
* @param context * @return The result of the operation. "Mark all" will always be zero, since
* The search context. * this method does not perform that operation.
* @return The result of the operation. "Mark all" will always be zero, * @throws PatternSyntaxException If this is a regular expression search but the
* since this method does not perform that operation. * search text is an invalid regular expression.
* @throws PatternSyntaxException
* If this is a regular expression search
* but the search text is an invalid regular expression.
*/ */
private static SearchResult findImpl(String findIn, SearchContext context) { private static SearchResult findImpl(String findIn, SearchContext context) {
String text = context.getSearchFor(); String text = context.getSearchFor();
@@ -140,7 +133,8 @@ public final class SearchEngine {
Point regExPos = null; Point regExPos = null;
int start = 0; int start = 0;
do { do {
regExPos = getNextMatchPosRegEx(text, findIn.substring(start), forward, context.getMatchCase(), context.getWholeWord()); regExPos = getNextMatchPosRegEx(text, findIn.substring(start), forward, context.getMatchCase(),
context.getWholeWord());
if (regExPos != null) { if (regExPos != null) {
if (regExPos.x != regExPos.y) { if (regExPos.x != regExPos.y) {
regExPos.translate(start, start); regExPos.translate(start, start);
@@ -159,18 +153,15 @@ public final class SearchEngine {
} }
/** /**
* Returns a <code>CharSequence</code> for a text area that doesn't make a * Returns a <code>CharSequence</code> for a text area that doesn't make a copy
* copy of its contents for iteration. This conserves memory but is likely * of its contents for iteration. This conserves memory but is likely just a tad
* just a tad slower. * slower.
* *
* @param textArea * @param textArea The text area whose document is the basis for the
* The text area whose document is the basis for the
* <code>CharSequence</code>. * <code>CharSequence</code>.
* @param start * @param start The starting offset of the sequence (or ending offset if
* The starting offset of the sequence (or ending offset if
* <code>forward</code> is <code>false</code>). * <code>forward</code> is <code>false</code>).
* @param forward * @param forward Whether we're searching forward or backward.
* Whether we're searching forward or backward.
* @return The character sequence. * @return The character sequence.
*/ */
private static CharSequence getFindInCharSequence(RTextArea textArea, int start, boolean forward) { private static CharSequence getFindInCharSequence(RTextArea textArea, int start, boolean forward) {
@@ -188,8 +179,8 @@ public final class SearchEngine {
} }
/** /**
* Returns the text in which to search, as a string. This is used * Returns the text in which to search, as a string. This is used internally to
* internally to grab the smallest buffer possible in which to search. * grab the smallest buffer possible in which to search.
*/ */
private static String getFindInText(JTextArea textArea, int start, boolean forward) { private static String getFindInText(JTextArea textArea, int start, boolean forward) {
// Be smart about the text we grab to search in. We grab more than // Be smart about the text we grab to search in. We grab more than
@@ -210,40 +201,34 @@ public final class SearchEngine {
} }
/** /**
* This method is called internally by * This method is called internally by <code>getNextMatchPosRegExImpl</code> and
* <code>getNextMatchPosRegExImpl</code> and is used to get the locations * is used to get the locations of all regular-expression matches, and possibly
* of all regular-expression matches, and possibly their replacement * their replacement strings.
* strings.
* <p> * <p>
* *
* Returns either: * Returns either:
* <ul> * <ul>
* <li>A list of points representing the starting and ending positions * <li>A list of points representing the starting and ending positions of all
* of all matches returned by the specified matcher, or * matches returned by the specified matcher, or
* <li>A list of <code>RegExReplaceInfo</code>s describing the matches * <li>A list of <code>RegExReplaceInfo</code>s describing the matches found by
* found by the matcher and the replacement strings for each. * the matcher and the replacement strings for each.
* </ul> * </ul>
* *
* If <code>replacement</code> is <code>null</code>, this method call is * If <code>replacement</code> is <code>null</code>, this method call is assumed
* assumed to be part of a "find" operation and points are returned. If * to be part of a "find" operation and points are returned. If if is
* if is non-<code>null</code>, it is assumed to be part of a "replace" * non-<code>null</code>, it is assumed to be part of a "replace" operation and
* operation and the <code>RegExReplaceInfo</code>s are returned. * the <code>RegExReplaceInfo</code>s are returned.
* <p> * <p>
* *
* @param m * @param m The matcher.
* The matcher. * @param replaceStr The string to replace matches with. This is a "template"
* @param replaceStr * string and can contain captured group references in the
* The string to replace matches with. This is a * form "<code>${digit}</code>".
* "template" string and can contain captured group references in
* the form "<code>${digit}</code>".
* @return A list of result objects. * @return A list of result objects.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If <code>replaceStr</code> references an
* If <code>replaceStr</code> references * invalid group (less than zero or greater
* an invalid group (less than zero or greater than the number * than the number of groups matched).
* of
* groups matched).
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" })
private static List getMatches(Matcher m, String replaceStr) { private static List getMatches(Matcher m, String replaceStr) {
ArrayList matches = new ArrayList(); ArrayList matches = new ArrayList();
while (m.find()) { while (m.find()) {
@@ -258,31 +243,26 @@ public final class SearchEngine {
} }
/** /**
* Searches <code>searchIn</code> for an occurrence of * Searches <code>searchIn</code> for an occurrence of <code>searchFor</code>
* <code>searchFor</code> either forwards or backwards, matching * either forwards or backwards, matching case or not.
* case or not.
* <p> * <p>
* *
* Most clients will have no need to call this method directly. * Most clients will have no need to call this method directly.
* *
* @param searchFor * @param searchFor The string to look for.
* The string to look for. * @param searchIn The string to search in.
* @param searchIn * @param forward Whether to search forward or backward in
* The string to search in.
* @param forward
* Whether to search forward or backward in
* <code>searchIn</code>. * <code>searchIn</code>.
* @param matchCase * @param matchCase If <code>true</code>, do a case-sensitive search for
* If <code>true</code>, do a case-sensitive search for
* <code>searchFor</code>. * <code>searchFor</code>.
* @param wholeWord * @param wholeWord If <code>true</code>, <code>searchFor</code> occurrences
* If <code>true</code>, <code>searchFor</code> * embedded in longer words in <code>searchIn</code> don't
* occurrences embedded in longer words in <code>searchIn</code> * count as matches.
* don't count as matches. * @return The starting position of a match, or <code>-1</code> if no match was
* @return The starting position of a match, or <code>-1</code> if no * found.
* match was found.
*/ */
public static int getNextMatchPos(String searchFor, String searchIn, boolean forward, boolean matchCase, boolean wholeWord) { public static int getNextMatchPos(String searchFor, String searchIn, boolean forward, boolean matchCase,
boolean wholeWord) {
// Make our variables lower case if we're ignoring case. // Make our variables lower case if we're ignoring case.
if (!matchCase) { if (!matchCase) {
return getNextMatchPosImpl(searchFor.toLowerCase(), searchIn.toLowerCase(), forward, matchCase, wholeWord); return getNextMatchPosImpl(searchFor.toLowerCase(), searchIn.toLowerCase(), forward, matchCase, wholeWord);
@@ -291,28 +271,23 @@ public final class SearchEngine {
} }
/** /**
* Actually does the work of matching; assumes searchFor and searchIn * Actually does the work of matching; assumes searchFor and searchIn are
* are already upper/lower-cased appropriately.<br> * already upper/lower-cased appropriately.<br>
* The reason this method is here is to attempt to speed up * The reason this method is here is to attempt to speed up
* <code>FindInFilesDialog</code>; since it repeatedly calls * <code>FindInFilesDialog</code>; since it repeatedly calls this method instead
* this method instead of <code>getNextMatchPos</code>, it gets better * of <code>getNextMatchPos</code>, it gets better performance as it no longer
* performance as it no longer has to allocate a lower-cased string for * has to allocate a lower-cased string for every call.
* every call.
* *
* @param searchFor * @param searchFor The string to search for.
* The string to search for. * @param searchIn The string to search in.
* @param searchIn * @param goForward Whether the search is forward or backward.
* The string to search in. * @param matchCase Whether the search is case-sensitive.
* @param goForward * @param wholeWord Whether only whole words should be matched.
* Whether the search is forward or backward. * @return The location of the next match, or <code>-1</code> if no match was
* @param matchCase * found.
* Whether the search is case-sensitive.
* @param wholeWord
* Whether only whole words should be matched.
* @return The location of the next match, or <code>-1</code> if no
* match was found.
*/ */
private static int getNextMatchPosImpl(String searchFor, String searchIn, boolean goForward, boolean matchCase, boolean wholeWord) { private static int getNextMatchPosImpl(String searchFor, String searchIn, boolean goForward, boolean matchCase,
boolean wholeWord) {
if (wholeWord) { if (wholeWord) {
int len = searchFor.length(); int len = searchFor.length();
int temp = goForward ? 0 : searchIn.length(); int temp = goForward ? 0 : searchIn.length();
@@ -339,29 +314,22 @@ public final class SearchEngine {
} }
/** /**
* Searches <code>searchIn</code> for an occurrence of <code>regEx</code> * Searches <code>searchIn</code> for an occurrence of <code>regEx</code> either
* either forwards or backwards, matching case or not. * forwards or backwards, matching case or not.
* *
* @param regEx * @param regEx The regular expression to look for.
* The regular expression to look for. * @param searchIn The string to search in.
* @param searchIn * @param goForward Whether to search forward. If <code>false</code>, search
* The string to search in. * backward.
* @param goForward * @param matchCase Whether or not to do a case-sensitive search for
* Whether to search forward. If <code>false</code>,
* search backward.
* @param matchCase
* Whether or not to do a case-sensitive search for
* <code>regEx</code>. * <code>regEx</code>.
* @param wholeWord * @param wholeWord If <code>true</code>, <code>regEx</code> occurrences
* If <code>true</code>, <code>regEx</code> * embedded in longer words in <code>searchIn</code> don't
* occurrences embedded in longer words in <code>searchIn</code> * count as matches.
* don't count as matches. * @return A <code>Point</code> representing the starting and ending position of
* @return A <code>Point</code> representing the starting and ending * the match, or <code>null</code> if no match was found.
* position of the match, or <code>null</code> if no match was * @throws PatternSyntaxException If <code>regEx</code> is an invalid regular
* found. * expression.
* @throws PatternSyntaxException
* If <code>regEx</code> is an invalid
* regular expression.
* @see #getNextMatchPos * @see #getNextMatchPos
*/ */
private static Point getNextMatchPosRegEx(String regEx, CharSequence searchIn, boolean goForward, boolean matchCase, private static Point getNextMatchPosRegEx(String regEx, CharSequence searchIn, boolean goForward, boolean matchCase,
@@ -370,47 +338,37 @@ public final class SearchEngine {
} }
/** /**
* Searches <code>searchIn</code> for an occurrence of <code>regEx</code> * Searches <code>searchIn</code> for an occurrence of <code>regEx</code> either
* either forwards or backwards, matching case or not. * forwards or backwards, matching case or not.
* *
* @param regEx * @param regEx The regular expression to look for.
* The regular expression to look for. * @param searchIn The string to search in.
* @param searchIn * @param goForward Whether to search forward. If <code>false</code>, search
* The string to search in. * backward.
* @param goForward * @param matchCase Whether or not to do a case-sensitive search for
* Whether to search forward. If <code>false</code>,
* search backward.
* @param matchCase
* Whether or not to do a case-sensitive search for
* <code>regEx</code>. * <code>regEx</code>.
* @param wholeWord * @param wholeWord If <code>true</code>, <code>regEx</code> occurrences
* If <code>true</code>, <code>regEx</code> * embedded in longer words in <code>searchIn</code> don't
* occurrences embedded in longer words in <code>searchIn</code> * count as matches.
* don't count as matches. * @param replaceStr The string that will replace the match found (if a match is
* @param replaceStr * found). The object returned will contain the replacement
* The string that will replace the match found (if * string with matched groups substituted. If this value is
* a match is found). The object returned will contain the * <code>null</code>, it is assumed this call is part of a
* replacement string with matched groups substituted. If this
* value is <code>null</code>, it is assumed this call is part of
* a
* "find" instead of a "replace" operation. * "find" instead of a "replace" operation.
* @return If <code>replaceStr</code> is <code>null</code>, a * @return If <code>replaceStr</code> is <code>null</code>, a <code>Point</code>
* <code>Point</code> representing the starting and ending points * representing the starting and ending points of the match. If it is
* of the match. If it is non-<code>null</code>, an object with * non-<code>null</code>, an object with information about the match and
* information about the match and the morphed string to replace * the morphed string to replace it with. If no match is found,
* it with. If no match is found, <code>null</code> is returned. * <code>null</code> is returned.
* @throws PatternSyntaxException * @throws PatternSyntaxException If <code>regEx</code> is an invalid regular
* If <code>regEx</code> is an invalid * expression.
* regular expression. * @throws IndexOutOfBoundsException If <code>replaceStr</code> references an
* @throws IndexOutOfBoundsException * invalid group (less than zero or greater
* If <code>replaceStr</code> references * than the number of groups matched).
* an invalid group (less than zero or greater than the number
* of
* groups matched).
* @see #getNextMatchPos * @see #getNextMatchPos
*/ */
private static Object getNextMatchPosRegExImpl(String regEx, CharSequence searchIn, boolean goForward, boolean matchCase, private static Object getNextMatchPosRegExImpl(String regEx, CharSequence searchIn, boolean goForward,
boolean wholeWord, String replaceStr) { boolean matchCase, boolean wholeWord, String replaceStr) {
if (wholeWord) { if (wholeWord) {
regEx = "\\b" + regEx + "\\b"; regEx = "\\b" + regEx + "\\b";
} }
@@ -446,22 +404,18 @@ public final class SearchEngine {
} }
/** /**
* Returns information on how to implement a regular expression "replace" * Returns information on how to implement a regular expression "replace" action
* action in the specified text with the specified replacement string. * in the specified text with the specified replacement string.
* *
* @param searchIn * @param searchIn The string to search in.
* The string to search in. * @param context The search options.
* @param context * @return A <code>RegExReplaceInfo</code> object describing how to implement
* The search options. * the replace.
* @return A <code>RegExReplaceInfo</code> object describing how to * @throws PatternSyntaxException If the search text is an invalid regular
* implement the replace.
* @throws PatternSyntaxException
* If the search text is an invalid regular
* expression. * expression.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If the replacement text references an
* If the replacement text references an * invalid group (less than zero or greater
* invalid group (less than zero or greater than the number of * than the number of groups matched).
* groups matched).
* @see #getNextMatchPos * @see #getNextMatchPos
*/ */
private static RegExReplaceInfo getRegExReplaceInfo(CharSequence searchIn, SearchContext context) { private static RegExReplaceInfo getRegExReplaceInfo(CharSequence searchIn, SearchContext context) {
@@ -476,39 +430,34 @@ public final class SearchEngine {
boolean goForward = context.getSearchForward(); boolean goForward = context.getSearchForward();
boolean matchCase = context.getMatchCase(); boolean matchCase = context.getMatchCase();
boolean wholeWord = context.getWholeWord(); boolean wholeWord = context.getWholeWord();
return (RegExReplaceInfo) getNextMatchPosRegExImpl(regex, searchIn, goForward, matchCase, wholeWord, replacement); return (RegExReplaceInfo) getNextMatchPosRegExImpl(regex, searchIn, goForward, matchCase, wholeWord,
replacement);
} }
/** /**
* Called internally by <code>getMatches()</code>. This method assumes * Called internally by <code>getMatches()</code>. This method assumes that the
* that the specified matcher has just found a match, and that you want * specified matcher has just found a match, and that you want to get the string
* to get the string with which to replace that match. * with which to replace that match.
* <p> * <p>
* *
* Escapes simply insert the escaped character, except for <code>\n</code> * Escapes simply insert the escaped character, except for <code>\n</code> and
* and <code>\t</code>, which insert a newline and tab respectively. * <code>\t</code>, which insert a newline and tab respectively. Substrings of
* Substrings of the form <code>$\d+</code> are considered to be matched * the form <code>$\d+</code> are considered to be matched groups. To include a
* groups. To include a literal dollar sign in your template, escape it * literal dollar sign in your template, escape it (i.e. <code>\$</code>).
* (i.e. <code>\$</code>).
* <p> * <p>
* *
* Most clients will have no need to call this method directly. * Most clients will have no need to call this method directly.
* *
* @param m * @param m The matcher.
* The matcher. * @param template The template for the replacement string. For example,
* @param template
* The template for the replacement string. For example,
* "<code>foo</code>" would yield the replacement string * "<code>foo</code>" would yield the replacement string
* "<code>foo</code>", while "<code>$1 is the greatest</code>" * "<code>foo</code>", while "<code>$1 is the greatest</code>"
* would yield different values depending on the value of the * would yield different values depending on the value of the
* first * first captured group in the match.
* captured group in the match.
* @return The string to replace the match with. * @return The string to replace the match with.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If <code>template</code> references an
* If <code>template</code> references * invalid group (less than zero or greater
* an invalid group (less than zero or greater than the number * than the number of groups matched).
* of
* groups matched).
*/ */
public static String getReplacementText(Matcher m, CharSequence template) { public static String getReplacementText(Matcher m, CharSequence template) {
// NOTE: This code was mostly ripped off from J2SE's Matcher // NOTE: This code was mostly ripped off from J2SE's Matcher
@@ -573,8 +522,8 @@ public final class SearchEngine {
/** /**
* Returns whether the characters on either side of * Returns whether the characters on either side of
* <code>substr(searchIn, startPos, startPos+searchStringLength)</code> * <code>substr(searchIn, startPos, startPos+searchStringLength)</code> are
* are <em>not</em> letters or digits. * <em>not</em> letters or digits.
*/ */
private static boolean isWholeWord(CharSequence searchIn, int offset, int len) { private static boolean isWholeWord(CharSequence searchIn, int offset, int len) {
boolean wsBefore, wsAfter; boolean wsBefore, wsAfter;
@@ -592,15 +541,13 @@ public final class SearchEngine {
} }
/** /**
* Makes the caret's dot and mark the same location so that, for the * Makes the caret's dot and mark the same location so that, for the next search
* next search in the specified direction, a match will be found even * in the specified direction, a match will be found even if it was within the
* if it was within the original dot and mark's selection. * original dot and mark's selection.
* *
* @param textArea * @param textArea The text area.
* The text area. * @param forward Whether the search will be forward through the document
* @param forward * (<code>false</code> means backward).
* Whether the search will be forward through the
* document (<code>false</code> means backward).
* @return The new dot and mark position. * @return The new dot and mark position.
*/ */
private static int makeMarkAndDotEqual(JTextArea textArea, boolean forward) { private static int makeMarkAndDotEqual(JTextArea textArea, boolean forward) {
@@ -611,18 +558,15 @@ public final class SearchEngine {
} }
/** /**
* Marks all instances of the specified text in this text area. This * Marks all instances of the specified text in this text area. This method is
* method is typically only called directly in response to search events * typically only called directly in response to search events of type
* of type <code>SearchEvent.Type.MARK_ALL</code>. "Mark all" behavior * <code>SearchEvent.Type.MARK_ALL</code>. "Mark all" behavior is automatically
* is automatically performed when {@link #find(JTextArea, SearchContext)} * performed when {@link #find(JTextArea, SearchContext)} or
* or {@link #replace(RTextArea, SearchContext)} is called. * {@link #replace(RTextArea, SearchContext)} is called.
* *
* @param textArea * @param textArea The text area in which to mark occurrences.
* The text area in which to mark occurrences. * @param context The search context specifying the text to search for. It is
* @param context * assumed that <code>context.getMarkAll()</code> has already
* The search context specifying the text to search for.
* It is assumed that <code>context.getMarkAll()</code> has
* already
* been checked and returns <code>true</code>. * been checked and returns <code>true</code>.
* @return The results of the operation. * @return The results of the operation.
*/ */
@@ -635,18 +579,15 @@ public final class SearchEngine {
} }
/** /**
* Marks all instances of the specified text in this text area. This * Marks all instances of the specified text in this text area. This method is
* method is typically only called directly in response to search events * typically only called directly in response to search events of type
* of type <code>SearchEvent.Type.MARK_ALL</code>. "Mark all" behavior * <code>SearchEvent.Type.MARK_ALL</code>. "Mark all" behavior is automatically
* is automatically performed when {@link #find(JTextArea, SearchContext)} * performed when {@link #find(JTextArea, SearchContext)} or #replace(RTextArea,
* or #replace(RTextArea, SearchContext) is called. * SearchContext) is called.
* *
* @param textArea * @param textArea The text area in which to mark occurrences.
* The text area in which to mark occurrences. * @param context The search context specifying the text to search for. It is
* @param context * assumed that <code>context.getMarkAll()</code> has already
* The search context specifying the text to search for.
* It is assumed that <code>context.getMarkAll()</code> has
* already
* been checked and returns <code>true</code>. * been checked and returns <code>true</code>.
* @return The results of the operation. * @return The results of the operation.
*/ */
@@ -700,23 +641,20 @@ public final class SearchEngine {
} }
/** /**
* Finds the next instance of the regular expression specified from * Finds the next instance of the regular expression specified from the caret
* the caret position. If a match is found, it is replaced with * position. If a match is found, it is replaced with the specified replacement
* the specified replacement string. * string.
* *
* @param textArea * @param textArea The text area in which to search.
* The text area in which to search. * @param context What to search for and all search options.
* @param context
* What to search for and all search options.
* @return The result of the operation. * @return The result of the operation.
* @throws PatternSyntaxException * @throws PatternSyntaxException If this is a regular expression search but
* If this is a regular expression search * the search text is an invalid regular
* but the search text is an invalid regular expression. * expression.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If this is a regular expression search but
* If this is a regular expression search * the replacement text references an invalid
* but the replacement text references an invalid group (less * group (less than zero or greater than the
* than * number of groups matched).
* zero or greater than the number of groups matched).
* @see #replace(RTextArea, SearchContext) * @see #replace(RTextArea, SearchContext)
* @see #find(JTextArea, SearchContext) * @see #find(JTextArea, SearchContext)
*/ */
@@ -778,23 +716,20 @@ public final class SearchEngine {
} }
/** /**
* Finds the next instance of the text/regular expression specified from * Finds the next instance of the text/regular expression specified from the
* the caret position. If a match is found, it is replaced with the * caret position. If a match is found, it is replaced with the specified
* specified replacement string. * replacement string.
* *
* @param textArea * @param textArea The text area in which to search.
* The text area in which to search. * @param context What to search for and all search options.
* @param context
* What to search for and all search options.
* @return The result of the operation. * @return The result of the operation.
* @throws PatternSyntaxException * @throws PatternSyntaxException If this is a regular expression search but
* If this is a regular expression search * the search text is an invalid regular
* but the search text is an invalid regular expression. * expression.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If this is a regular expression search but
* If this is a regular expression search * the replacement text references an invalid
* but the replacement text references an invalid group (less * group (less than zero or greater than the
* than * number of groups matched).
* zero or greater than the number of groups matched).
* @see #replaceAll(RTextArea, SearchContext) * @see #replaceAll(RTextArea, SearchContext)
* @see #find(JTextArea, SearchContext) * @see #find(JTextArea, SearchContext)
*/ */
@@ -849,22 +784,19 @@ public final class SearchEngine {
} }
/** /**
* Replaces all instances of the text/regular expression specified in * Replaces all instances of the text/regular expression specified in the
* the specified document with the specified replacement. * specified document with the specified replacement.
* *
* @param textArea * @param textArea The text area in which to search.
* The text area in which to search. * @param context What to search for and all search options.
* @param context
* What to search for and all search options.
* @return The result of the operation. * @return The result of the operation.
* @throws PatternSyntaxException * @throws PatternSyntaxException If this is a regular expression search but
* If this is a regular expression search * the replacement text is an invalid regular
* but the replacement text is an invalid regular expression. * expression.
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException If this is a regular expression search but
* If this is a regular expression search * the replacement text references an invalid
* but the replacement text references an invalid group (less * group (less than zero or greater than the
* than * number of groups matched).
* zero or greater than the number of groups matched).
* @see #replace(RTextArea, SearchContext) * @see #replace(RTextArea, SearchContext)
* @see #find(JTextArea, SearchContext) * @see #find(JTextArea, SearchContext)
*/ */