mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-16 11:21:18 +03:00
Initial Arduino IDE based on Processing.
This commit is contained in:
1111
app/Base.java
Normal file
1111
app/Base.java
Normal file
File diff suppressed because it is too large
Load Diff
455
app/Compiler.java
Normal file
455
app/Compiler.java
Normal file
@ -0,0 +1,455 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Compiler - default compiler class that connects to jikes
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
|
||||
Copyleft 2005 Massimo Banzi (arduino modifications)
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
//import processing.core.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import javax.swing.*;
|
||||
|
||||
public class Compiler implements MessageConsumer {
|
||||
static final String BUGS_URL = "http://arduino.berlios.de";
|
||||
static final String SUPER_BADNESS = "Compiler error, please submit this code to " + BUGS_URL;
|
||||
|
||||
Sketch sketch;
|
||||
String buildPath;
|
||||
|
||||
//String buildPath;
|
||||
//String className;
|
||||
//File includeFolder;
|
||||
RunnerException exception;
|
||||
//Editor editor;
|
||||
|
||||
/*
|
||||
public Compiler(String buildPath, String className,
|
||||
File includeFolder, Editor editor) {
|
||||
this.buildPath = buildPath;
|
||||
this.includeFolder = includeFolder;
|
||||
this.className = className;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
|
||||
public boolean compile(PrintStream leechErr) {
|
||||
*/
|
||||
|
||||
public Compiler() { } // null constructor
|
||||
|
||||
public boolean compile(Sketch sketch, String buildPath)
|
||||
throws RunnerException {
|
||||
|
||||
this.sketch = sketch;
|
||||
this.buildPath = buildPath;
|
||||
|
||||
// the pms object isn't used for anything but storage
|
||||
MessageStream pms = new MessageStream(this);
|
||||
|
||||
String userdir = System.getProperty("user.dir") + File.separator;
|
||||
|
||||
System.out.println("Compiling Arduino program");
|
||||
Process process;
|
||||
int result = 0;
|
||||
try {
|
||||
process = Runtime.getRuntime().exec(userdir + "tools/gnumake -s -C " + userdir + "lib compile");
|
||||
|
||||
// System.err.println(userdir + "lib/wiringlite/bin/gnumake -s -C " + userdir + "lib compile");
|
||||
|
||||
new MessageSiphon(process.getInputStream(), this);
|
||||
new MessageSiphon(process.getErrorStream(), this);
|
||||
boolean compiling = true;
|
||||
while (compiling) {
|
||||
try {
|
||||
result = process.waitFor();
|
||||
compiling = false;
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error: GNUMake probably couldn't be found");
|
||||
result = 99;
|
||||
}
|
||||
if(0 == result){
|
||||
System.out.println("Arduino Compilation Successful");
|
||||
}else{
|
||||
System.out.println("Arduino Compilation Unsuccessful (error: " + result + ")");
|
||||
}
|
||||
return (result == 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean firstErrorFound;
|
||||
boolean secondErrorFound;
|
||||
|
||||
/**
|
||||
* Part of the MessageConsumer interface, this is called
|
||||
* whenever a piece (usually a line) of error message is spewed
|
||||
* out from the compiler. The errors are parsed for their contents
|
||||
* and line number, which is then reported back to Editor.
|
||||
*/
|
||||
public void message(String s) {
|
||||
// This receives messages as full lines, so a newline needs
|
||||
// to be added as they're printed to the console.
|
||||
System.err.println(s);
|
||||
|
||||
// ignore cautions
|
||||
if (s.indexOf("Caution") != -1) return;
|
||||
|
||||
// jikes always uses a forward slash character as its separator,
|
||||
// so replace any platform-specific separator characters before
|
||||
// attemping to compare
|
||||
//
|
||||
String buildPathSubst = buildPath.replace(File.separatorChar, '/') + "/";
|
||||
|
||||
String partialTempPath = null;
|
||||
int partialStartIndex = -1; //s.indexOf(partialTempPath);
|
||||
int fileIndex = -1; // use this to build a better exception
|
||||
|
||||
// iterate through the project files to see who's causing the trouble
|
||||
for (int i = 0; i < sketch.codeCount; i++) {
|
||||
if (sketch.code[i].preprocName == null) continue;
|
||||
|
||||
partialTempPath = buildPathSubst + sketch.code[i].preprocName;
|
||||
partialStartIndex = s.indexOf(partialTempPath);
|
||||
if (partialStartIndex != -1) {
|
||||
fileIndex = i;
|
||||
//System.out.println("fileIndex is " + fileIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//+ className + ".java";
|
||||
|
||||
// if the partial temp path appears in the error message...
|
||||
//
|
||||
//int partialStartIndex = s.indexOf(partialTempPath);
|
||||
if (partialStartIndex != -1) {
|
||||
|
||||
// skip past the path and parse the int after the first colon
|
||||
//
|
||||
String s1 = s.substring(partialStartIndex +
|
||||
partialTempPath.length() + 1);
|
||||
int colon = s1.indexOf(':');
|
||||
int lineNumber = Integer.parseInt(s1.substring(0, colon));
|
||||
//System.out.println("pde / line number: " + lineNumber);
|
||||
|
||||
if (fileIndex == 0) { // main class, figure out which tab
|
||||
for (int i = 1; i < sketch.codeCount; i++) {
|
||||
if (sketch.code[i].flavor == Sketch.PDE) {
|
||||
if (sketch.code[i].preprocOffset < lineNumber) {
|
||||
fileIndex = i;
|
||||
//System.out.println("i'm thinkin file " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fileIndex != 0) { // if found another culprit
|
||||
lineNumber -= sketch.code[fileIndex].preprocOffset;
|
||||
//System.out.println("i'm sayin line " + lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
//String s2 = s1.substring(colon + 2);
|
||||
int err = s1.indexOf("Error:");
|
||||
if (err != -1) {
|
||||
|
||||
// if the first error has already been found, then this must be
|
||||
// (at least) the second error found
|
||||
if (firstErrorFound) {
|
||||
secondErrorFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// if executing at this point, this is *at least* the first error
|
||||
firstErrorFound = true;
|
||||
|
||||
//err += "error:".length();
|
||||
String description = s1.substring(err + "Error:".length());
|
||||
description = description.trim();
|
||||
|
||||
String hasLoop = "The method \"void loop();\" with default access";
|
||||
if (description.indexOf(hasLoop) != -1) {
|
||||
description =
|
||||
"Rename loop() to draw() in Processing 0070 and higher";
|
||||
}
|
||||
|
||||
String constructorProblem =
|
||||
"No applicable overload was found for a constructor of type";
|
||||
if (description.indexOf(constructorProblem) != -1) {
|
||||
//"simong.particles.ParticleSystem". Perhaps you wanted the overloaded version "ParticleSystem();" instead?
|
||||
int nextSentence = description.indexOf("\".") + 3;
|
||||
description = description.substring(nextSentence);
|
||||
}
|
||||
|
||||
String overloadProblem = "No applicable overload";
|
||||
if (description.indexOf(overloadProblem) != -1) {
|
||||
int nextSentence = description.indexOf("\".") + 3;
|
||||
description = description.substring(nextSentence);
|
||||
}
|
||||
|
||||
// c:/fry/processing/build/windows/work/lib/build/Temporary_6858_2476.java:1:34:1:41: Semantic Error: You need to modify your classpath, sourcepath, bootclasspath, and/or extdirs setup. Package "poo/shoe" could not be found in:
|
||||
String classpathProblem = "You need to modify your classpath";
|
||||
if (description.indexOf(classpathProblem) != -1) {
|
||||
if (description.indexOf("quicktime/std") != -1) {
|
||||
// special case for the quicktime libraries
|
||||
description =
|
||||
"To run sketches that use the Processing video library, " +
|
||||
"you must first install QuickTime for Java.";
|
||||
|
||||
} else {
|
||||
int nextSentence = description.indexOf(". Package") + 2;
|
||||
description =
|
||||
description.substring(nextSentence, description.indexOf(':')) +
|
||||
" the code folder or in any libraries.";
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("description = " + description);
|
||||
//System.out.println("creating exception " + exception);
|
||||
exception = new RunnerException(description, fileIndex, lineNumber-1, -1);
|
||||
|
||||
// NOTE!! major change here, this exception will be queued
|
||||
// here to be thrown by the compile() function
|
||||
//editor.error(exception);
|
||||
|
||||
} else {
|
||||
System.err.println("i suck: " + s);
|
||||
}
|
||||
|
||||
} else {
|
||||
// this isn't the start of an error line, so don't attempt to parse
|
||||
// a line number out of it.
|
||||
|
||||
// if the second error hasn't been discovered yet, these lines
|
||||
// are probably associated with the first error message,
|
||||
// which is already in the status bar, and are likely to be
|
||||
// of interest to the user, so spit them to the console.
|
||||
//
|
||||
if (!secondErrorFound) {
|
||||
System.err.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static String bootClassPath;
|
||||
|
||||
static public String calcBootClassPath() {
|
||||
if (bootClassPath == null) {
|
||||
String additional = "";
|
||||
if (Base.isMacOS()) {
|
||||
additional =
|
||||
contentsToClassPath(new File("/System/Library/Java/Extensions/"));
|
||||
}
|
||||
bootClassPath = System.getProperty("sun.boot.class.path") + additional;
|
||||
}
|
||||
return bootClassPath;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
|
||||
|
||||
/**
|
||||
* Return the path for a folder, with appended paths to
|
||||
* any .jar or .zip files inside that folder.
|
||||
* This will prepend a colon (or whatever the path separator is)
|
||||
* so that it can be directly appended to another path string.
|
||||
*
|
||||
* This will always add the root folder as well, and doesn't bother
|
||||
* checking to see if there are any .class files in the folder or
|
||||
* within a subfolder.
|
||||
*/
|
||||
static public String contentsToClassPath(File folder) {
|
||||
if (folder == null) return "";
|
||||
|
||||
StringBuffer abuffer = new StringBuffer();
|
||||
String sep = System.getProperty("path.separator");
|
||||
|
||||
try {
|
||||
// add the folder itself in case any unzipped files
|
||||
String path = folder.getCanonicalPath();
|
||||
abuffer.append(sep);
|
||||
abuffer.append(path);
|
||||
|
||||
if (!path.endsWith(File.separator)) {
|
||||
path += File.separator;
|
||||
}
|
||||
//System.out.println("path is " + path);
|
||||
|
||||
String list[] = folder.list();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i].toLowerCase().endsWith(".jar") ||
|
||||
list[i].toLowerCase().endsWith(".zip")) {
|
||||
abuffer.append(sep);
|
||||
abuffer.append(path);
|
||||
abuffer.append(list[i]);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // this would be odd
|
||||
}
|
||||
//System.out.println("included path is " + abuffer.toString());
|
||||
//packageListFromClassPath(abuffer.toString()); // WHY?
|
||||
return abuffer.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A classpath, separated by the path separator, will contain
|
||||
* a series of .jar/.zip files or directories containing .class
|
||||
* files, or containing subdirectories that have .class files.
|
||||
*
|
||||
* @param path the input classpath
|
||||
* @return array of possible package names
|
||||
*/
|
||||
static public String[] packageListFromClassPath(String path) {
|
||||
Hashtable table = new Hashtable();
|
||||
String pieces[] =
|
||||
Base.split(path, File.pathSeparatorChar);
|
||||
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
//System.out.println("checking piece '" + pieces[i] + "'");
|
||||
if (pieces[i].length() == 0) continue;
|
||||
|
||||
if (pieces[i].toLowerCase().endsWith(".jar") ||
|
||||
pieces[i].toLowerCase().endsWith(".zip")) {
|
||||
packageListFromZip(pieces[i], table);
|
||||
|
||||
} else { // it's another type of file or directory
|
||||
File dir = new File(pieces[i]);
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
packageListFromFolder(dir, null, table);
|
||||
//importCount = magicImportsRecursive(dir, null,
|
||||
// table);
|
||||
//imports, importCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
int tableCount = table.size();
|
||||
String output[] = new String[tableCount];
|
||||
int index = 0;
|
||||
Enumeration e = table.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
output[index++] = ((String) e.nextElement()).replace('/', '.');
|
||||
}
|
||||
//System.arraycopy(imports, 0, output, 0, importCount);
|
||||
//PApplet.printarr(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
static private void packageListFromZip(String filename, Hashtable table) {
|
||||
try {
|
||||
ZipFile file = new ZipFile(filename);
|
||||
Enumeration entries = file.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry) entries.nextElement();
|
||||
|
||||
if (!entry.isDirectory()) {
|
||||
String name = entry.getName();
|
||||
|
||||
if (name.endsWith(".class")) {
|
||||
int slash = name.lastIndexOf('/');
|
||||
if (slash == -1) continue;
|
||||
|
||||
String pname = name.substring(0, slash);
|
||||
if (table.get(pname) == null) {
|
||||
table.put(pname, new Object());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")");
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make list of package names by traversing a directory hierarchy.
|
||||
* Each time a class is found in a folder, add its containing set
|
||||
* of folders to the package list. If another folder is found,
|
||||
* walk down into that folder and continue.
|
||||
*/
|
||||
static private void packageListFromFolder(File dir, String sofar,
|
||||
Hashtable table) {
|
||||
//String imports[],
|
||||
//int importCount) {
|
||||
//System.err.println("checking dir '" + dir + "'");
|
||||
boolean foundClass = false;
|
||||
String files[] = dir.list();
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].equals(".") || files[i].equals("..")) continue;
|
||||
|
||||
File sub = new File(dir, files[i]);
|
||||
if (sub.isDirectory()) {
|
||||
String nowfar =
|
||||
(sofar == null) ? files[i] : (sofar + "." + files[i]);
|
||||
packageListFromFolder(sub, nowfar, table);
|
||||
//System.out.println(nowfar);
|
||||
//imports[importCount++] = nowfar;
|
||||
//importCount = magicImportsRecursive(sub, nowfar,
|
||||
// imports, importCount);
|
||||
} else if (!foundClass) { // if no classes found in this folder yet
|
||||
if (files[i].endsWith(".class")) {
|
||||
//System.out.println("unique class: " + files[i] + " for " + sofar);
|
||||
table.put(sofar, new Object());
|
||||
foundClass = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//return importCount;
|
||||
}
|
||||
|
||||
/*
|
||||
static public int magicImportsRecursive(File dir, String sofar,
|
||||
Hashtable table) {
|
||||
//String imports[],
|
||||
//int importCount) {
|
||||
System.err.println("checking dir '" + dir + "'");
|
||||
String files[] = dir.list();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].equals(".") || files[i].equals("..")) continue;
|
||||
|
||||
File sub = new File(dir, files[i]);
|
||||
if (sub.isDirectory()) {
|
||||
String nowfar = (sofar == null) ?
|
||||
files[i] : (sofar + "." + files[i]);
|
||||
//System.out.println(nowfar);
|
||||
imports[importCount++] = nowfar;
|
||||
|
||||
importCount = magicImportsRecursive(sub, nowfar,
|
||||
imports, importCount);
|
||||
}
|
||||
}
|
||||
return importCount;
|
||||
}
|
||||
*/
|
||||
}
|
268
app/Downloader.java
Executable file
268
app/Downloader.java
Executable file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
Downloader - default downloader class that connects to uisp
|
||||
|
||||
Part of the Arduino project http://arduino.berlios.de
|
||||
|
||||
Based on PdeDownloader by
|
||||
Copyright (c) 2005
|
||||
Hernando Barragan, Interaction Design Institute Ivrea
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
package processing.app;
|
||||
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import gnu.io.*;
|
||||
|
||||
|
||||
|
||||
public class Downloader implements MessageConsumer {
|
||||
static final String BUGS_URL =
|
||||
"http://arduino.berlios.de";
|
||||
static final String SUPER_BADNESS =
|
||||
"Compiler error, please submit this code to " + BUGS_URL;
|
||||
|
||||
String buildPath;
|
||||
String className;
|
||||
File includeFolder;
|
||||
RunnerException exception;
|
||||
Sketch sketch;
|
||||
//Preferences preferences;
|
||||
|
||||
//static SerialPort serialPort;
|
||||
static InputStream serialInput;
|
||||
static OutputStream serialOutput;
|
||||
//int serial; // last byte of data received
|
||||
|
||||
private String serial_port = "COM1";
|
||||
private int serial_rate = 9600;
|
||||
private char serial_parity = 'N';
|
||||
private int serial_databits = 8;
|
||||
private float serial_stopbits = 1;
|
||||
|
||||
public void serialPreferences() {
|
||||
// System.out.println("setting serial properties");
|
||||
serial_port = Preferences.get("serial.port");
|
||||
//serial_rate = 9600; //Preferences.getInteger("serial.download_rate");
|
||||
//serial_parity = Preferences.get("serial.parity").charAt(0);
|
||||
//serial_databits = Preferences.getInteger("serial.databits");
|
||||
//serial_stopbits = new Float(Preferences.get("serial.stopbits")).floatValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Downloader() {
|
||||
}
|
||||
|
||||
|
||||
private boolean downloadMake(String userdir) {
|
||||
System.out.println("Downloading - makefile");
|
||||
Process process;
|
||||
int result = 0;
|
||||
try {
|
||||
serialPreferences();
|
||||
String command = userdir + "tools/gnumake SERIAL=" + serial_port + " -C " + userdir + "lib program";
|
||||
System.out.println(command);
|
||||
process = Runtime.getRuntime().exec(command);
|
||||
new MessageSiphon(process.getInputStream(), this);
|
||||
new MessageSiphon(process.getErrorStream(), this);
|
||||
boolean compiling = true;
|
||||
while (compiling) {
|
||||
try {
|
||||
result = process.waitFor();
|
||||
compiling = false;
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error: GNUMake probably couldn't be found");
|
||||
result = 99;
|
||||
}
|
||||
if(0 == result){
|
||||
System.out.println("Arduino Download Successful");
|
||||
}else{
|
||||
System.out.println("Arduino Download Unsuccessful (error: " + result + ")");
|
||||
}
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
public boolean downloadJava() {
|
||||
String userdir = System.getProperty("user.dir") + File.separator;
|
||||
|
||||
|
||||
return downloadMake(userdir);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean downloadNative(String userdir) {
|
||||
System.out.println("Downloading - native");
|
||||
|
||||
|
||||
String commandDownloader[] = new String[] {
|
||||
(( Base.isMacOS()) ? "tools/avr/bin/uisp" :
|
||||
userdir + "tools/avr/bin/uisp"),
|
||||
//[2] Serial port
|
||||
//[6] hex class file
|
||||
"-dprog=stk500",
|
||||
" ",
|
||||
"-dspeed=9600",
|
||||
"-dpart=atmega8",
|
||||
"--upload",
|
||||
" "
|
||||
};
|
||||
|
||||
firstErrorFound = false; // haven't found any errors yet
|
||||
secondErrorFound = false;
|
||||
|
||||
int result=0; // pre-initialized to quiet a bogus warning from gcc
|
||||
try {
|
||||
|
||||
serialPreferences();
|
||||
commandDownloader[2] = ((Base.isMacOS()) ? "-dserial=" + serial_port.toLowerCase() : "-dserial=" + serial_port );
|
||||
commandDownloader[6] = "if=" + buildPath + File.separator + className + ".hex";
|
||||
// for(int i = 0; i < commandDownloader.length; i++) {
|
||||
// System.out.println(commandDownloader[i]);
|
||||
// }
|
||||
Process process = Runtime.getRuntime().exec(commandDownloader);
|
||||
new MessageSiphon(process.getInputStream(), this);
|
||||
new MessageSiphon(process.getErrorStream(), this);
|
||||
|
||||
// wait for the process to finish. if interrupted
|
||||
// before waitFor returns, continue waiting
|
||||
//
|
||||
boolean compiling = true;
|
||||
while (compiling) {
|
||||
try {
|
||||
result = process.waitFor();
|
||||
compiling = false;
|
||||
} catch (InterruptedException intExc) {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
if ((msg != null) && (msg.indexOf("uisp: not found") != -1)) {
|
||||
//System.err.println("gcc is missing");
|
||||
//JOptionPane.showMessageDialog(editor.base,
|
||||
// "Could not find the downloader.\n" +
|
||||
// "uisp is missing from your PATH,\n" +
|
||||
// "see readme.txt for help.",
|
||||
// "Downloade error",
|
||||
// JOptionPane.ERROR_MESSAGE);
|
||||
return false;
|
||||
}
|
||||
e.printStackTrace();
|
||||
result = -1;
|
||||
}
|
||||
|
||||
// if the result isn't a known, expected value it means that something
|
||||
// is fairly wrong, one possibility is that gcc has crashed.
|
||||
//
|
||||
if (result != 0 && result != 1 ) {
|
||||
exception = new RunnerException(SUPER_BADNESS);
|
||||
//editor.error(exception);
|
||||
//Base.openURL(BUGS_URL);
|
||||
}
|
||||
|
||||
return (result == 0) ? true : false;
|
||||
|
||||
}
|
||||
|
||||
boolean firstErrorFound;
|
||||
boolean secondErrorFound;
|
||||
|
||||
// part of the PdeMessageConsumer interface
|
||||
//
|
||||
public void message(String s) {
|
||||
//System.err.println("MSG: " + s);
|
||||
//System.err.print(s);
|
||||
|
||||
// ignore cautions
|
||||
if (s.indexOf("Caution") != -1) return;
|
||||
|
||||
// gcc always uses a forward slash character as its separator, so
|
||||
// we need to replace any platform-specific separator characters before
|
||||
// attemping to compare
|
||||
//
|
||||
String partialTempPath = buildPath.replace(File.separatorChar, '/')
|
||||
+ "/" + className + ".c";
|
||||
|
||||
// if the partial temp path appears in the error message...
|
||||
//
|
||||
int partialStartIndex = s.indexOf(partialTempPath);
|
||||
//System.out.println(partialStartIndex);
|
||||
if (partialStartIndex != -1) {
|
||||
|
||||
// skip past the path and parse the int after the first colon
|
||||
//
|
||||
String s1 = s.substring(partialStartIndex + partialTempPath.length()
|
||||
+ 1);
|
||||
int colon = s1.indexOf(':');
|
||||
int lineNumber = Integer.parseInt(s1.substring(0, colon));
|
||||
//System.out.println("pde / line number: " + lineNumber);
|
||||
|
||||
//String s2 = s1.substring(colon + 2);
|
||||
int err = s1.indexOf("Error:");
|
||||
if (err != -1) {
|
||||
|
||||
// if the first error has already been found, then this must be
|
||||
// (at least) the second error found
|
||||
if (firstErrorFound) {
|
||||
secondErrorFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're here at all, this is at least the first error
|
||||
firstErrorFound = true;
|
||||
|
||||
//err += "error:".length();
|
||||
String description = s1.substring(err + "Error:".length());
|
||||
description = description.trim();
|
||||
//System.out.println("description = " + description);
|
||||
exception = new RunnerException(description, lineNumber-1);
|
||||
//editor.error(exception);
|
||||
|
||||
} else {
|
||||
System.err.println("i suck: " + s);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// this isn't the start of an error line, so don't attempt to parse
|
||||
// a line number out of it.
|
||||
|
||||
// if we're not yet at the second error, these lines are probably
|
||||
// associated with the first error message, which is already in the
|
||||
// status bar, and are likely to be of interest to the user, so
|
||||
// spit them to the console.
|
||||
//
|
||||
if (!secondErrorFound) {
|
||||
System.err.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
1903
app/Editor.java
Normal file
1903
app/Editor.java
Normal file
File diff suppressed because it is too large
Load Diff
404
app/EditorButtons.java
Normal file
404
app/EditorButtons.java
Normal file
@ -0,0 +1,404 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.font.*;
|
||||
import java.awt.geom.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
|
||||
/**
|
||||
* run/stop/etc buttons for the ide
|
||||
*/
|
||||
public class EditorButtons extends JComponent implements MouseInputListener {
|
||||
|
||||
static final String title[] = {
|
||||
"Compile", "Stop", "New", "Open", "Save", "Export"
|
||||
};
|
||||
|
||||
static final int BUTTON_COUNT = title.length;
|
||||
static final int BUTTON_WIDTH = 27; //Preferences.GRID_SIZE;
|
||||
static final int BUTTON_HEIGHT = 32; //Preferences.GRID_SIZE;
|
||||
static final int BUTTON_GAP = 15; //BUTTON_WIDTH / 2;
|
||||
|
||||
static final int RUN = 0;
|
||||
static final int STOP = 1;
|
||||
|
||||
static final int NEW = 2;
|
||||
static final int OPEN = 3;
|
||||
static final int SAVE = 4;
|
||||
static final int EXPORT = 5;
|
||||
|
||||
static final int INACTIVE = 0;
|
||||
static final int ROLLOVER = 1;
|
||||
static final int ACTIVE = 2;
|
||||
|
||||
Editor editor;
|
||||
boolean disableRun;
|
||||
//Label status;
|
||||
|
||||
Image offscreen;
|
||||
int width, height;
|
||||
|
||||
Color bgcolor;
|
||||
|
||||
Image buttons;
|
||||
Image inactive[];
|
||||
Image rollover[];
|
||||
Image active[];
|
||||
int currentRollover;
|
||||
int currentSelection;
|
||||
|
||||
JPopupMenu popup;
|
||||
|
||||
int buttonCount;
|
||||
int state[] = new int[BUTTON_COUNT];
|
||||
Image stateImage[];
|
||||
int which[]; // mapping indices to implementation
|
||||
|
||||
int x1[], x2[];
|
||||
int y1, y2;
|
||||
|
||||
String status;
|
||||
Font statusFont;
|
||||
Color statusColor;
|
||||
//int statusY;
|
||||
|
||||
|
||||
public EditorButtons(Editor editor) {
|
||||
this.editor = editor;
|
||||
buttons = Base.getImage("buttons.gif", this);
|
||||
|
||||
buttonCount = 0;
|
||||
which = new int[BUTTON_COUNT];
|
||||
|
||||
//which[buttonCount++] = NOTHING;
|
||||
which[buttonCount++] = RUN;
|
||||
which[buttonCount++] = STOP;
|
||||
which[buttonCount++] = NEW;
|
||||
which[buttonCount++] = OPEN;
|
||||
which[buttonCount++] = SAVE;
|
||||
which[buttonCount++] = EXPORT;
|
||||
|
||||
currentRollover = -1;
|
||||
|
||||
bgcolor = Preferences.getColor("buttons.bgcolor");
|
||||
|
||||
status = "";
|
||||
|
||||
statusFont = Preferences.getFont("buttons.status.font");
|
||||
statusColor = Preferences.getColor("buttons.status.color");
|
||||
|
||||
//statusY = (BUTTON_COUNT + 1) * BUTTON_HEIGHT;
|
||||
|
||||
addMouseListener(this);
|
||||
addMouseMotionListener(this);
|
||||
}
|
||||
|
||||
|
||||
public void paintComponent(Graphics screen) {
|
||||
if (inactive == null) {
|
||||
inactive = new Image[BUTTON_COUNT];
|
||||
rollover = new Image[BUTTON_COUNT];
|
||||
active = new Image[BUTTON_COUNT];
|
||||
|
||||
int IMAGE_SIZE = 33;
|
||||
|
||||
for (int i = 0; i < BUTTON_COUNT; i++) {
|
||||
inactive[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
Graphics g = inactive[i].getGraphics();
|
||||
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -2*IMAGE_SIZE, null);
|
||||
|
||||
rollover[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
g = rollover[i].getGraphics();
|
||||
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -1*IMAGE_SIZE, null);
|
||||
|
||||
active[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
g = active[i].getGraphics();
|
||||
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -0*IMAGE_SIZE, null);
|
||||
}
|
||||
|
||||
state = new int[buttonCount];
|
||||
stateImage = new Image[buttonCount];
|
||||
for (int i = 0; i < buttonCount; i++) {
|
||||
setState(i, INACTIVE, false);
|
||||
}
|
||||
}
|
||||
Dimension size = size();
|
||||
if ((offscreen == null) ||
|
||||
(size.width != width) || (size.height != height)) {
|
||||
offscreen = createImage(size.width, size.height);
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
|
||||
y1 = 0;
|
||||
y2 = BUTTON_HEIGHT;
|
||||
|
||||
x1 = new int[buttonCount];
|
||||
x2 = new int[buttonCount];
|
||||
|
||||
int offsetX = 3;
|
||||
for (int i = 0; i < buttonCount; i++) {
|
||||
x1[i] = offsetX;
|
||||
if (i == 2) x1[i] += BUTTON_GAP;
|
||||
x2[i] = x1[i] + BUTTON_WIDTH;
|
||||
offsetX = x2[i];
|
||||
}
|
||||
}
|
||||
Graphics g = offscreen.getGraphics();
|
||||
g.setColor(bgcolor); //getBackground());
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
for (int i = 0; i < buttonCount; i++) {
|
||||
g.drawImage(stateImage[i], x1[i], y1, null);
|
||||
}
|
||||
|
||||
g.setColor(statusColor);
|
||||
g.setFont(statusFont);
|
||||
|
||||
/*
|
||||
// if i ever find the guy who wrote the java2d api, i will hurt him.
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
FontRenderContext frc = g2.getFontRenderContext();
|
||||
float statusW = (float) statusFont.getStringBounds(status, frc).getWidth();
|
||||
float statusX = (getSize().width - statusW) / 2;
|
||||
g2.drawString(status, statusX, statusY);
|
||||
*/
|
||||
//int statusY = (BUTTON_HEIGHT + statusFont.getAscent()) / 2;
|
||||
int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
|
||||
g.drawString(status, buttonCount * BUTTON_WIDTH + 2 * BUTTON_GAP, statusY);
|
||||
|
||||
screen.drawImage(offscreen, 0, 0, null);
|
||||
}
|
||||
|
||||
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
// mouse events before paint();
|
||||
if (state == null) return;
|
||||
|
||||
if (state[OPEN] != INACTIVE) {
|
||||
// avoid flicker, since there will probably be an update event
|
||||
setState(OPEN, INACTIVE, false);
|
||||
}
|
||||
//System.out.println(e);
|
||||
//mouseMove(e);
|
||||
handleMouse(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
|
||||
public void mouseDragged(MouseEvent e) { }
|
||||
|
||||
|
||||
public void handleMouse(int x, int y) {
|
||||
if (currentRollover != -1) {
|
||||
if ((x > x1[currentRollover]) && (y > y1) &&
|
||||
(x < x2[currentRollover]) && (y < y2)) {
|
||||
return;
|
||||
|
||||
} else {
|
||||
setState(currentRollover, INACTIVE, true);
|
||||
messageClear(title[currentRollover]);
|
||||
currentRollover = -1;
|
||||
}
|
||||
}
|
||||
int sel = findSelection(x, y);
|
||||
if (sel == -1) return;
|
||||
|
||||
if (state[sel] != ACTIVE) {
|
||||
if (!(disableRun && ((sel == RUN) || (sel == STOP)))) {
|
||||
setState(sel, ROLLOVER, true);
|
||||
currentRollover = sel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int findSelection(int x, int y) {
|
||||
// if app loads slowly and cursor is near the buttons
|
||||
// when it comes up, the app may not have time to load
|
||||
if ((x1 == null) || (x2 == null)) return -1;
|
||||
|
||||
for (int i = 0; i < buttonCount; i++) {
|
||||
if ((y > y1) && (x > x1[i]) &&
|
||||
(y < y2) && (x < x2[i])) {
|
||||
//System.out.println("sel is " + i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private void setState(int slot, int newState, boolean updateAfter) {
|
||||
//if (inactive == null) return;
|
||||
state[slot] = newState;
|
||||
switch (newState) {
|
||||
case INACTIVE:
|
||||
stateImage[slot] = inactive[which[slot]];
|
||||
break;
|
||||
case ACTIVE:
|
||||
stateImage[slot] = active[which[slot]];
|
||||
break;
|
||||
case ROLLOVER:
|
||||
stateImage[slot] = rollover[which[slot]];
|
||||
message(title[which[slot]]);
|
||||
break;
|
||||
}
|
||||
if (updateAfter) repaint(); // changed for swing from update();
|
||||
}
|
||||
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
//mouseMove(e);
|
||||
handleMouse(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
if (state[OPEN] != INACTIVE) {
|
||||
setState(OPEN, INACTIVE, true);
|
||||
}
|
||||
status = "";
|
||||
handleMouse(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
int wasDown = -1;
|
||||
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int sel = findSelection(x, y);
|
||||
///if (sel == -1) return false;
|
||||
if (sel == -1) return;
|
||||
currentRollover = -1;
|
||||
currentSelection = sel;
|
||||
if (!(disableRun && ((sel == RUN) || (sel == STOP)))) {
|
||||
setState(sel, ACTIVE, true);
|
||||
}
|
||||
|
||||
if (currentSelection == OPEN) {
|
||||
if (popup == null) {
|
||||
//popup = new JPopupMenu();
|
||||
popup = editor.sketchbook.getPopupMenu();
|
||||
add(popup);
|
||||
}
|
||||
//editor.sketchbook.rebuildPopup(popup);
|
||||
popup.show(this, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mouseClicked(MouseEvent e) { }
|
||||
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
switch (currentSelection) {
|
||||
case RUN:
|
||||
if (!disableRun) {
|
||||
editor.handleRun(e.isShiftDown());
|
||||
}
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
if (!disableRun) {
|
||||
setState(RUN, INACTIVE, true);
|
||||
editor.handleStop();
|
||||
}
|
||||
break;
|
||||
|
||||
case OPEN: setState(OPEN, INACTIVE, true); break;
|
||||
case NEW: editor.handleNew(e.isShiftDown()); break;
|
||||
case SAVE: editor.handleSave(); break;
|
||||
case EXPORT: editor.handleExport(); break;
|
||||
}
|
||||
currentSelection = -1;
|
||||
}
|
||||
|
||||
|
||||
public void disableRun(boolean what) {
|
||||
disableRun = what;
|
||||
}
|
||||
|
||||
|
||||
public void clear() { // (int button) {
|
||||
if (inactive == null) return;
|
||||
|
||||
// skip the run button, do the others
|
||||
for (int i = 1; i < buttonCount; i++) {
|
||||
setState(i, INACTIVE, false);
|
||||
}
|
||||
repaint(); // changed for swing from update();
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
if (inactive == null) return;
|
||||
clear();
|
||||
setState(RUN, ACTIVE, true);
|
||||
}
|
||||
|
||||
|
||||
public void running(boolean yesno) {
|
||||
setState(RUN, yesno ? ACTIVE : INACTIVE, true);
|
||||
}
|
||||
|
||||
|
||||
public void clearRun() {
|
||||
if (inactive == null) return;
|
||||
setState(RUN, INACTIVE, true);
|
||||
}
|
||||
|
||||
|
||||
public void message(String msg) {
|
||||
//status.setText(msg + " "); // don't mind the hack
|
||||
status = msg;
|
||||
}
|
||||
|
||||
|
||||
public void messageClear(String msg) {
|
||||
//if (status.getText().equals(msg + " ")) status.setText(Editor.EMPTY);
|
||||
if (status.equals(msg)) status = "";
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension((BUTTON_COUNT + 1)*BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
//return new Dimension(BUTTON_WIDTH, (BUTTON_COUNT + 1)*BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(3000, BUTTON_HEIGHT);
|
||||
}
|
||||
}
|
334
app/EditorConsole.java
Normal file
334
app/EditorConsole.java
Normal file
@ -0,0 +1,334 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
|
||||
/**
|
||||
* Message console that sits below the editing area.
|
||||
* <P>
|
||||
* Debugging this class is tricky... If it's throwing exceptions,
|
||||
* don't take over System.err, and debug while watching just System.out
|
||||
* or just write println() or whatever directly to systemOut or systemErr.
|
||||
*/
|
||||
public class EditorConsole extends JScrollPane {
|
||||
Editor editor;
|
||||
|
||||
JTextPane consoleTextPane;
|
||||
StyledDocument consoleDoc;
|
||||
|
||||
MutableAttributeSet stdStyle;
|
||||
MutableAttributeSet errStyle;
|
||||
|
||||
boolean cerror;
|
||||
|
||||
//int maxCharCount;
|
||||
int maxLineCount;
|
||||
|
||||
static PrintStream systemOut;
|
||||
static PrintStream systemErr;
|
||||
|
||||
static PrintStream consoleOut;
|
||||
static PrintStream consoleErr;
|
||||
|
||||
static OutputStream stdoutFile;
|
||||
static OutputStream stderrFile;
|
||||
|
||||
|
||||
public EditorConsole(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
maxLineCount = Preferences.getInteger("console.length");
|
||||
|
||||
consoleTextPane = new JTextPane();
|
||||
consoleTextPane.setEditable(false);
|
||||
consoleDoc = consoleTextPane.getStyledDocument();
|
||||
|
||||
// necessary?
|
||||
MutableAttributeSet standard = new SimpleAttributeSet();
|
||||
StyleConstants.setAlignment(standard, StyleConstants.ALIGN_LEFT);
|
||||
consoleDoc.setParagraphAttributes(0, 0, standard, true);
|
||||
|
||||
// build styles for different types of console output
|
||||
Color bgColor = Preferences.getColor("console.color");
|
||||
Color fgColorOut = Preferences.getColor("console.output.color");
|
||||
Color fgColorErr = Preferences.getColor("console.error.color");
|
||||
Font font = Preferences.getFont("console.font");
|
||||
|
||||
stdStyle = new SimpleAttributeSet();
|
||||
StyleConstants.setForeground(stdStyle, fgColorOut);
|
||||
StyleConstants.setBackground(stdStyle, bgColor);
|
||||
StyleConstants.setFontSize(stdStyle, font.getSize());
|
||||
StyleConstants.setFontFamily(stdStyle, font.getFamily());
|
||||
StyleConstants.setBold(stdStyle, font.isBold());
|
||||
StyleConstants.setItalic(stdStyle, font.isItalic());
|
||||
|
||||
errStyle = new SimpleAttributeSet();
|
||||
StyleConstants.setForeground(errStyle, fgColorErr);
|
||||
StyleConstants.setBackground(errStyle, bgColor);
|
||||
StyleConstants.setFontSize(errStyle, font.getSize());
|
||||
StyleConstants.setFontFamily(errStyle, font.getFamily());
|
||||
StyleConstants.setBold(errStyle, font.isBold());
|
||||
StyleConstants.setItalic(errStyle, font.isItalic());
|
||||
|
||||
consoleTextPane.setBackground(bgColor);
|
||||
|
||||
// add the jtextpane to this scrollpane
|
||||
this.setViewportView(consoleTextPane);
|
||||
|
||||
// calculate height of a line of text in pixels
|
||||
// and size window accordingly
|
||||
FontMetrics metrics = this.getFontMetrics(font);
|
||||
int height = metrics.getAscent() + metrics.getDescent();
|
||||
int lines = Preferences.getInteger("console.lines"); //, 4);
|
||||
int sizeFudge = 6; //10; // unclear why this is necessary, but it is
|
||||
setPreferredSize(new Dimension(1024, (height * lines) + sizeFudge));
|
||||
setMinimumSize(new Dimension(1024, (height * 4) + sizeFudge));
|
||||
|
||||
if (systemOut == null) {
|
||||
systemOut = System.out;
|
||||
systemErr = System.err;
|
||||
|
||||
try {
|
||||
String outFileName = Preferences.get("console.output.file");
|
||||
if (outFileName != null) {
|
||||
stdoutFile = new FileOutputStream(outFileName);
|
||||
}
|
||||
|
||||
String errFileName = Preferences.get("console.error.file");
|
||||
if (errFileName != null) {
|
||||
stderrFile = new FileOutputStream(outFileName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Base.showWarning("Console Error",
|
||||
"A problem occurred while trying to open the\n" +
|
||||
"files used to store the console output.", e);
|
||||
}
|
||||
|
||||
consoleOut =
|
||||
new PrintStream(new EditorConsoleStream(this, false, stdoutFile));
|
||||
consoleErr =
|
||||
new PrintStream(new EditorConsoleStream(this, true, stderrFile));
|
||||
|
||||
if (Preferences.getBoolean("console")) {
|
||||
try {
|
||||
System.setOut(consoleOut);
|
||||
System.setErr(consoleErr);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(systemOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||
// ugly white border around this object, so turn it off.
|
||||
if (Base.isMacOS()) {
|
||||
setBorder(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(byte b[], int offset, int length, boolean err) {
|
||||
if (err != cerror) {
|
||||
// advance the line because switching between err/out streams
|
||||
// potentially, could check whether we're already on a new line
|
||||
message("", cerror, true);
|
||||
}
|
||||
|
||||
// we could do some cross platform CR/LF mangling here before outputting
|
||||
|
||||
// add text to output document
|
||||
message(new String(b, offset, length), err, false);
|
||||
// set last error state
|
||||
cerror = err;
|
||||
}
|
||||
|
||||
|
||||
// added sync for 0091.. not sure if it helps or hinders
|
||||
synchronized public void message(String what, boolean err, boolean advance) {
|
||||
if (err) {
|
||||
systemErr.print(what);
|
||||
//systemErr.print("CE" + what);
|
||||
} else {
|
||||
systemOut.print(what);
|
||||
//systemOut.print("CO" + what);
|
||||
}
|
||||
|
||||
if (advance) {
|
||||
appendText("\n", err);
|
||||
if (err) {
|
||||
systemErr.println();
|
||||
} else {
|
||||
systemOut.println();
|
||||
}
|
||||
}
|
||||
|
||||
// to console display
|
||||
appendText(what, err);
|
||||
// moved down here since something is punting
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* append a piece of text to the console.
|
||||
* <P>
|
||||
* Swing components are NOT thread-safe, and since the MessageSiphon
|
||||
* instantiates new threads, and in those callbacks, they often print
|
||||
* output to stdout and stderr, which are wrapped by EditorConsoleStream
|
||||
* and eventually leads to EditorConsole.appendText(), which directly
|
||||
* updates the Swing text components, causing deadlock.
|
||||
* <P>
|
||||
* A quick hack from Francis Li (who found this to be a problem)
|
||||
* wraps the contents of appendText() into a Runnable and uses
|
||||
* SwingUtilities.invokeLater() to ensure that the updates only
|
||||
* occur on the main event dispatching thread, and that appears
|
||||
* to have solved the problem.
|
||||
* <P>
|
||||
* unfortunately this is probably extremely slow and helping cause
|
||||
* some of the general print() and println() mess.. need to fix
|
||||
* up so that it's using a proper queue instead.
|
||||
*/
|
||||
synchronized private void appendText(String txt, boolean e) {
|
||||
final String text = txt;
|
||||
final boolean err = e;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// check how many lines have been used so far
|
||||
// if too many, shave off a few lines from the beginning
|
||||
Element element = consoleDoc.getDefaultRootElement();
|
||||
int lineCount = element.getElementCount();
|
||||
int overage = lineCount - maxLineCount;
|
||||
if (overage > 0) {
|
||||
// if 1200 lines, and 1000 lines is max,
|
||||
// find the position of the end of the 200th line
|
||||
//systemOut.println("overage is " + overage);
|
||||
Element lineElement = element.getElement(overage);
|
||||
if (lineElement == null) return; // do nuthin
|
||||
|
||||
int endOffset = lineElement.getEndOffset();
|
||||
// remove to the end of the 200th line
|
||||
consoleDoc.remove(0, endOffset);
|
||||
}
|
||||
|
||||
// make sure this line doesn't go over 32k chars
|
||||
lineCount = element.getElementCount(); // may have changed
|
||||
Element currentElement = element.getElement(lineCount-1);
|
||||
int currentStart = currentElement.getStartOffset();
|
||||
int currentEnd = currentElement.getEndOffset();
|
||||
//systemOut.println(currentEnd - currentStart);
|
||||
if (currentEnd - currentStart > 10000) { // force a newline
|
||||
consoleDoc.insertString(consoleDoc.getLength(), "\n",
|
||||
err ? errStyle : stdStyle);
|
||||
}
|
||||
|
||||
// add the text to the end of the console,
|
||||
consoleDoc.insertString(consoleDoc.getLength(), text,
|
||||
err ? errStyle : stdStyle);
|
||||
|
||||
// always move to the end of the text as it's added
|
||||
consoleTextPane.setCaretPosition(consoleDoc.getLength());
|
||||
|
||||
} catch (BadLocationException e) {
|
||||
// ignore the error otherwise this will cause an infinite loop
|
||||
// maybe not a good idea in the long run?
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
try {
|
||||
consoleDoc.remove(0, consoleDoc.getLength());
|
||||
} catch (BadLocationException e) {
|
||||
// ignore the error otherwise this will cause an infinite loop
|
||||
// maybe not a good idea in the long run?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class EditorConsoleStream extends OutputStream {
|
||||
EditorConsole parent;
|
||||
boolean err; // whether stderr or stdout
|
||||
byte single[] = new byte[1];
|
||||
OutputStream echo;
|
||||
|
||||
public EditorConsoleStream(EditorConsole parent,
|
||||
boolean err, OutputStream echo) {
|
||||
this.parent = parent;
|
||||
this.err = err;
|
||||
this.echo = echo;
|
||||
}
|
||||
|
||||
public void close() { }
|
||||
|
||||
public void flush() { }
|
||||
|
||||
public void write(byte b[]) { // appears never to be used
|
||||
parent.write(b, 0, b.length, err);
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b); //, 0, b.length);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(byte b[], int offset, int length) {
|
||||
parent.write(b, offset, length, err);
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b, offset, length);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
single[0] = (byte)b;
|
||||
parent.write(single, 0, 1, err);
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
389
app/EditorHeader.java
Normal file
389
app/EditorHeader.java
Normal file
@ -0,0 +1,389 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
|
||||
/**
|
||||
* Sketch tabs at the top of the editor window.
|
||||
*/
|
||||
public class EditorHeader extends JComponent {
|
||||
static Color backgroundColor;
|
||||
static Color textColor[] = new Color[2];
|
||||
|
||||
Editor editor;
|
||||
|
||||
int tabLeft[];
|
||||
int tabRight[];
|
||||
|
||||
Font font;
|
||||
FontMetrics metrics;
|
||||
int fontAscent;
|
||||
|
||||
JMenu menu;
|
||||
JPopupMenu popup;
|
||||
|
||||
JMenuItem hideItem;
|
||||
|
||||
int menuLeft;
|
||||
int menuRight;
|
||||
|
||||
//
|
||||
|
||||
static final String STATUS[] = { "unsel", "sel" };
|
||||
static final int UNSELECTED = 0;
|
||||
static final int SELECTED = 1;
|
||||
|
||||
static final String WHERE[] = { "left", "mid", "right", "menu" };
|
||||
static final int LEFT = 0;
|
||||
static final int MIDDLE = 1;
|
||||
static final int RIGHT = 2;
|
||||
static final int MENU = 3;
|
||||
|
||||
static final int PIECE_WIDTH = 4;
|
||||
|
||||
Image[][] pieces;
|
||||
|
||||
//
|
||||
|
||||
Image offscreen;
|
||||
int sizeW, sizeH;
|
||||
int imageW, imageH;
|
||||
|
||||
|
||||
public EditorHeader(Editor eddie) {
|
||||
this.editor = eddie; // weird name for listener
|
||||
|
||||
pieces = new Image[STATUS.length][WHERE.length];
|
||||
for (int i = 0; i < STATUS.length; i++) {
|
||||
for (int j = 0; j < WHERE.length; j++) {
|
||||
pieces[i][j] = Base.getImage("tab-" + STATUS[i] + "-" +
|
||||
WHERE[j] + ".gif", this);
|
||||
}
|
||||
}
|
||||
|
||||
if (backgroundColor == null) {
|
||||
backgroundColor =
|
||||
Preferences.getColor("header.bgcolor");
|
||||
textColor[SELECTED] =
|
||||
Preferences.getColor("header.text.selected.color");
|
||||
textColor[UNSELECTED] =
|
||||
Preferences.getColor("header.text.unselected.color");
|
||||
}
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
if ((x > menuLeft) && (x < menuRight)) {
|
||||
popup.show(EditorHeader.this, x, y);
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < editor.sketch.codeCount; i++) {
|
||||
if ((x > tabLeft[i]) && (x < tabRight[i])) {
|
||||
editor.sketch.setCurrent(i);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void paintComponent(Graphics screen) {
|
||||
if (screen == null) return;
|
||||
|
||||
Sketch sketch = editor.sketch;
|
||||
if (sketch == null) return; // ??
|
||||
|
||||
Dimension size = getSize();
|
||||
if ((size.width != sizeW) || (size.height != sizeH)) {
|
||||
// component has been resized
|
||||
|
||||
if ((size.width > imageW) || (size.height > imageH)) {
|
||||
// nix the image and recreate, it's too small
|
||||
offscreen = null;
|
||||
|
||||
} else {
|
||||
// who cares, just resize
|
||||
sizeW = size.width;
|
||||
sizeH = size.height;
|
||||
//userLeft = 0; // reset
|
||||
}
|
||||
}
|
||||
|
||||
if (offscreen == null) {
|
||||
sizeW = size.width;
|
||||
sizeH = size.height;
|
||||
imageW = sizeW;
|
||||
imageH = sizeH;
|
||||
offscreen = createImage(imageW, imageH);
|
||||
}
|
||||
|
||||
Graphics g = offscreen.getGraphics();
|
||||
if (font == null) {
|
||||
font = Preferences.getFont("header.text.font");
|
||||
}
|
||||
g.setFont(font); // need to set this each time through
|
||||
metrics = g.getFontMetrics();
|
||||
fontAscent = metrics.getAscent();
|
||||
//}
|
||||
|
||||
//Graphics2D g2 = (Graphics2D) g;
|
||||
//g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
// RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
// set the background for the offscreen
|
||||
g.setColor(backgroundColor);
|
||||
g.fillRect(0, 0, imageW, imageH);
|
||||
|
||||
if ((tabLeft == null) ||
|
||||
(tabLeft.length < sketch.codeCount)) {
|
||||
tabLeft = new int[sketch.codeCount];
|
||||
tabRight = new int[sketch.codeCount];
|
||||
}
|
||||
|
||||
// disable hide on the first tab
|
||||
hideItem.setEnabled(sketch.current != sketch.code[0]);
|
||||
|
||||
//int x = 0; //Preferences.GUI_SMALL;
|
||||
//int x = (Base.platform == Base.MACOSX) ? 0 : 1;
|
||||
int x = 6; // offset from left edge of the component
|
||||
for (int i = 0; i < sketch.codeCount; i++) {
|
||||
SketchCode code = sketch.code[i];
|
||||
|
||||
String codeName = (code.flavor == Sketch.PDE) ?
|
||||
code.name : code.file.getName();
|
||||
|
||||
// if modified, add the li'l glyph next to the name
|
||||
String text = " " + codeName + (code.modified ? " \u00A7" : " ");
|
||||
|
||||
//int textWidth = metrics.stringWidth(text);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
int textWidth = (int)
|
||||
font.getStringBounds(text, g2.getFontRenderContext()).getWidth();
|
||||
|
||||
int pieceCount = 2 + (textWidth / PIECE_WIDTH);
|
||||
int pieceWidth = pieceCount * PIECE_WIDTH;
|
||||
|
||||
int state = (code == sketch.current) ? SELECTED : UNSELECTED;
|
||||
g.drawImage(pieces[state][LEFT], x, 0, null);
|
||||
x += PIECE_WIDTH;
|
||||
|
||||
int contentLeft = x;
|
||||
tabLeft[i] = x;
|
||||
for (int j = 0; j < pieceCount; j++) {
|
||||
g.drawImage(pieces[state][MIDDLE], x, 0, null);
|
||||
x += PIECE_WIDTH;
|
||||
}
|
||||
tabRight[i] = x;
|
||||
int textLeft = contentLeft + (pieceWidth - textWidth) / 2;
|
||||
|
||||
g.setColor(textColor[state]);
|
||||
int baseline = (sizeH + fontAscent) / 2;
|
||||
//g.drawString(sketch.code[i].name, textLeft, baseline);
|
||||
g.drawString(text, textLeft, baseline);
|
||||
|
||||
g.drawImage(pieces[state][RIGHT], x, 0, null);
|
||||
x += PIECE_WIDTH - 1; // overlap by 1 pixel
|
||||
}
|
||||
|
||||
menuLeft = sizeW - (16 + pieces[0][MENU].getWidth(this));
|
||||
menuRight = sizeW - 16;
|
||||
// draw the dropdown menu target
|
||||
g.drawImage(pieces[popup.isVisible() ? SELECTED : UNSELECTED][MENU],
|
||||
menuLeft, 0, null);
|
||||
|
||||
screen.drawImage(offscreen, 0, 0, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when a new sketch is opened.
|
||||
*/
|
||||
public void rebuild() {
|
||||
//System.out.println("rebuilding editor header");
|
||||
rebuildMenu();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void rebuildMenu() {
|
||||
if (menu != null) {
|
||||
menu.removeAll();
|
||||
|
||||
} else {
|
||||
menu = new JMenu();
|
||||
popup = menu.getPopupMenu();
|
||||
add(popup);
|
||||
popup.addPopupMenuListener(new PopupMenuListener() {
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
// on redraw, the isVisible() will get checked.
|
||||
// actually, a repaint may be fired anyway, so this
|
||||
// may be redundant.
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
|
||||
});
|
||||
}
|
||||
JMenuItem item;
|
||||
|
||||
// maybe this shouldn't have a command key anyways..
|
||||
// since we're not trying to make this a full ide..
|
||||
//item = Editor.newJMenuItem("New", 'T');
|
||||
|
||||
/*
|
||||
item = Editor.newJMenuItem("Previous", KeyEvent.VK_PAGE_UP);
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.out.println("prev");
|
||||
}
|
||||
});
|
||||
if (editor.sketch != null) {
|
||||
item.setEnabled(editor.sketch.codeCount > 1);
|
||||
}
|
||||
menu.add(item);
|
||||
|
||||
item = Editor.newJMenuItem("Next", KeyEvent.VK_PAGE_DOWN);
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.out.println("ext");
|
||||
}
|
||||
});
|
||||
if (editor.sketch != null) {
|
||||
item.setEnabled(editor.sketch.codeCount > 1);
|
||||
}
|
||||
menu.add(item);
|
||||
|
||||
menu.addSeparator();
|
||||
*/
|
||||
|
||||
item = new JMenuItem("New Tab");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.newCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem("Rename");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.renameCode();
|
||||
if (editor.sketch.current == editor.sketch.code[0]) {
|
||||
editor.sketchbook.rebuildMenus();
|
||||
}
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem("Delete");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.deleteCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem("Hide");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.hideCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
hideItem = item;
|
||||
|
||||
JMenu unhide = new JMenu("Unhide");
|
||||
ActionListener unhideListener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String which = (String) e.getActionCommand();
|
||||
editor.sketch.unhideCode(which);
|
||||
rebuildMenu();
|
||||
}
|
||||
};
|
||||
Sketch sketch = editor.sketch;
|
||||
if (sketch != null) {
|
||||
for (int i = 0; i < sketch.hiddenCount; i++) {
|
||||
item = new JMenuItem(sketch.hidden[i].name);
|
||||
item.setActionCommand(sketch.hidden[i].name);
|
||||
item.addActionListener(unhideListener);
|
||||
unhide.add(item);
|
||||
}
|
||||
}
|
||||
if (unhide.getItemCount() == 0) {
|
||||
unhide.setEnabled(false);
|
||||
}
|
||||
|
||||
menu.add(unhide);
|
||||
|
||||
if (sketch != null) {
|
||||
menu.addSeparator();
|
||||
|
||||
ActionListener jumpListener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.setCurrent(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < sketch.codeCount; i++) {
|
||||
item = new JMenuItem(sketch.code[i].name);
|
||||
item.addActionListener(jumpListener);
|
||||
menu.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deselectMenu() {
|
||||
repaint();
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
if (Base.isMacOS()) {
|
||||
return new Dimension(300, Preferences.GRID_SIZE);
|
||||
}
|
||||
return new Dimension(300, Preferences.GRID_SIZE - 1);
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
if (Base.isMacOS()) {
|
||||
return new Dimension(3000, Preferences.GRID_SIZE);
|
||||
}
|
||||
return new Dimension(3000, Preferences.GRID_SIZE - 1);
|
||||
}
|
||||
}
|
119
app/EditorLineStatus.java
Normal file
119
app/EditorLineStatus.java
Normal file
@ -0,0 +1,119 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005 Ben Fry and Casey Reas
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.syntax.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
|
||||
/**
|
||||
* Li'l status bar fella that shows the line number.
|
||||
*/
|
||||
public class EditorLineStatus extends JComponent {
|
||||
JEditTextArea textarea;
|
||||
int start = -1, stop;
|
||||
|
||||
Image resize;
|
||||
|
||||
Color foreground;
|
||||
Color background;
|
||||
Font font;
|
||||
int high;
|
||||
|
||||
String text = "";
|
||||
|
||||
|
||||
public EditorLineStatus(JEditTextArea textarea) {
|
||||
this.textarea = textarea;
|
||||
textarea.editorLineStatus = this;
|
||||
|
||||
background = Preferences.getColor("linestatus.bgcolor");
|
||||
font = Preferences.getFont("linestatus.font");
|
||||
foreground = Preferences.getColor("linestatus.color");
|
||||
high = Preferences.getInteger("linestatus.height");
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
resize = Base.getImage("resize.gif", this);
|
||||
}
|
||||
//linestatus.bgcolor = #000000
|
||||
//linestatus.font = SansSerif,plain,10
|
||||
//linestatus.color = #FFFFFF
|
||||
}
|
||||
|
||||
|
||||
public void set(int newStart, int newStop) {
|
||||
if ((newStart == start) && (newStop == stop)) return;
|
||||
|
||||
start = newStart;
|
||||
stop = newStop;
|
||||
|
||||
/*
|
||||
if (start == stop) {
|
||||
text = "Line " + (start + 1);
|
||||
} else {
|
||||
text = "Lines " + (start + 1) + " to " + (stop + 1);
|
||||
}
|
||||
*/
|
||||
if (start == stop) {
|
||||
text = String.valueOf(start+1);
|
||||
} else {
|
||||
text = (start+1) + " - " + (stop+1);
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void paintComponent(Graphics g) {
|
||||
g.setColor(background);
|
||||
Dimension size = getSize();
|
||||
g.fillRect(0, 0, size.width, size.height);
|
||||
|
||||
g.setFont(font);
|
||||
g.setColor(foreground);
|
||||
int baseline = (high + g.getFontMetrics().getAscent()) / 2;
|
||||
g.drawString(text, 6, baseline);
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
g.drawImage(resize, size.width - 20, 0, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(300, high);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(3000, high);
|
||||
}
|
||||
}
|
172
app/EditorListener.java
Normal file
172
app/EditorListener.java
Normal file
@ -0,0 +1,172 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.syntax.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
|
||||
/**
|
||||
* Filters key events for tab expansion/indent/etc.
|
||||
*/
|
||||
public class EditorListener {
|
||||
Editor editor;
|
||||
JEditTextArea textarea;
|
||||
|
||||
boolean externalEditor;
|
||||
boolean expandTabs;
|
||||
String tabString;
|
||||
boolean autoIndent;
|
||||
|
||||
int selectionStart, selectionEnd;
|
||||
int position;
|
||||
|
||||
|
||||
public EditorListener(Editor editor, JEditTextArea textarea) {
|
||||
this.editor = editor;
|
||||
this.textarea = textarea;
|
||||
|
||||
// let him know that i'm leechin'
|
||||
textarea.editorListener = this;
|
||||
|
||||
applyPreferences();
|
||||
}
|
||||
|
||||
|
||||
public void applyPreferences() {
|
||||
expandTabs = Preferences.getBoolean("editor.tabs.expand");
|
||||
int tabSize = Preferences.getInteger("editor.tabs.size");
|
||||
tabString = Editor.EMPTY.substring(0, tabSize);
|
||||
autoIndent = Preferences.getBoolean("editor.indent");
|
||||
externalEditor = Preferences.getBoolean("editor.external");
|
||||
}
|
||||
|
||||
|
||||
//public void setExternalEditor(boolean externalEditor) {
|
||||
//this.externalEditor = externalEditor;
|
||||
//}
|
||||
|
||||
|
||||
// called by JEditTextArea inside processKeyEvent
|
||||
public boolean keyPressed(KeyEvent event) {
|
||||
// don't do things if the textarea isn't editable
|
||||
if (externalEditor) return false;
|
||||
|
||||
//deselect(); // this is for paren balancing
|
||||
char c = event.getKeyChar();
|
||||
int code = event.getKeyCode();
|
||||
|
||||
//System.out.println(c + " " + code + " " + event);
|
||||
//System.out.println();
|
||||
|
||||
if ((event.getModifiers() & KeyEvent.META_MASK) != 0) {
|
||||
//event.consume(); // does nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO i don't like these accessors. clean em up later.
|
||||
if (!editor.sketch.current.modified) {
|
||||
if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) ||
|
||||
(code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
|
||||
editor.sketch.setModified();
|
||||
}
|
||||
}
|
||||
|
||||
switch ((int) c) {
|
||||
|
||||
case 9: // expand tabs
|
||||
if (expandTabs) {
|
||||
//tc.replaceSelection(tabString);
|
||||
textarea.setSelectedText(tabString);
|
||||
event.consume();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10: // auto-indent
|
||||
case 13:
|
||||
if (autoIndent) {
|
||||
char contents[] = textarea.getText().toCharArray();
|
||||
|
||||
// this is the position of the caret, if the textarea
|
||||
// only used a single kind of line ending
|
||||
int origIndex = textarea.getCaretPosition() - 1;
|
||||
|
||||
// walk through the array to the current caret position,
|
||||
// and count how many weirdo windows line endings there are,
|
||||
// which would be throwing off the caret position number
|
||||
int offset = 0;
|
||||
int realIndex = origIndex;
|
||||
for (int i = 0; i < realIndex-1; i++) {
|
||||
if ((contents[i] == 13) && (contents[i+1] == 10)) {
|
||||
offset++;
|
||||
realIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// back up until \r \r\n or \n.. @#($* cross platform
|
||||
|
||||
//System.out.println(origIndex + " offset = " + offset);
|
||||
origIndex += offset; // ARGH!#(* WINDOWS#@($*
|
||||
|
||||
int index = origIndex;
|
||||
int spaceCount = 0;
|
||||
boolean finished = false;
|
||||
while ((index != -1) && (!finished)) {
|
||||
if ((contents[index] == 10) ||
|
||||
(contents[index] == 13)) {
|
||||
finished = true;
|
||||
index++; // maybe ?
|
||||
} else {
|
||||
index--; // new
|
||||
}
|
||||
}
|
||||
while ((index < contents.length) && (index >= 0) &&
|
||||
(contents[index++] == ' ')) {
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
// seems that \r is being inserted anyway
|
||||
// so no need to insert the platform's line separator
|
||||
String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
|
||||
//tc.replaceSelection(insertion);
|
||||
textarea.setSelectedText(insertion);
|
||||
// microsoft vm version:
|
||||
//tc.setCaretPosition(oldCarrot + insertion.length() - 1);
|
||||
// sun vm version:
|
||||
// tc.setCaretPosition(oldCarrot + insertion.length());
|
||||
event.consume();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
430
app/EditorStatus.java
Normal file
430
app/EditorStatus.java
Normal file
@ -0,0 +1,430 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
/**
|
||||
* Panel just below the editing area that contains status messages.
|
||||
*/
|
||||
public class EditorStatus extends JPanel implements ActionListener {
|
||||
static Color bgcolor[];
|
||||
static Color fgcolor[];
|
||||
|
||||
static final int NOTICE = 0;
|
||||
static final int ERR = 1;
|
||||
static final int PROMPT = 2;
|
||||
static final int EDIT = 3;
|
||||
|
||||
static final int YES = 1;
|
||||
static final int NO = 2;
|
||||
static final int CANCEL = 3;
|
||||
static final int OK = 4;
|
||||
|
||||
static final String NO_MESSAGE = "";
|
||||
|
||||
Editor editor;
|
||||
|
||||
int mode;
|
||||
String message;
|
||||
|
||||
Font font;
|
||||
FontMetrics metrics;
|
||||
int ascent;
|
||||
|
||||
Image offscreen;
|
||||
int sizeW, sizeH;
|
||||
int imageW, imageH;
|
||||
|
||||
JButton yesButton;
|
||||
JButton noButton;
|
||||
JButton cancelButton;
|
||||
JButton okButton;
|
||||
JTextField editField;
|
||||
|
||||
//Thread promptThread;
|
||||
int response;
|
||||
|
||||
|
||||
public EditorStatus(Editor editor) {
|
||||
this.editor = editor;
|
||||
empty();
|
||||
|
||||
if (bgcolor == null) {
|
||||
bgcolor = new Color[4];
|
||||
bgcolor[0] = Preferences.getColor("status.notice.bgcolor");
|
||||
bgcolor[1] = Preferences.getColor("status.error.bgcolor");
|
||||
bgcolor[2] = Preferences.getColor("status.prompt.bgcolor");
|
||||
bgcolor[3] = Preferences.getColor("status.prompt.bgcolor");
|
||||
|
||||
fgcolor = new Color[4];
|
||||
fgcolor[0] = Preferences.getColor("status.notice.fgcolor");
|
||||
fgcolor[1] = Preferences.getColor("status.error.fgcolor");
|
||||
fgcolor[2] = Preferences.getColor("status.prompt.fgcolor");
|
||||
fgcolor[3] = Preferences.getColor("status.prompt.fgcolor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void empty() {
|
||||
mode = NOTICE;
|
||||
message = NO_MESSAGE;
|
||||
//update();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void notice(String message) {
|
||||
mode = NOTICE;
|
||||
this.message = message;
|
||||
//update();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void unnotice(String unmessage) {
|
||||
if (message.equals(unmessage)) empty();
|
||||
}
|
||||
|
||||
|
||||
public void error(String message) {
|
||||
mode = ERR;
|
||||
this.message = message;
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void prompt(String message) {
|
||||
mode = PROMPT;
|
||||
this.message = message;
|
||||
|
||||
response = 0;
|
||||
yesButton.setVisible(true);
|
||||
noButton.setVisible(true);
|
||||
cancelButton.setVisible(true);
|
||||
yesButton.requestFocus();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
// prompt has been handled, re-hide the buttons
|
||||
public void unprompt() {
|
||||
yesButton.setVisible(false);
|
||||
noButton.setVisible(false);
|
||||
cancelButton.setVisible(false);
|
||||
empty();
|
||||
}
|
||||
|
||||
|
||||
public void edit(String message, String dflt) {
|
||||
mode = EDIT;
|
||||
this.message = message;
|
||||
|
||||
response = 0;
|
||||
okButton.setVisible(true);
|
||||
cancelButton.setVisible(true);
|
||||
editField.setVisible(true);
|
||||
editField.setText(dflt);
|
||||
editField.selectAll();
|
||||
editField.requestFocus();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void unedit() {
|
||||
okButton.setVisible(false);
|
||||
cancelButton.setVisible(false);
|
||||
editField.setVisible(false);
|
||||
empty();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public void update() {
|
||||
Graphics g = this.getGraphics();
|
||||
try {
|
||||
setBackground(bgcolor[mode]);
|
||||
} catch (NullPointerException e) { } // if not ready yet
|
||||
if (g != null) paint(g);
|
||||
}
|
||||
|
||||
public void update(Graphics g) {
|
||||
paint(g);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public void paintComponent(Graphics screen) {
|
||||
//if (screen == null) return;
|
||||
if (yesButton == null) setup();
|
||||
|
||||
//System.out.println("status.paintComponent");
|
||||
|
||||
Dimension size = getSize();
|
||||
if ((size.width != sizeW) || (size.height != sizeH)) {
|
||||
// component has been resized
|
||||
|
||||
if ((size.width > imageW) || (size.height > imageH)) {
|
||||
// nix the image and recreate, it's too small
|
||||
offscreen = null;
|
||||
|
||||
} else {
|
||||
// who cares, just resize
|
||||
sizeW = size.width;
|
||||
sizeH = size.height;
|
||||
setButtonBounds();
|
||||
}
|
||||
}
|
||||
|
||||
if (offscreen == null) {
|
||||
sizeW = size.width;
|
||||
sizeH = size.height;
|
||||
setButtonBounds();
|
||||
imageW = sizeW;
|
||||
imageH = sizeH;
|
||||
offscreen = createImage(imageW, imageH);
|
||||
}
|
||||
|
||||
Graphics g = offscreen.getGraphics();
|
||||
if (font == null) {
|
||||
font = Preferences.getFont("status.font");
|
||||
//new Font("SansSerif", Font.PLAIN, 12));
|
||||
g.setFont(font);
|
||||
metrics = g.getFontMetrics();
|
||||
ascent = metrics.getAscent();
|
||||
}
|
||||
|
||||
//setBackground(bgcolor[mode]); // does nothing
|
||||
|
||||
g.setColor(bgcolor[mode]);
|
||||
g.fillRect(0, 0, imageW, imageH);
|
||||
|
||||
g.setColor(fgcolor[mode]);
|
||||
g.setFont(font); // needs to be set each time on osx
|
||||
g.drawString(message, Preferences.GUI_SMALL, (sizeH + ascent) / 2);
|
||||
|
||||
screen.drawImage(offscreen, 0, 0, null);
|
||||
}
|
||||
|
||||
|
||||
protected void setup() {
|
||||
if (yesButton == null) {
|
||||
yesButton = new JButton(Preferences.PROMPT_YES);
|
||||
noButton = new JButton(Preferences.PROMPT_NO);
|
||||
cancelButton = new JButton(Preferences.PROMPT_CANCEL);
|
||||
okButton = new JButton(Preferences.PROMPT_OK);
|
||||
|
||||
// !@#(* aqua ui #($*(( that turtle-neck wearing #(** (#$@)(
|
||||
// os9 seems to work if bg of component is set, but x still a bastard
|
||||
if (Base.isMacOS()) {
|
||||
yesButton.setBackground(bgcolor[PROMPT]);
|
||||
noButton.setBackground(bgcolor[PROMPT]);
|
||||
cancelButton.setBackground(bgcolor[PROMPT]);
|
||||
okButton.setBackground(bgcolor[PROMPT]);
|
||||
}
|
||||
setLayout(null);
|
||||
|
||||
yesButton.addActionListener(this);
|
||||
noButton.addActionListener(this);
|
||||
cancelButton.addActionListener(this);
|
||||
okButton.addActionListener(this);
|
||||
|
||||
add(yesButton);
|
||||
add(noButton);
|
||||
add(cancelButton);
|
||||
add(okButton);
|
||||
|
||||
yesButton.setVisible(false);
|
||||
noButton.setVisible(false);
|
||||
cancelButton.setVisible(false);
|
||||
okButton.setVisible(false);
|
||||
|
||||
editField = new JTextField();
|
||||
editField.addActionListener(this);
|
||||
|
||||
//if (Base.platform != Base.MACOSX) {
|
||||
editField.addKeyListener(new KeyAdapter() {
|
||||
// no-op implemented because of a jikes bug
|
||||
//protected void noop() { }
|
||||
|
||||
//public void keyPressed(KeyEvent event) {
|
||||
//System.out.println("pressed " + event + " " + KeyEvent.VK_SPACE);
|
||||
//}
|
||||
|
||||
// use keyTyped to catch when the feller is actually
|
||||
// added to the text field. with keyTyped, as opposed to
|
||||
// keyPressed, the keyCode will be zero, even if it's
|
||||
// enter or backspace or whatever, so the keychar should
|
||||
// be used instead. grr.
|
||||
public void keyTyped(KeyEvent event) {
|
||||
//System.out.println("got event " + event + " " +
|
||||
// KeyEvent.VK_SPACE);
|
||||
int c = event.getKeyChar();
|
||||
|
||||
if (c == KeyEvent.VK_ENTER) { // accept the input
|
||||
String answer = editField.getText();
|
||||
editor.sketch.nameCode(answer);
|
||||
unedit();
|
||||
event.consume();
|
||||
|
||||
// easier to test the affirmative case than the negative
|
||||
} else if ((c == KeyEvent.VK_BACK_SPACE) ||
|
||||
(c == KeyEvent.VK_DELETE) ||
|
||||
(c == KeyEvent.VK_RIGHT) ||
|
||||
(c == KeyEvent.VK_LEFT) ||
|
||||
(c == KeyEvent.VK_UP) ||
|
||||
(c == KeyEvent.VK_DOWN) ||
|
||||
(c == KeyEvent.VK_HOME) ||
|
||||
(c == KeyEvent.VK_END) ||
|
||||
(c == KeyEvent.VK_SHIFT)) {
|
||||
//System.out.println("nothing to see here");
|
||||
//noop();
|
||||
|
||||
} else if (c == KeyEvent.VK_ESCAPE) {
|
||||
unedit();
|
||||
editor.buttons.clear();
|
||||
event.consume();
|
||||
|
||||
} else if (c == KeyEvent.VK_SPACE) {
|
||||
//System.out.println("got a space");
|
||||
// if a space, insert an underscore
|
||||
//editField.insert("_", editField.getCaretPosition());
|
||||
/* tried to play nice and see where it got me
|
||||
editField.dispatchEvent(new KeyEvent(editField,
|
||||
KeyEvent.KEY_PRESSED,
|
||||
System.currentTimeMillis(),
|
||||
0, 45, '_'));
|
||||
*/
|
||||
//System.out.println("start/end = " +
|
||||
// editField.getSelectionStart() + " " +
|
||||
// editField.getSelectionEnd());
|
||||
String t = editField.getText();
|
||||
//int p = editField.getCaretPosition();
|
||||
//editField.setText(t.substring(0, p) + "_" + t.substring(p));
|
||||
//editField.setCaretPosition(p+1);
|
||||
int start = editField.getSelectionStart();
|
||||
int end = editField.getSelectionEnd();
|
||||
editField.setText(t.substring(0, start) + "_" +
|
||||
t.substring(end));
|
||||
editField.setCaretPosition(start+1);
|
||||
//System.out.println("consuming event");
|
||||
event.consume();
|
||||
|
||||
} else if ((c == '_') || (c == '.') || // allow .pde and .java
|
||||
((c >= 'A') && (c <= 'Z')) ||
|
||||
((c >= 'a') && (c <= 'z'))) {
|
||||
// everything fine, catches upper and lower
|
||||
//noop();
|
||||
|
||||
} else if ((c >= '0') && (c <= '9')) {
|
||||
// getCaretPosition == 0 means that it's the first char
|
||||
// and the field is empty.
|
||||
// getSelectionStart means that it *will be* the first
|
||||
// char, because the selection is about to be replaced
|
||||
// with whatever is typed.
|
||||
if ((editField.getCaretPosition() == 0) ||
|
||||
(editField.getSelectionStart() == 0)) {
|
||||
// number not allowed as first digit
|
||||
//System.out.println("bad number bad");
|
||||
event.consume();
|
||||
}
|
||||
} else {
|
||||
event.consume();
|
||||
//System.out.println("code is " + code + " char = " + c);
|
||||
}
|
||||
//System.out.println("code is " + code + " char = " + c);
|
||||
}
|
||||
});
|
||||
add(editField);
|
||||
editField.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void setButtonBounds() {
|
||||
int top = (sizeH - Preferences.BUTTON_HEIGHT) / 2;
|
||||
int eachButton = Preferences.GUI_SMALL + Preferences.BUTTON_WIDTH;
|
||||
|
||||
int cancelLeft = sizeW - eachButton;
|
||||
int noLeft = cancelLeft - eachButton;
|
||||
int yesLeft = noLeft - eachButton;
|
||||
|
||||
yesButton.setLocation(yesLeft, top);
|
||||
noButton.setLocation(noLeft, top);
|
||||
cancelButton.setLocation(cancelLeft, top);
|
||||
editField.setLocation(yesLeft - Preferences.BUTTON_WIDTH, top);
|
||||
okButton.setLocation(noLeft, top);
|
||||
|
||||
yesButton.setSize( Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
|
||||
noButton.setSize( Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
|
||||
cancelButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
|
||||
okButton.setSize( Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
|
||||
editField.setSize( 2*Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(300, Preferences.GRID_SIZE);
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(3000, Preferences.GRID_SIZE);
|
||||
}
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getSource() == noButton) {
|
||||
// shut everything down, clear status, and return
|
||||
unprompt();
|
||||
// don't need to save changes
|
||||
editor.checkModified2();
|
||||
|
||||
} else if (e.getSource() == yesButton) {
|
||||
// answer was in response to "save changes?"
|
||||
unprompt();
|
||||
editor.handleSave();
|
||||
editor.checkModified2();
|
||||
|
||||
} else if (e.getSource() == cancelButton) {
|
||||
// don't do anything, don't continue with checkModified2
|
||||
if (mode == PROMPT) unprompt();
|
||||
else if (mode == EDIT) unedit();
|
||||
editor.buttons.clear();
|
||||
|
||||
} else if (e.getSource() == okButton) {
|
||||
// answering to "save as..." question
|
||||
String answer = editField.getText();
|
||||
//editor.handleSaveAs2(answer);
|
||||
editor.sketch.nameCode(answer);
|
||||
unedit();
|
||||
}
|
||||
}
|
||||
}
|
305
app/FindReplace.java
Normal file
305
app/FindReplace.java
Normal file
@ -0,0 +1,305 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
/**
|
||||
* Find & Replace window for the processing editor.
|
||||
*/
|
||||
public class FindReplace extends JFrame
|
||||
implements ActionListener, KeyListener {
|
||||
|
||||
static final int BIG = 13;
|
||||
static final int SMALL = 6;
|
||||
|
||||
Editor editor;
|
||||
|
||||
JTextField findField;
|
||||
JTextField replaceField;
|
||||
|
||||
JButton replaceButton;
|
||||
JButton replaceAllButton;
|
||||
JButton findButton;
|
||||
|
||||
JCheckBox ignoreCaseBox;
|
||||
boolean ignoreCase;
|
||||
|
||||
KeyStroke windowClose;
|
||||
|
||||
boolean found;
|
||||
|
||||
|
||||
public FindReplace(Editor editor) {
|
||||
super("Find");
|
||||
setResizable(false);
|
||||
this.editor = editor;
|
||||
|
||||
Container pain = getContentPane();
|
||||
pain.setLayout(null);
|
||||
|
||||
JLabel findLabel = new JLabel("Find:");
|
||||
Dimension d0 = findLabel.getPreferredSize();
|
||||
JLabel replaceLabel = new JLabel("Replace with:");
|
||||
Dimension d1 = replaceLabel.getPreferredSize();
|
||||
|
||||
pain.add(findLabel);
|
||||
pain.add(replaceLabel);
|
||||
|
||||
pain.add(findField = new JTextField(20));
|
||||
pain.add(replaceField = new JTextField(20));
|
||||
Dimension d2 = findField.getPreferredSize();
|
||||
|
||||
// +1 since it's better to tend downwards
|
||||
int yoff = (1 + d2.height - d1.height) / 2;
|
||||
|
||||
findLabel.setBounds(BIG + (d1.width-d0.width) + yoff, BIG,
|
||||
d1.width, d1.height);
|
||||
replaceLabel.setBounds(BIG, BIG + d2.height + SMALL + yoff,
|
||||
d1.width, d1.height);
|
||||
|
||||
ignoreCase = true;
|
||||
ignoreCaseBox = new JCheckBox("Ignore Case");
|
||||
ignoreCaseBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ignoreCase = ignoreCaseBox.isSelected();
|
||||
}
|
||||
});
|
||||
ignoreCaseBox.setSelected(ignoreCase);
|
||||
pain.add(ignoreCaseBox);
|
||||
|
||||
//
|
||||
|
||||
JPanel buttons = new JPanel();
|
||||
buttons.setLayout(new FlowLayout());
|
||||
|
||||
// ordering is different on mac versus pc
|
||||
if (Base.isMacOS()) {
|
||||
buttons.add(replaceButton = new JButton("Replace"));
|
||||
buttons.add(replaceAllButton = new JButton("Replace All"));
|
||||
buttons.add(findButton = new JButton("Find"));
|
||||
|
||||
} else {
|
||||
buttons.add(findButton = new JButton("Find"));
|
||||
buttons.add(replaceButton = new JButton("Replace"));
|
||||
buttons.add(replaceAllButton = new JButton("Replace All"));
|
||||
}
|
||||
pain.add(buttons);
|
||||
|
||||
// 0069 TEMPORARILY DISABLED!
|
||||
//replaceAllButton.setEnabled(false);
|
||||
|
||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||
// ugly white border around this object, so turn it off.
|
||||
//if (Base.platform == Base.MACOSX) {
|
||||
if (Base.isMacOS()) {
|
||||
buttons.setBorder(null);
|
||||
}
|
||||
|
||||
Dimension d3 = buttons.getPreferredSize();
|
||||
//buttons.setBounds(BIG, BIG + d2.height*2 + SMALL + BIG,
|
||||
buttons.setBounds(BIG, BIG + d2.height*3 + SMALL*2 + BIG,
|
||||
d3.width, d3.height);
|
||||
|
||||
//
|
||||
|
||||
findField.setBounds(BIG + d1.width + SMALL, BIG,
|
||||
d3.width - (d1.width + SMALL), d2.height);
|
||||
replaceField.setBounds(BIG + d1.width + SMALL, BIG + d2.height + SMALL,
|
||||
d3.width - (d1.width + SMALL), d2.height);
|
||||
|
||||
ignoreCaseBox.setBounds(BIG + d1.width + SMALL,
|
||||
BIG + d2.height*2 + SMALL*2,
|
||||
d3.width, d2.height);
|
||||
|
||||
//
|
||||
|
||||
replaceButton.addActionListener(this);
|
||||
replaceAllButton.addActionListener(this);
|
||||
findButton.addActionListener(this);
|
||||
|
||||
// you mustn't replace what you haven't found, my son
|
||||
replaceButton.setEnabled(false);
|
||||
|
||||
// so that typing will go straight to this field
|
||||
findField.requestFocus();
|
||||
|
||||
// make the find button the blinky default
|
||||
getRootPane().setDefaultButton(findButton);
|
||||
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
|
||||
int wide = d3.width + BIG*2;
|
||||
Rectangle butt = buttons.getBounds(); // how big is your butt?
|
||||
int high = butt.y + butt.height + BIG*2 + SMALL;
|
||||
|
||||
setBounds((screen.width - wide) / 2,
|
||||
(screen.height - high) / 2, wide, high);
|
||||
|
||||
// add key listener to trap esc and ctrl/cmd-w
|
||||
findField.addKeyListener(this);
|
||||
replaceField.addKeyListener(this);
|
||||
addKeyListener(this);
|
||||
|
||||
// hack to to get first field to focus properly on osx
|
||||
// though this still doesn't seem to work
|
||||
addWindowListener(new WindowAdapter() {
|
||||
public void windowActivated(WindowEvent e) {
|
||||
//System.out.println("activating");
|
||||
findField.requestFocus();
|
||||
findField.selectAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle window closing commands for ctrl/cmd-W or hitting ESC.
|
||||
*/
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (windowClose == null) {
|
||||
int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
windowClose = KeyStroke.getKeyStroke('W', modifiers);
|
||||
}
|
||||
if ((e.getKeyCode() == KeyEvent.VK_ESCAPE) ||
|
||||
(KeyStroke.getKeyStrokeForEvent(e).equals(windowClose))) {
|
||||
hide();
|
||||
//} else {
|
||||
//System.out.println("event " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public void keyReleased(KeyEvent e) { }
|
||||
|
||||
public void keyTyped(KeyEvent e) { }
|
||||
|
||||
|
||||
/*
|
||||
public void show() {
|
||||
super.show();
|
||||
findField.selectAll();
|
||||
findField.requestFocus();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Object source = e.getSource();
|
||||
|
||||
if (source == findButton) {
|
||||
find(true);
|
||||
|
||||
} else if (source == replaceButton) {
|
||||
replace();
|
||||
|
||||
} else if (source == replaceAllButton) {
|
||||
replaceAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// look for the next instance of the find string
|
||||
// to be found later than the current caret selection
|
||||
|
||||
// once found, select it (and go to that line)
|
||||
|
||||
public void find(boolean wrap) {
|
||||
// in case search len is zero,
|
||||
// otherwise replace all will go into an infinite loop
|
||||
found = false;
|
||||
|
||||
String search = findField.getText();
|
||||
// this will catch "find next" being called when no search yet
|
||||
if (search.length() == 0) return;
|
||||
|
||||
String text = editor.textarea.getText();
|
||||
|
||||
if (ignoreCase) {
|
||||
search = search.toLowerCase();
|
||||
text = text.toLowerCase();
|
||||
}
|
||||
|
||||
//int selectionStart = editor.textarea.getSelectionStart();
|
||||
int selectionEnd = editor.textarea.getSelectionEnd();
|
||||
|
||||
int nextIndex = text.indexOf(search, selectionEnd);
|
||||
if (nextIndex == -1) {
|
||||
if (wrap) {
|
||||
// if wrapping, a second chance is ok, start from beginning
|
||||
nextIndex = text.indexOf(search, 0);
|
||||
}
|
||||
|
||||
if (nextIndex == -1) {
|
||||
found = false;
|
||||
replaceButton.setEnabled(false);
|
||||
//Toolkit.getDefaultToolkit().beep();
|
||||
return;
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
replaceButton.setEnabled(true);
|
||||
editor.textarea.select(nextIndex, nextIndex + search.length());
|
||||
}
|
||||
|
||||
|
||||
// replace the current selection with whatever's in the
|
||||
// replacement text field
|
||||
|
||||
public void replace() {
|
||||
if (!found) return; // don't replace if nothing found
|
||||
|
||||
// check to see if the document has wrapped around
|
||||
// otherwise this will cause an infinite loop
|
||||
String sel = editor.textarea.getSelectedText();
|
||||
if (sel.equals(replaceField.getText())) {
|
||||
found = false;
|
||||
replaceButton.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.textarea.setSelectedText(replaceField.getText());
|
||||
//editor.setSketchModified(true);
|
||||
//editor.sketch.setCurrentModified(true);
|
||||
editor.sketch.setModified();
|
||||
|
||||
// don't allow a double replace
|
||||
replaceButton.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
// keep doing find and replace alternately until nothing more found
|
||||
|
||||
public void replaceAll() {
|
||||
// move to the beginning
|
||||
editor.textarea.select(0, 0);
|
||||
|
||||
do {
|
||||
find(false);
|
||||
replace();
|
||||
} while (found);
|
||||
}
|
||||
}
|
42
app/MessageConsumer.java
Normal file
42
app/MessageConsumer.java
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for dealing with parser/compiler output.
|
||||
* <P>
|
||||
* Different instances of MessageStream need to do different things with
|
||||
* messages. In particular, a stream instance used for parsing output from
|
||||
* the compiler compiler has to interpret its messages differently than one
|
||||
* parsing output from the runtime.
|
||||
* <P>
|
||||
* Classes which consume messages and do something with them
|
||||
* should implement this interface.
|
||||
*/
|
||||
public interface MessageConsumer {
|
||||
|
||||
public void message(String s);
|
||||
|
||||
}
|
86
app/MessageSiphon.java
Normal file
86
app/MessageSiphon.java
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* Slurps up messages from compiler.
|
||||
*/
|
||||
class MessageSiphon implements Runnable {
|
||||
BufferedReader streamReader;
|
||||
Thread thread;
|
||||
MessageConsumer consumer;
|
||||
|
||||
|
||||
public MessageSiphon(InputStream stream, MessageConsumer consumer) {
|
||||
this.streamReader = new BufferedReader(new InputStreamReader(stream));
|
||||
this.consumer = consumer;
|
||||
|
||||
thread = new Thread(this);
|
||||
// don't set priority too low, otherwise exceptions won't
|
||||
// bubble up in time (i.e. compile errors have a weird delay)
|
||||
//thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
// process data until we hit EOF; this will happily block
|
||||
// (effectively sleeping the thread) until new data comes in.
|
||||
// when the program is finally done, null will come through.
|
||||
//
|
||||
String currentLine;
|
||||
while ((currentLine = streamReader.readLine()) != null) {
|
||||
// \n is added again because readLine() strips it out
|
||||
//EditorConsole.systemOut.println("messaging in");
|
||||
consumer.message(currentLine + "\n");
|
||||
//EditorConsole.systemOut.println("messaging out");
|
||||
}
|
||||
//EditorConsole.systemOut.println("messaging thread done");
|
||||
thread = null;
|
||||
|
||||
} catch (NullPointerException npe) {
|
||||
// Fairly common exception during shutdown
|
||||
thread = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
// On Linux and sometimes on Mac OS X, a "bad file descriptor"
|
||||
// message comes up when closing an applet that's run externally.
|
||||
// That message just gets supressed here..
|
||||
String mess = e.getMessage();
|
||||
if ((mess != null) &&
|
||||
(mess.indexOf("Bad file descriptor") != -1)) {
|
||||
//if (e.getMessage().indexOf("Bad file descriptor") == -1) {
|
||||
//System.err.println("MessageSiphon err " + e);
|
||||
//e.printStackTrace();
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
}
|
62
app/MessageStream.java
Normal file
62
app/MessageStream.java
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* OutputStream to handle stdout/stderr messages.
|
||||
* <P>
|
||||
* This is used by Editor, System.err is set to
|
||||
* new PrintStream(new MessageStream()).
|
||||
* It's also used by Compiler.
|
||||
*/
|
||||
class MessageStream extends OutputStream {
|
||||
|
||||
MessageConsumer messageConsumer;
|
||||
|
||||
public MessageStream(MessageConsumer messageConsumer) {
|
||||
this.messageConsumer = messageConsumer;
|
||||
}
|
||||
|
||||
public void close() { }
|
||||
|
||||
public void flush() { }
|
||||
|
||||
public void write(byte b[]) {
|
||||
// this never seems to get called
|
||||
System.out.println("leech1: " + new String(b));
|
||||
}
|
||||
|
||||
public void write(byte b[], int offset, int length) {
|
||||
//System.out.println("leech2: " + new String(b));
|
||||
this.messageConsumer.message(new String(b, offset, length));
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
// this never seems to get called
|
||||
System.out.println("leech3: '" + ((char)b) + "'");
|
||||
}
|
||||
}
|
793
app/Preferences.java
Normal file
793
app/Preferences.java
Normal file
@ -0,0 +1,793 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.syntax.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.*;
|
||||
|
||||
//import processing.core.PApplet;
|
||||
|
||||
|
||||
/**
|
||||
* Storage class for user preferences and environment settings.
|
||||
* <P>
|
||||
* This class no longer uses the Properties class, since
|
||||
* properties files are iso8859-1, which is highly likely to
|
||||
* be a problem when trying to save sketch folders and locations.
|
||||
*/
|
||||
public class Preferences extends JComponent {
|
||||
|
||||
// what to call the feller
|
||||
|
||||
static final String PREFS_FILE = "preferences.txt";
|
||||
|
||||
|
||||
// platform strings (used to get settings for specific platforms)
|
||||
|
||||
static final String platforms[] = {
|
||||
"other", "windows", "macos9", "macosx", "linux"
|
||||
};
|
||||
|
||||
|
||||
// prompt text stuff
|
||||
|
||||
static final String PROMPT_YES = "Yes";
|
||||
static final String PROMPT_NO = "No";
|
||||
static final String PROMPT_CANCEL = "Cancel";
|
||||
static final String PROMPT_OK = "OK";
|
||||
static final String PROMPT_BROWSE = "Browse";
|
||||
|
||||
// mac needs it to be 70, windows needs 66, linux needs 76
|
||||
|
||||
static int BUTTON_WIDTH = 76;
|
||||
static int BUTTON_HEIGHT = 24;
|
||||
|
||||
// value for the size bars, buttons, etc
|
||||
|
||||
static final int GRID_SIZE = 33;
|
||||
|
||||
// gui variables
|
||||
|
||||
static final int GUI_BIG = 13;
|
||||
static final int GUI_BETWEEN = 10;
|
||||
static final int GUI_SMALL = 6;
|
||||
|
||||
// gui elements
|
||||
|
||||
//JFrame frame;
|
||||
JDialog frame;
|
||||
int wide, high;
|
||||
|
||||
JTextField sketchbookLocationField;
|
||||
JCheckBox sketchPromptBox;
|
||||
JCheckBox sketchCleanBox;
|
||||
//JCheckBox exportLibraryBox;
|
||||
JCheckBox externalEditorBox;
|
||||
JCheckBox checkUpdatesBox;
|
||||
|
||||
JTextField fontSizeField;
|
||||
|
||||
|
||||
// the calling editor, so updates can be applied
|
||||
Editor editor;
|
||||
|
||||
|
||||
// data model
|
||||
|
||||
static Hashtable table = new Hashtable();;
|
||||
static File preferencesFile;
|
||||
//boolean firstTime; // first time this feller has been run
|
||||
|
||||
|
||||
static public void init() {
|
||||
|
||||
// start by loading the defaults, in case something
|
||||
// important was deleted from the user prefs
|
||||
|
||||
try {
|
||||
load(Base.getStream("preferences.txt"));
|
||||
|
||||
} catch (Exception e) {
|
||||
Base.showError(null, "Could not read default settings.\n" +
|
||||
"You'll need to reinstall Processing.", e);
|
||||
}
|
||||
|
||||
// check for platform-specific properties in the defaults
|
||||
|
||||
String platformExtension = "." +
|
||||
platforms[Base.platform];
|
||||
int extensionLength = platformExtension.length();
|
||||
|
||||
Enumeration e = table.keys(); //properties.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = (String) e.nextElement();
|
||||
if (key.endsWith(platformExtension)) {
|
||||
// this is a key specific to a particular platform
|
||||
String actualKey = key.substring(0, key.length() - extensionLength);
|
||||
String value = get(key);
|
||||
table.put(actualKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// other things that have to be set explicitly for the defaults
|
||||
|
||||
setColor("run.window.bgcolor", SystemColor.control);
|
||||
|
||||
|
||||
// next load user preferences file
|
||||
|
||||
//File home = new File(System.getProperty("user.home"));
|
||||
//File processingHome = new File(home, "Processing");
|
||||
//preferencesFile = new File(home, PREFS_FILE);
|
||||
preferencesFile = Base.getSettingsFile(PREFS_FILE);
|
||||
|
||||
if (!preferencesFile.exists()) {
|
||||
// create a new preferences file if none exists
|
||||
// saves the defaults out to the file
|
||||
save();
|
||||
|
||||
} else {
|
||||
// load the previous preferences file
|
||||
|
||||
try {
|
||||
load(new FileInputStream(preferencesFile));
|
||||
|
||||
} catch (Exception ex) {
|
||||
Base.showError("Error reading preferences",
|
||||
"Error reading the preferences file. " +
|
||||
"Please delete (or move)\n" +
|
||||
preferencesFile.getAbsolutePath() +
|
||||
" and restart Processing.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Preferences() {
|
||||
|
||||
// setup frame for the prefs
|
||||
|
||||
//frame = new JFrame("Preferences");
|
||||
frame = new JDialog(editor, "Preferences", true);
|
||||
//frame.setResizable(false);
|
||||
|
||||
//Container pain = this;
|
||||
Container pain = frame.getContentPane();
|
||||
pain.setLayout(null);
|
||||
|
||||
int top = GUI_BIG;
|
||||
int left = GUI_BIG;
|
||||
int right = 0;
|
||||
|
||||
JLabel label;
|
||||
JButton button, button2;
|
||||
JComboBox combo;
|
||||
Dimension d, d2, d3;
|
||||
int h, v, vmax;
|
||||
|
||||
|
||||
// [ ] Prompt for name and folder when creating new sketch
|
||||
|
||||
sketchPromptBox =
|
||||
new JCheckBox("Prompt for name when opening or creating a sketch");
|
||||
pain.add(sketchPromptBox);
|
||||
d = sketchPromptBox.getPreferredSize();
|
||||
sketchPromptBox.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
|
||||
// [ ] Delete empty sketches on Quit
|
||||
|
||||
sketchCleanBox = new JCheckBox("Delete empty sketches on Quit");
|
||||
pain.add(sketchCleanBox);
|
||||
d = sketchCleanBox.getPreferredSize();
|
||||
sketchCleanBox.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
|
||||
// Sketchbook location:
|
||||
// [...............................] [ Browse ]
|
||||
|
||||
label = new JLabel("Sketchbook location:");
|
||||
pain.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
top += d.height; // + GUI_SMALL;
|
||||
|
||||
sketchbookLocationField = new JTextField(40);
|
||||
pain.add(sketchbookLocationField);
|
||||
d = sketchbookLocationField.getPreferredSize();
|
||||
|
||||
button = new JButton(PROMPT_BROWSE);
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
fc.setSelectedFile(new File(sketchbookLocationField.getText()));
|
||||
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
|
||||
int returned = fc.showOpenDialog(new JDialog());
|
||||
if (returned == JFileChooser.APPROVE_OPTION) {
|
||||
File file = fc.getSelectedFile();
|
||||
sketchbookLocationField.setText(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
});
|
||||
pain.add(button);
|
||||
d2 = button.getPreferredSize();
|
||||
|
||||
// take max height of all components to vertically align em
|
||||
vmax = Math.max(d.height, d2.height);
|
||||
//label.setBounds(left, top + (vmax-d.height)/2,
|
||||
// d.width, d.height);
|
||||
|
||||
//h = left + d.width + GUI_BETWEEN;
|
||||
sketchbookLocationField.setBounds(left, top + (vmax-d.height)/2,
|
||||
d.width, d.height);
|
||||
h = left + d.width + GUI_SMALL; //GUI_BETWEEN;
|
||||
button.setBounds(h, top + (vmax-d2.height)/2,
|
||||
d2.width, d2.height);
|
||||
|
||||
right = Math.max(right, h + d2.width + GUI_BIG);
|
||||
top += vmax + GUI_BETWEEN;
|
||||
|
||||
|
||||
// Editor font size [ ]
|
||||
|
||||
Container box = Box.createHorizontalBox();
|
||||
label = new JLabel("Editor font size: ");
|
||||
box.add(label);
|
||||
fontSizeField = new JTextField(4);
|
||||
box.add(fontSizeField);
|
||||
pain.add(box);
|
||||
d = box.getPreferredSize();
|
||||
box.setBounds(left, top, d.width, d.height);
|
||||
Font editorFont = Preferences.getFont("editor.font");
|
||||
fontSizeField.setText(String.valueOf(editorFont.getSize()));
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
|
||||
// [ ] Enable export to "Library"
|
||||
|
||||
/*
|
||||
exportLibraryBox = new JCheckBox("Enable advanced \"Library\" features" +
|
||||
" (requires restart)");
|
||||
exportLibraryBox.setEnabled(false);
|
||||
pain.add(exportLibraryBox);
|
||||
d = exportLibraryBox.getPreferredSize();
|
||||
exportLibraryBox.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
*/
|
||||
|
||||
|
||||
// [ ] Use external editor
|
||||
|
||||
externalEditorBox = new JCheckBox("Use external editor");
|
||||
pain.add(externalEditorBox);
|
||||
d = externalEditorBox.getPreferredSize();
|
||||
externalEditorBox.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
|
||||
// [ ] Check for updates on startup
|
||||
|
||||
checkUpdatesBox = new JCheckBox("Check for updates on startup");
|
||||
pain.add(checkUpdatesBox);
|
||||
d = checkUpdatesBox.getPreferredSize();
|
||||
checkUpdatesBox.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height + GUI_BETWEEN;
|
||||
|
||||
|
||||
// More preferences are in the ...
|
||||
|
||||
/*
|
||||
String blather =
|
||||
"More preferences can be edited directly\n" +
|
||||
"in the file " + preferencesFile.getAbsolutePath();
|
||||
//"More preferences are in the 'lib' folder inside text files\n" +
|
||||
//"named preferences.txt and pde_" +
|
||||
//Base.platforms[Base.platform] + ".properties";
|
||||
|
||||
JTextArea textarea = new JTextArea(blather);
|
||||
textarea.setEditable(false);
|
||||
textarea.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
textarea.setBackground(null);
|
||||
textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
|
||||
pain.add(textarea);
|
||||
*/
|
||||
label = new JLabel("More preferences can be edited directly in the file");
|
||||
|
||||
pain.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setForeground(Color.gray);
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height; // + GUI_SMALL;
|
||||
|
||||
label = new JLabel(preferencesFile.getAbsolutePath());
|
||||
pain.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height;
|
||||
|
||||
label = new JLabel("(edit only when Processing is not running)");
|
||||
pain.add(label);
|
||||
d = label.getPreferredSize();
|
||||
label.setForeground(Color.gray);
|
||||
label.setBounds(left, top, d.width, d.height);
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height; // + GUI_SMALL;
|
||||
|
||||
|
||||
// [ OK ] [ Cancel ] maybe these should be next to the message?
|
||||
|
||||
//right = Math.max(right, left + d.width + GUI_BETWEEN +
|
||||
// BUTTON_WIDTH + GUI_SMALL + BUTTON_WIDTH);
|
||||
|
||||
button = new JButton(PROMPT_OK);
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
applyFrame();
|
||||
disposeFrame();
|
||||
}
|
||||
});
|
||||
pain.add(button);
|
||||
d2 = button.getPreferredSize();
|
||||
BUTTON_HEIGHT = d2.height;
|
||||
|
||||
// smoosh up to the line before
|
||||
//top -= BUTTON_HEIGHT;
|
||||
|
||||
h = right - (BUTTON_WIDTH + GUI_SMALL + BUTTON_WIDTH);
|
||||
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
h += BUTTON_WIDTH + GUI_SMALL;
|
||||
|
||||
button = new JButton(PROMPT_CANCEL);
|
||||
button.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
disposeFrame();
|
||||
}
|
||||
});
|
||||
pain.add(button);
|
||||
button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
|
||||
top += BUTTON_HEIGHT + GUI_BETWEEN;
|
||||
|
||||
|
||||
// finish up
|
||||
|
||||
wide = right + GUI_BIG;
|
||||
high = top + GUI_SMALL; //GUI_BIG;
|
||||
setSize(wide, high);
|
||||
|
||||
|
||||
// closing the window is same as hitting cancel button
|
||||
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
disposeFrame();
|
||||
}
|
||||
});
|
||||
|
||||
Container content = frame.getContentPane();
|
||||
content.setLayout(new BorderLayout());
|
||||
content.add(this, BorderLayout.CENTER);
|
||||
|
||||
frame.pack();
|
||||
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
frame.setLocation((screen.width - wide) / 2,
|
||||
(screen.height - high) / 2);
|
||||
|
||||
|
||||
// handle window closing commands for ctrl/cmd-W or hitting ESC.
|
||||
|
||||
addKeyListener(new KeyAdapter() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
KeyStroke wc = Editor.WINDOW_CLOSE_KEYSTROKE;
|
||||
if ((e.getKeyCode() == KeyEvent.VK_ESCAPE) ||
|
||||
(KeyStroke.getKeyStrokeForEvent(e).equals(wc))) {
|
||||
disposeFrame();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(wide, high);
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
/**
|
||||
* Close the window after an OK or Cancel.
|
||||
*/
|
||||
public void disposeFrame() {
|
||||
frame.dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change internal settings based on what was chosen in the prefs,
|
||||
* then send a message to the editor saying that it's time to do the same.
|
||||
*/
|
||||
public void applyFrame() {
|
||||
// put each of the settings into the table
|
||||
setBoolean("sketchbook.prompt", sketchPromptBox.isSelected());
|
||||
setBoolean("sketchbook.auto_clean", sketchCleanBox.isSelected());
|
||||
set("sketchbook.path", sketchbookLocationField.getText());
|
||||
setBoolean("editor.external", externalEditorBox.isSelected());
|
||||
setBoolean("update.check", checkUpdatesBox.isSelected());
|
||||
|
||||
String newSizeText = fontSizeField.getText();
|
||||
try {
|
||||
int newSize = Integer.parseInt(newSizeText.trim());
|
||||
String pieces[] = Base.split(get("editor.font"), ',');
|
||||
pieces[2] = String.valueOf(newSize);
|
||||
set("editor.font", Base.join(pieces, ','));
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("ignoring invalid font size " + newSizeText);
|
||||
}
|
||||
editor.applyPreferences();
|
||||
}
|
||||
|
||||
|
||||
public void showFrame(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
// set all settings entry boxes to their actual status
|
||||
sketchPromptBox.setSelected(getBoolean("sketchbook.prompt"));
|
||||
sketchCleanBox.setSelected(getBoolean("sketchbook.auto_clean"));
|
||||
sketchbookLocationField.setText(get("sketchbook.path"));
|
||||
externalEditorBox.setSelected(getBoolean("editor.external"));
|
||||
checkUpdatesBox.setSelected(getBoolean("update.check"));
|
||||
|
||||
frame.show();
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
static public void load(InputStream input) throws IOException {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(input));
|
||||
|
||||
//table = new Hashtable();
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if ((line.length() == 0) ||
|
||||
(line.charAt(0) == '#')) continue;
|
||||
|
||||
// this won't properly handle = signs being in the text
|
||||
int equals = line.indexOf('=');
|
||||
if (equals != -1) {
|
||||
String key = line.substring(0, equals).trim();
|
||||
String value = line.substring(equals + 1).trim();
|
||||
table.put(key, value);
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
static public void save() {
|
||||
try {
|
||||
FileOutputStream output = new FileOutputStream(preferencesFile);
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output));
|
||||
|
||||
Enumeration e = table.keys(); //properties.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = (String) e.nextElement();
|
||||
writer.println(key + "=" + ((String) table.get(key)));
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
/*
|
||||
FileOutputStream output = null;
|
||||
|
||||
if ((Base.platform == Base.MACOSX) ||
|
||||
(Base.platform == Base.MACOS9)) {
|
||||
output = new FileOutputStream("lib/preferences.txt");
|
||||
|
||||
} else { // win95/98/ME doesn't set cwd properly
|
||||
URL url = getClass().getResource("buttons.gif");
|
||||
String urlstr = url.getFile();
|
||||
urlstr = urlstr.substring(0, urlstr.lastIndexOf("/") + 1) +
|
||||
".properties";
|
||||
output = new FileOutputStream(URLDecoder.decode(urlstr));
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
//base.storePreferences();
|
||||
|
||||
Properties skprops = new Properties();
|
||||
|
||||
//Rectangle window = Base.frame.getBounds();
|
||||
Rectangle window = editor.getBounds();
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
|
||||
skprops.put("last.window.x", String.valueOf(window.x));
|
||||
skprops.put("last.window.y", String.valueOf(window.y));
|
||||
skprops.put("last.window.w", String.valueOf(window.width));
|
||||
skprops.put("last.window.h", String.valueOf(window.height));
|
||||
|
||||
skprops.put("last.screen.w", String.valueOf(screen.width));
|
||||
skprops.put("last.screen.h", String.valueOf(screen.height));
|
||||
|
||||
skprops.put("last.sketch.name", sketchName);
|
||||
skprops.put("last.sketch.directory", sketchDir.getAbsolutePath());
|
||||
//skprops.put("user.name", userName);
|
||||
|
||||
skprops.put("last.divider.location",
|
||||
String.valueOf(splitPane.getDividerLocation()));
|
||||
|
||||
//
|
||||
|
||||
skprops.put("editor.external", externalEditor ? "true" : "false");
|
||||
|
||||
//skprops.put("serial.port", Preferences.get("serial.port", "unspecified"));
|
||||
|
||||
// save() is deprecated, and didn't properly
|
||||
// throw exceptions when it wasn't working
|
||||
skprops.store(output, "Settings for processing. " +
|
||||
"See lib/preferences.txt for defaults.");
|
||||
|
||||
// need to close the stream.. didn't do this before
|
||||
skprops.close();
|
||||
*/
|
||||
|
||||
} catch (IOException ex) {
|
||||
Base.showWarning(null, "Error while saving the settings file", ex);
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
// all the information from preferences.txt
|
||||
|
||||
//static public String get(String attribute) {
|
||||
//return get(attribute, null);
|
||||
//}
|
||||
|
||||
static public String get(String attribute /*, String defaultValue */) {
|
||||
return (String) table.get(attribute);
|
||||
/*
|
||||
//String value = (properties != null) ?
|
||||
//properties.getProperty(attribute) : applet.getParameter(attribute);
|
||||
String value = properties.getProperty(attribute);
|
||||
|
||||
return (value == null) ?
|
||||
defaultValue : value;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static public void set(String attribute, String value) {
|
||||
//preferences.put(attribute, value);
|
||||
table.put(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public boolean getBoolean(String attribute) {
|
||||
String value = get(attribute); //, null);
|
||||
return (new Boolean(value)).booleanValue();
|
||||
|
||||
/*
|
||||
supposedly not needed, because anything besides 'true'
|
||||
(ignoring case) will just be false.. so if malformed -> false
|
||||
if (value == null) return defaultValue;
|
||||
|
||||
try {
|
||||
return (new Boolean(value)).booleanValue();
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("expecting an integer: " + attribute + " = " + value);
|
||||
}
|
||||
return defaultValue;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static public void setBoolean(String attribute, boolean value) {
|
||||
set(attribute, value ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
static public int getInteger(String attribute /*, int defaultValue*/) {
|
||||
return Integer.parseInt(get(attribute));
|
||||
|
||||
/*
|
||||
String value = get(attribute, null);
|
||||
if (value == null) return defaultValue;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
// ignored will just fall through to returning the default
|
||||
System.err.println("expecting an integer: " + attribute + " = " + value);
|
||||
}
|
||||
return defaultValue;
|
||||
//if (value == null) return defaultValue;
|
||||
//return (value == null) ? defaultValue :
|
||||
//Integer.parseInt(value);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static public void setInteger(String key, int value) {
|
||||
set(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
|
||||
static public Color getColor(String name /*, Color otherwise*/) {
|
||||
Color parsed = null;
|
||||
String s = get(name); //, null);
|
||||
//System.out.println(name + " = " + s);
|
||||
if ((s != null) && (s.indexOf("#") == 0)) {
|
||||
try {
|
||||
int v = Integer.parseInt(s.substring(1), 16);
|
||||
parsed = new Color(v);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
//if (parsed == null) return otherwise;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
|
||||
static public void setColor(String attr, Color what) {
|
||||
String r = Integer.toHexString(what.getRed());
|
||||
String g = Integer.toHexString(what.getGreen());
|
||||
String b = Integer.toHexString(what.getBlue());
|
||||
set(attr, "#" + r.substring(r.length() - 2) +
|
||||
g.substring(g.length() - 2) + b.substring(b.length() - 2));
|
||||
}
|
||||
|
||||
|
||||
static public Font getFont(String which /*, Font otherwise*/) {
|
||||
//System.out.println("getting font '" + which + "'");
|
||||
String str = get(which);
|
||||
//if (str == null) return otherwise; // ENABLE LATER
|
||||
StringTokenizer st = new StringTokenizer(str, ",");
|
||||
String fontname = st.nextToken();
|
||||
String fontstyle = st.nextToken();
|
||||
return new Font(fontname,
|
||||
((fontstyle.indexOf("bold") != -1) ? Font.BOLD : 0) |
|
||||
((fontstyle.indexOf("italic") != -1) ? Font.ITALIC : 0),
|
||||
Integer.parseInt(st.nextToken()));
|
||||
}
|
||||
|
||||
|
||||
static public SyntaxStyle getStyle(String what /*, String dflt*/) {
|
||||
String str = get("editor." + what + ".style"); //, dflt);
|
||||
|
||||
StringTokenizer st = new StringTokenizer(str, ",");
|
||||
|
||||
String s = st.nextToken();
|
||||
if (s.indexOf("#") == 0) s = s.substring(1);
|
||||
Color color = new Color(Integer.parseInt(s, 16));
|
||||
|
||||
s = st.nextToken();
|
||||
boolean bold = (s.indexOf("bold") != -1);
|
||||
boolean italic = (s.indexOf("italic") != -1);
|
||||
//System.out.println(what + " = " + str + " " + bold + " " + italic);
|
||||
|
||||
return new SyntaxStyle(color, italic, bold);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Default serial port: [ COM1 + ]
|
||||
|
||||
/*
|
||||
label = new JLabel("Default serial port:");
|
||||
pain.add(label);
|
||||
d = label.getPreferredSize();
|
||||
|
||||
Vector list = buildPortList();
|
||||
combo = new JComboBox(list);
|
||||
pain.add(combo);
|
||||
d2 = combo.getPreferredSize();
|
||||
|
||||
if (list.size() == 0) {
|
||||
label.setEnabled(false);
|
||||
combo.setEnabled(false);
|
||||
|
||||
} else {
|
||||
String defaultName = Preferences.get("serial.port", "unspecified");
|
||||
combo.setSelectedItem(defaultName);
|
||||
}
|
||||
|
||||
vmax = Math.max(d.height, d2.height);
|
||||
label.setBounds(left, top + (vmax-d.height)/2,
|
||||
d.width, d.height);
|
||||
h = left + d.width + BETWEEN;
|
||||
combo.setBounds(h, top + (vmax-d2.height)/2,
|
||||
d2.width, d2.height);
|
||||
right = Math.max(right, h + d2.width + BIG);
|
||||
top += vmax + BETWEEN;
|
||||
*/
|
||||
|
||||
// open the last-used sketch, etc
|
||||
|
||||
//public void init() {
|
||||
|
||||
//String what = path + File.separator + name + ".pde";
|
||||
|
||||
///String serialPort = skprops.getProperty("serial.port");
|
||||
//if (serialPort != null) {
|
||||
// properties.put("serial.port", serialPort);
|
||||
//}
|
||||
|
||||
//boolean ee = new Boolean(skprops.getProperty("editor.external", "false")).booleanValue();
|
||||
//editor.setExternalEditor(ee);
|
||||
|
||||
///} catch (Exception e) {
|
||||
// this exception doesn't matter, it's just the normal course of things
|
||||
// the app reaches here when no sketch.properties file exists
|
||||
//e.printStackTrace();
|
||||
|
||||
// indicator that this is the first time this feller has used p5
|
||||
//firstTime = true;
|
||||
|
||||
// even if folder for 'default' user doesn't exist, or
|
||||
// sketchbook itself is missing, mkdirs() will make it happy
|
||||
//userName = "default";
|
||||
|
||||
// doesn't exist, not available, make my own
|
||||
//skNew();
|
||||
//}
|
||||
//}
|
128
app/PresentMode.java
Normal file
128
app/PresentMode.java
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005- Ben Fry and Casey Reas
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Vector;
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for full-screen presentation mode.
|
||||
*/
|
||||
public class PresentMode {
|
||||
|
||||
static GraphicsDevice devices[];
|
||||
|
||||
/**
|
||||
* Index of the default display device, probably the one that p5 was
|
||||
* started from.
|
||||
*/
|
||||
static int defaultIndex;
|
||||
|
||||
/**
|
||||
* Menu object for preferences window
|
||||
*/
|
||||
//JMenu preferencesMenu;
|
||||
static JComboBox selector;
|
||||
|
||||
/**
|
||||
* Index of the currently selected display to be used for present mode.
|
||||
*/
|
||||
static GraphicsDevice device;
|
||||
|
||||
|
||||
static {
|
||||
GraphicsEnvironment environment =
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
devices = environment.getScreenDevices();
|
||||
GraphicsDevice defaultDevice = environment.getDefaultScreenDevice();
|
||||
|
||||
Vector names = new Vector();
|
||||
for (int i = 0; i < devices.length; i++) {
|
||||
String name = String.valueOf(i + 1);
|
||||
if (devices[i] == defaultDevice) {
|
||||
defaultIndex = i;
|
||||
name += " (default)";
|
||||
}
|
||||
names.add(name);
|
||||
}
|
||||
|
||||
selector = new JComboBox(names);
|
||||
selector.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int index = selector.getSelectedIndex();
|
||||
//device = devices[index];
|
||||
Preferences.setInteger("run.present.display", index + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static public JComboBox getSelector() {
|
||||
int deviceIndex = Preferences.getInteger("run.present.display") - 1;
|
||||
selector.setSelectedIndex(deviceIndex);
|
||||
return selector;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static public JFrame create() {
|
||||
int deviceIndex = PrePreferences.getInteger("run.present.display") - 1;
|
||||
if ((deviceIndex < 0) || (deviceIndex >= devices.length)) {
|
||||
Base.showWarning("Display doesn't exist",
|
||||
"Present Mode is set to use display " +
|
||||
(deviceIndex+1) +
|
||||
" but that doesn't seem to exist. \n" +
|
||||
"This preference will be reset to " +
|
||||
"use the default display.", null);
|
||||
deviceIndex = defaultIndex;
|
||||
}
|
||||
//GraphicsDevice device = devices[
|
||||
//JFrame frame = new JFrame(devices[deviceIndex]);
|
||||
PresentFrame frame = new PresentFrame(devices[deviceIndex]);
|
||||
}
|
||||
|
||||
|
||||
public void show() {
|
||||
setUndecorated(true);
|
||||
setResizable(false);
|
||||
device.setFullScreenWindow(this);
|
||||
}
|
||||
|
||||
|
||||
public Window getWindow() {
|
||||
return device.getFullScreenWindow(); // isn't this just me?
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
Window window = device.getFullScreenWindow();
|
||||
if (window != null) {
|
||||
window.dispose();
|
||||
}
|
||||
device.setFullScreenWindow(null);
|
||||
}
|
||||
*/
|
||||
}
|
645
app/Runner.java
Normal file
645
app/Runner.java
Normal file
@ -0,0 +1,645 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
//import processing.core.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.oroinc.text.regex.*;
|
||||
|
||||
|
||||
/**
|
||||
* Runs a compiled java applet, whether as an external application
|
||||
* or internally as an applet object in a window.
|
||||
*/
|
||||
public class Runner implements MessageConsumer {
|
||||
|
||||
//PApplet applet;
|
||||
RunnerException exception;
|
||||
Window window;
|
||||
PrintStream leechErr;
|
||||
//String className;
|
||||
|
||||
Editor editor;
|
||||
Sketch sketch;
|
||||
|
||||
boolean newMessage;
|
||||
int messageLineCount;
|
||||
boolean foundMessageSource;
|
||||
|
||||
Process process;
|
||||
SystemOutSiphon processInput;
|
||||
OutputStream processOutput;
|
||||
MessageSiphon processError;
|
||||
|
||||
|
||||
public Runner(Sketch sketch, Editor editor) {
|
||||
this.sketch = sketch;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
|
||||
public void start(Point windowLocation) throws RunnerException {
|
||||
//System.out.println(" externalRuntime is " + sketch.externalRuntime);
|
||||
/* this.leechErr = new PrintStream(new MessageStream(this));
|
||||
|
||||
try {
|
||||
if (editor.presenting) {
|
||||
startPresenting();
|
||||
|
||||
} else if (sketch.externalRuntime) {
|
||||
startExternalRuntime(windowLocation);
|
||||
|
||||
} else {
|
||||
startInternal(windowLocation);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// this will pass through to the first part of message
|
||||
// this handles errors that happen inside setup()
|
||||
e.printStackTrace();
|
||||
|
||||
// make sure applet is in use
|
||||
if (applet != null) applet.finished = true;
|
||||
|
||||
leechErr.println(PApplet.LEECH_WAKEUP);
|
||||
e.printStackTrace(this.leechErr);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void startPresenting() throws Exception {
|
||||
Vector params = new Vector();
|
||||
|
||||
params.add("java");
|
||||
|
||||
String options = Preferences.get("run.options");
|
||||
/* if (options.length() > 0) {
|
||||
String pieces[] = PApplet.split(options, ' ');
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
String p = pieces[i].trim();
|
||||
if (p.length() > 0) {
|
||||
params.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.add("-Djava.library.path=" +
|
||||
sketch.libraryPath +
|
||||
File.pathSeparator +
|
||||
System.getProperty("java.library.path"));
|
||||
|
||||
params.add("-cp");
|
||||
params.add(sketch.classPath + Sketchbook.librariesClassPath);
|
||||
|
||||
params.add("processing.core.PApplet");
|
||||
|
||||
params.add(PApplet.ARGS_EXTERNAL);
|
||||
params.add(PApplet.ARGS_PRESENT);
|
||||
params.add(PApplet.ARGS_PRESENT_STOP_COLOR + "=" +
|
||||
Preferences.get("run.present.stop.color"));
|
||||
params.add(PApplet.ARGS_BGCOLOR + "=" +
|
||||
Preferences.get("run.present.bgcolor"));
|
||||
params.add(PApplet.ARGS_DISPLAY + "=" +
|
||||
Preferences.get("run.display"));
|
||||
params.add(PApplet.ARGS_SKETCH_FOLDER + "=" +
|
||||
sketch.folder.getAbsolutePath());
|
||||
params.add(sketch.mainClassName);
|
||||
|
||||
String command[] = new String[params.size()];
|
||||
params.copyInto(command);
|
||||
//PApplet.println(command);
|
||||
|
||||
process = Runtime.getRuntime().exec(command);
|
||||
processInput = new SystemOutSiphon(process.getInputStream());
|
||||
processError = new MessageSiphon(process.getErrorStream(), this);
|
||||
processOutput = process.getOutputStream();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void startExternalRuntime(Point windowLocation) throws Exception {
|
||||
// if there was a saved location (this guy has been run more than
|
||||
// once) then windowLocation will be set to the last position of
|
||||
// the sketch window. this will be passed to the PApplet runner
|
||||
// using something like --external=e30,20 where the e stands for
|
||||
// exact. otherwise --external=x,y for just the regular positioning.
|
||||
/* Point editorLocation = editor.getLocation();
|
||||
String location =
|
||||
(windowLocation != null) ?
|
||||
(PApplet.ARGS_LOCATION + "=" +
|
||||
windowLocation.x + "," + windowLocation.y) :
|
||||
(PApplet.ARGS_EDITOR_LOCATION + "=" +
|
||||
editorLocation.x + "," + editorLocation.y);
|
||||
|
||||
// this as prefix made the code folder bug go away, but killed stdio
|
||||
//"cmd", "/c", "start",
|
||||
|
||||
// all params have to be stored as separate items,
|
||||
// so a growable array needs to be used. i.e. -Xms128m -Xmx1024m
|
||||
// will throw an error if it's shoved into a single array element
|
||||
Vector params = new Vector();
|
||||
|
||||
params.add("java");
|
||||
|
||||
String options = Preferences.get("run.options");
|
||||
if (options.length() > 0) {
|
||||
String pieces[] = PApplet.split(options, ' ');
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
String p = pieces[i].trim();
|
||||
if (p.length() > 0) {
|
||||
params.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
// sketch.libraryPath might be ""
|
||||
// librariesClassPath will always have sep char prepended
|
||||
params.add("-Djava.library.path=" +
|
||||
sketch.libraryPath +
|
||||
File.pathSeparator +
|
||||
System.getProperty("java.library.path"));
|
||||
|
||||
params.add("-cp");
|
||||
params.add(sketch.classPath + Sketchbook.librariesClassPath);
|
||||
|
||||
params.add("processing.core.PApplet");
|
||||
|
||||
params.add(location);
|
||||
params.add(PApplet.ARGS_EXTERNAL);
|
||||
params.add(PApplet.ARGS_DISPLAY + "=" +
|
||||
Preferences.get("run.display"));
|
||||
params.add(PApplet.ARGS_SKETCH_FOLDER + "=" +
|
||||
sketch.folder.getAbsolutePath());
|
||||
params.add(sketch.mainClassName);
|
||||
|
||||
String command[] = new String[params.size()];
|
||||
params.copyInto(command);
|
||||
//PApplet.println(command);
|
||||
|
||||
process = Runtime.getRuntime().exec(command);
|
||||
processInput = new SystemOutSiphon(process.getInputStream());
|
||||
processError = new MessageSiphon(process.getErrorStream(), this);
|
||||
processOutput = process.getOutputStream();
|
||||
*/ }
|
||||
|
||||
|
||||
public void startInternal(Point windowLocation) throws Exception {
|
||||
/* Point editorLocation = editor.getLocation();
|
||||
//Insets editorInsets = editor.getInsets();
|
||||
|
||||
int windowX = editorLocation.x;
|
||||
int windowY = editorLocation.y + editor.getInsets().top;
|
||||
|
||||
RunnerClassLoader loader = new RunnerClassLoader();
|
||||
Class c = loader.loadClass(sketch.mainClassName);
|
||||
applet = (PApplet) c.newInstance();
|
||||
|
||||
window = new Frame(sketch.name); // use ugly window
|
||||
((Frame)window).setResizable(false);
|
||||
if (editor.icon != null) {
|
||||
((Frame)window).setIconImage(editor.icon);
|
||||
}
|
||||
window.pack(); // to get a peer, size set later, need for insets
|
||||
|
||||
applet.leechErr = leechErr;
|
||||
applet.folder = sketch.folder.getAbsolutePath();
|
||||
applet.frame = (Frame) window;
|
||||
|
||||
applet.init();
|
||||
//applet.start();
|
||||
|
||||
while ((applet.width == 0) && !applet.finished) {
|
||||
try {
|
||||
if (applet.exception != null) {
|
||||
throw new RunnerException(applet.exception.getMessage());
|
||||
}
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
|
||||
window.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
stop();
|
||||
editor.doClose();
|
||||
}
|
||||
});
|
||||
|
||||
applet.addKeyListener(new KeyAdapter() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||
stop();
|
||||
editor.doClose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.add(applet);
|
||||
|
||||
Dimension screen =
|
||||
Toolkit.getDefaultToolkit().getScreenSize();
|
||||
|
||||
window.setLayout(null);
|
||||
Insets insets = window.getInsets();
|
||||
|
||||
int minW = Preferences.getInteger("run.window.width.minimum");
|
||||
int minH = Preferences.getInteger("run.window.height.minimum");
|
||||
int windowW =
|
||||
Math.max(applet.width, minW) + insets.left + insets.right;
|
||||
int windowH =
|
||||
Math.max(applet.height, minH) + insets.top + insets.bottom;
|
||||
|
||||
if (windowX - windowW > 10) { // if it fits to the left of the window
|
||||
window.setBounds(windowX - windowW, windowY, windowW, windowH);
|
||||
|
||||
} else { // if it fits inside the editor window
|
||||
windowX = editorLocation.x + Preferences.GRID_SIZE * 2; // 66
|
||||
windowY = editorLocation.y + Preferences.GRID_SIZE * 2; // 66
|
||||
|
||||
if ((windowX + windowW > screen.width - Preferences.GRID_SIZE) ||
|
||||
(windowY + windowH > screen.height - Preferences.GRID_SIZE)) {
|
||||
// otherwise center on screen
|
||||
windowX = (screen.width - windowW) / 2;
|
||||
windowY = (screen.height - windowH) / 2;
|
||||
}
|
||||
window.setBounds(windowX, windowY, windowW, windowH); //ww, wh);
|
||||
}
|
||||
|
||||
Color windowBgColor = Preferences.getColor("run.window.bgcolor");
|
||||
window.setBackground(windowBgColor);
|
||||
|
||||
int usableH = windowH - insets.top - insets.bottom;
|
||||
applet.setBounds((windowW - applet.width)/2,
|
||||
insets.top + (usableH - applet.height) / 2,
|
||||
windowW, windowH);
|
||||
|
||||
applet.setVisible(true); // no effect
|
||||
if (windowLocation != null) {
|
||||
window.setLocation(windowLocation);
|
||||
}
|
||||
window.show();
|
||||
applet.requestFocus(); // necessary for key events
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void stop() {
|
||||
/* // check for null in case stop is called during compilation
|
||||
if (applet != null) {
|
||||
applet.stop();
|
||||
|
||||
// above avoids NullPointerExceptions
|
||||
// but still threading is too complex, and so
|
||||
// some boogers are being left behind
|
||||
applet = null;
|
||||
|
||||
} else if (process != null) { // running externally
|
||||
try {
|
||||
processOutput.write(PApplet.EXTERNAL_STOP);
|
||||
processOutput.flush();
|
||||
|
||||
} catch (IOException e) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
/* //if (window != null) window.hide();
|
||||
if (window != null) {
|
||||
//System.err.println("disposing window");
|
||||
window.dispose();
|
||||
window = null;
|
||||
}
|
||||
|
||||
if (process != null) {
|
||||
try {
|
||||
process.destroy();
|
||||
} catch (Exception e) {
|
||||
//System.err.println("(ignored) error while destroying");
|
||||
//e.printStackTrace();
|
||||
}
|
||||
process = null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
// made synchronized for rev 87
|
||||
synchronized public void message(String s) {
|
||||
//System.out.println("M" + s.length() + ":" + s.trim()); // + "MMM" + s.length());
|
||||
|
||||
// this eats the CRLFs on the lines.. oops.. do it later
|
||||
//if (s.trim().length() == 0) return;
|
||||
|
||||
// this is PApplet sending a message (via System.out.println)
|
||||
// that signals that the applet has been quit.
|
||||
// if (s.indexOf(PApplet.EXTERNAL_QUIT) == 0) {
|
||||
//System.out.println("external: quit");
|
||||
// editor.doClose();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this is the PApplet sending us a message that the applet
|
||||
// is being moved to a new window location
|
||||
// if (s.indexOf(PApplet.EXTERNAL_MOVE) == 0) {
|
||||
// String nums = s.substring(s.indexOf(' ') + 1).trim();
|
||||
// int space = nums.indexOf(' ');
|
||||
// int left = Integer.parseInt(nums.substring(0, space));
|
||||
// int top = Integer.parseInt(nums.substring(space + 1));
|
||||
// editor.appletLocation = new Point(left, top);
|
||||
// //System.out.println("external: move to " + left + " " + top);
|
||||
//// return;
|
||||
// }
|
||||
|
||||
// this is PApplet sending a message saying "i'm about to spew
|
||||
// a stack trace because an error occurred during PApplet.run()"
|
||||
// if (s.indexOf(PApplet.LEECH_WAKEUP) == 0) {
|
||||
// newMessage being set to 'true' means that the next time
|
||||
// message() is called, expect the first line of the actual
|
||||
// // error message & stack trace to be sent from the applet.
|
||||
// newMessage = true;
|
||||
// return; // this line ignored
|
||||
// }
|
||||
|
||||
// these are used for debugging, in case there are concerns
|
||||
// that some errors aren't coming through properly
|
||||
/*
|
||||
if (s.length() > 2) {
|
||||
System.err.println(newMessage);
|
||||
System.err.println("message " + s.length() + ":" + s);
|
||||
}
|
||||
*/
|
||||
// always shove out the mesage, since it might not fall under
|
||||
// the same setup as we're expecting
|
||||
System.err.print(s);
|
||||
//System.err.println("[" + s.length() + "] " + s);
|
||||
System.err.flush();
|
||||
|
||||
// exit here because otherwise the exception name
|
||||
// may be titled with a blank string
|
||||
if (s.trim().length() == 0) return;
|
||||
|
||||
// annoying, because it seems as though the terminators
|
||||
// aren't being sent properly
|
||||
//System.err.println(s);
|
||||
|
||||
//if (newMessage && s.length() > 2) {
|
||||
if (newMessage) {
|
||||
exception = new RunnerException(s); // type of java ex
|
||||
exception.hideStackTrace = true;
|
||||
//System.out.println("setting ex type to " + s);
|
||||
newMessage = false;
|
||||
foundMessageSource = false;
|
||||
messageLineCount = 0;
|
||||
|
||||
} else {
|
||||
messageLineCount++;
|
||||
|
||||
/*
|
||||
java.lang.NullPointerException
|
||||
at javatest.<init>(javatest.java:5)
|
||||
at Temporary_2425_1153.draw(Temporary_2425_1153.java:11)
|
||||
at PApplet.nextFrame(PApplet.java:481)
|
||||
at PApplet.run(PApplet.java:428)
|
||||
at java.lang.Thread.run(Unknown Source)
|
||||
*/
|
||||
|
||||
if (!foundMessageSource) {
|
||||
// " at javatest.<init>(javatest.java:5)"
|
||||
// -> "javatest.<init>(javatest.java:5)"
|
||||
int afterAt = s.indexOf("at") + 3;
|
||||
//if (afterAt == -1) {
|
||||
if (afterAt == 2) { // means indexOf was -1
|
||||
//System.err.println(s); // stop double-printing exceptions
|
||||
return;
|
||||
}
|
||||
s = s.substring(afterAt + 1);
|
||||
|
||||
// "javatest.<init>(javatest.java:5)"
|
||||
// -> "javatest.<init>" and "(javatest.java:5)"
|
||||
int startParen = s.indexOf('(');
|
||||
// at javatest.<init>(javatest.java:5)
|
||||
String pkgClassFxn = null;
|
||||
//String fileLine = null;
|
||||
int codeIndex = -1;
|
||||
int lineNumber = -1;
|
||||
|
||||
if (startParen == -1) {
|
||||
pkgClassFxn = s;
|
||||
|
||||
} else {
|
||||
pkgClassFxn = s.substring(0, startParen);
|
||||
// "(javatest.java:5)"
|
||||
String fileAndLine = s.substring(startParen + 1);
|
||||
int stopParen = fileAndLine.indexOf(')');
|
||||
//fileAndLine = fileAndLine.substring(0, fileAndLine.length() - 1);
|
||||
fileAndLine = fileAndLine.substring(0, stopParen);
|
||||
//System.out.println("file 'n line " + fileAndLine);
|
||||
|
||||
//if (!fileAndLine.equals("Unknown Source")) {
|
||||
// "javatest.java:5"
|
||||
int colonIndex = fileAndLine.indexOf(':');
|
||||
if (colonIndex != -1) {
|
||||
String filename = fileAndLine.substring(0, colonIndex);
|
||||
// "javatest.java" and "5"
|
||||
//System.out.println("filename = " + filename);
|
||||
//System.out.println("pre0 = " + sketch.code[0].preprocName);
|
||||
//for (int i = 0; i < sketch.codeCount; i++) {
|
||||
//System.out.println(i + " " + sketch.code[i].lineOffset + " " +
|
||||
// sketch.code[i].preprocName);
|
||||
//}
|
||||
lineNumber =
|
||||
Integer.parseInt(fileAndLine.substring(colonIndex + 1)) - 1;
|
||||
|
||||
for (int i = 0; i < sketch.codeCount; i++) {
|
||||
SketchCode code = sketch.code[i];
|
||||
//System.out.println(code.preprocName + " " + lineNumber + " " +
|
||||
// code.preprocOffset);
|
||||
if (((code.preprocName == null) &&
|
||||
(lineNumber >= code.preprocOffset)) ||
|
||||
((code.preprocName != null) &&
|
||||
code.preprocName.equals(filename))) {
|
||||
codeIndex = i;
|
||||
//System.out.println("got codeindex " + codeIndex);
|
||||
//break;
|
||||
//} else if (
|
||||
}
|
||||
}
|
||||
|
||||
if (codeIndex != -1) {
|
||||
// in case this was a tab that got embedded into the main .java
|
||||
lineNumber -= sketch.code[codeIndex].preprocOffset;
|
||||
|
||||
// this may have a paren on the end, if so need to strip
|
||||
// down to just the digits
|
||||
/*
|
||||
int lastNumberIndex = colonIndex + 1;
|
||||
while ((lastNumberIndex < fileAndLine.length()) &&
|
||||
Character.isDigit(fileAndLine.charAt(lastNumberIndex))) {
|
||||
lastNumberIndex++;
|
||||
}
|
||||
*/
|
||||
|
||||
// lineNumber is 1-indexed, but editor wants zero-indexed
|
||||
// getMessage() will be what's shown in the editor
|
||||
exception =
|
||||
new RunnerException(exception.getMessage(),
|
||||
codeIndex, lineNumber, -1);
|
||||
exception.hideStackTrace = true;
|
||||
foundMessageSource = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
editor.error(exception);
|
||||
|
||||
/*
|
||||
int index = s.indexOf(className + ".java");
|
||||
if (index != -1) {
|
||||
int len = (className + ".java").length();
|
||||
String lineNumberStr = s.substring(index + len + 1);
|
||||
index = lineNumberStr.indexOf(')');
|
||||
lineNumberStr = lineNumberStr.substring(0, index);
|
||||
try {
|
||||
exception.line = Integer.parseInt(lineNumberStr) - 1; //2;
|
||||
} catch (NumberFormatException e) { }
|
||||
//e.printStackTrace(); // a recursive error waiting to happen?
|
||||
// if nfe occurs, who cares, still send the error on up
|
||||
editor.error(exception);
|
||||
*/
|
||||
|
||||
/*
|
||||
// WARNING THESE ARE DISABLED!!
|
||||
} else if ((index = s.indexOf(className + ".class")) != -1) {
|
||||
// code to check for:
|
||||
// at Temporary_484_3845.loop(Compiled Code)
|
||||
// would also probably get:
|
||||
// at Temporary_484_3845.loop
|
||||
// which (i believe) is used by the mac and/or jview
|
||||
String functionStr = s.substring(index +
|
||||
(className + ".class").length() + 1);
|
||||
index = functionStr.indexOf('(');
|
||||
if (index != -1) {
|
||||
functionStr = functionStr.substring(0, index);
|
||||
}
|
||||
exception = new RunnerException(//"inside \"" + functionStr + "()\": " +
|
||||
exception.getMessage() +
|
||||
" inside " + functionStr + "() " +
|
||||
"[add Compiler.disable() to setup()]");
|
||||
editor.error(exception);
|
||||
// this will fall through in tihs example:
|
||||
// at Temporary_4636_9696.pootie(Compiled Code)
|
||||
// at Temporary_4636_9696.loop(Temporary_4636_9696.java:24)
|
||||
// because pootie() (re)sets the exception title
|
||||
// and throws it, but then the line number gets set
|
||||
// because of the line that comes after
|
||||
*/
|
||||
|
||||
} else if (messageLineCount > 10) { // 5 -> 10 for 0088
|
||||
// this means the class name may not be mentioned
|
||||
// in the stack trace.. this is just a general purpose
|
||||
// error, but needs to make it through anyway.
|
||||
// so if five lines have gone past, might as well signal
|
||||
messageLineCount = -100;
|
||||
exception = new RunnerException(exception.getMessage());
|
||||
exception.hideStackTrace = true;
|
||||
editor.error(exception);
|
||||
|
||||
} else {
|
||||
//System.err.print(s);
|
||||
}
|
||||
//System.out.println("got it " + s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Siphons from an InputStream of System.out (from a Process)
|
||||
* and sends it to the real System.out.
|
||||
*/
|
||||
class SystemOutSiphon implements Runnable {
|
||||
InputStream input;
|
||||
Thread thread;
|
||||
|
||||
public SystemOutSiphon(InputStream input) {
|
||||
this.input = input;
|
||||
|
||||
thread = new Thread(this);
|
||||
// unless this is set to min, it seems to hork the app
|
||||
// since it's in charge of stuffing the editor console with strings
|
||||
// maybe it's time to get rid of/fix that friggin console
|
||||
// ...disabled for 0075, with 0074's fix for code folder hanging
|
||||
// this only seems to make the console unresponsive
|
||||
//thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
byte boofer[] = new byte[256];
|
||||
|
||||
while (Thread.currentThread() == thread) {
|
||||
try {
|
||||
// can't use a buffered reader here because incremental
|
||||
// print statements are interesting too.. causes some
|
||||
// disparity with how System.err gets spewed, oh well.
|
||||
int count = input.read(boofer, 0, boofer.length);
|
||||
if (count == -1) {
|
||||
thread = null;
|
||||
|
||||
} else {
|
||||
System.out.print(new String(boofer, 0, count));
|
||||
//System.out.flush();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// this is prolly because the app was quit & the stream broken
|
||||
//e.printStackTrace(System.out);
|
||||
//e.printStackTrace();
|
||||
thread = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
//System.out.println("SystemOutSiphon: i just died in your arms tonight");
|
||||
// on mac os x, this will spew a "Bad File Descriptor" ex
|
||||
// each time an external app is shut down.
|
||||
//e.printStackTrace();
|
||||
thread = null;
|
||||
//System.out.println("");
|
||||
}
|
||||
//System.out.println("SystemOutSiphon: out");
|
||||
//thread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
128
app/RunnerClassLoader.java
Normal file
128
app/RunnerClassLoader.java
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Based on Simple1.2ClassLoader.java - simple Java 1.2 class loader
|
||||
Copyright (c) 1999 Ken McCrary, All Rights Reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
and its documentation for NON-COMMERCIAL purposes and without
|
||||
fee is hereby granted provided that this copyright notice
|
||||
appears in all copies.
|
||||
|
||||
KEN MCCRARY MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
|
||||
SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. KEN MCCRARY
|
||||
SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT
|
||||
OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
|
||||
*/
|
||||
package processing.app;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.jar.*;
|
||||
|
||||
|
||||
/**
|
||||
* Simple class loader adapted for Processing.
|
||||
* <P>
|
||||
* Based on code from Ken McCrary.
|
||||
*/
|
||||
public class RunnerClassLoader extends ClassLoader {
|
||||
String buildFolderPath;
|
||||
|
||||
RunnerClassLoader() {
|
||||
buildFolderPath = Base.getBuildFolder().getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method where the task of class loading
|
||||
* is delegated to our custom loader.
|
||||
*
|
||||
* @param name the name of the class
|
||||
* @return the resulting <code>Class</code> object
|
||||
* @exception ClassNotFoundException if the class could not be found
|
||||
*/
|
||||
protected Class findClass(String name) throws ClassNotFoundException {
|
||||
FileInputStream fi = null;
|
||||
|
||||
try {
|
||||
String path =
|
||||
buildFolderPath + File.separator + name.replace('.', '/');
|
||||
//System.out.println("(from " + path + ")");
|
||||
fi = new FileInputStream(path + ".class");
|
||||
byte[] classBytes = new byte[fi.available()];
|
||||
fi.read(classBytes);
|
||||
//definePackage(name);
|
||||
return defineClass(name, classBytes, 0, classBytes.length);
|
||||
|
||||
} catch (Exception e) {
|
||||
// could not find the class, so indicate the problem with an exception
|
||||
throw new ClassNotFoundException(name);
|
||||
|
||||
} finally {
|
||||
if (fi != null) {
|
||||
try {
|
||||
fi.close();
|
||||
} catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identify where to load a resource from, resources for
|
||||
* this simple ClassLoader are in a directory name "store"
|
||||
*
|
||||
* @param name the resource name
|
||||
* @return URL for resource or null if not found
|
||||
*/
|
||||
protected URL findResource(String name) {
|
||||
String path =
|
||||
buildFolderPath + File.separator + name.replace('.', '/');
|
||||
File searchResource = new File(path, name);
|
||||
//URL result = null;
|
||||
|
||||
if (searchResource.exists()) {
|
||||
try {
|
||||
return searchResource.toURL();
|
||||
} catch (MalformedURLException mfe) { }
|
||||
}
|
||||
//return result;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used for identifying resources from multiple URLS
|
||||
* Since our simple Classloader only has one repository
|
||||
* the returned Enumeration contains 0 to 1 items
|
||||
*
|
||||
* @param name the resource name
|
||||
* @return Enumeration of one URL
|
||||
*/
|
||||
protected Enumeration findResources(final String name) throws IOException {
|
||||
// Since we only have a single repository we will only have one
|
||||
// resource of a particular name, the Enumeration will just return
|
||||
// this single URL
|
||||
|
||||
return new Enumeration() {
|
||||
URL resource = findResource(name);
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return ( resource != null ? true : false);
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
if (!hasMoreElements()) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
URL result = resource;
|
||||
resource = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
83
app/RunnerException.java
Normal file
83
app/RunnerException.java
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
/**
|
||||
* An exception with a line number attached that occurs
|
||||
* during either compile time or run time.
|
||||
*/
|
||||
public class RunnerException extends Exception {
|
||||
public int file = -1;
|
||||
public int line = -1;
|
||||
public int column = -1;
|
||||
public boolean hideStackTrace;
|
||||
|
||||
public RunnerException() { }
|
||||
|
||||
public RunnerException(String message) {
|
||||
super(massage(message));
|
||||
}
|
||||
|
||||
public RunnerException(String message, int line) {
|
||||
super(massage(message));
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public RunnerException(String message, int line, int column) {
|
||||
super(massage(message));
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public RunnerException(String message, int file, int line, int column) {
|
||||
super(massage(message));
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Nix the java.lang crap out of an exception message
|
||||
* because it scares the children.
|
||||
* <P>
|
||||
* This function must be static to be used with super()
|
||||
* in each of the constructors above.
|
||||
*/
|
||||
static public final String massage(String msg) {
|
||||
if (msg.indexOf("java.lang.") == 0) {
|
||||
//int dot = msg.lastIndexOf('.');
|
||||
msg = msg.substring("java.lang.".length());
|
||||
}
|
||||
return msg;
|
||||
//return (dot == -1) ? msg : msg.substring(dot+1);
|
||||
}
|
||||
|
||||
|
||||
public void printStackTrace() {
|
||||
if (!hideStackTrace) {
|
||||
super.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
1804
app/Sketch.java
Normal file
1804
app/Sketch.java
Normal file
File diff suppressed because it is too large
Load Diff
105
app/SketchCode.java
Normal file
105
app/SketchCode.java
Normal file
@ -0,0 +1,105 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
SketchCode - data class for a single file inside a sketch
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
import processing.app.syntax.*;
|
||||
|
||||
import java.io.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.*;
|
||||
|
||||
|
||||
public class SketchCode {
|
||||
/** Pretty name (no extension), not the full file name */
|
||||
public String name;
|
||||
|
||||
/** File object for where this code is located */
|
||||
public File file;
|
||||
|
||||
/** Type of code in this tab, Sketch.PDE or Sketch.JAVA */
|
||||
public int flavor;
|
||||
|
||||
/** Text of the program text for this tab */
|
||||
public String program;
|
||||
|
||||
/** Document object for this tab */
|
||||
public SyntaxDocument document;
|
||||
|
||||
/** Undo Manager for this tab, each tab keeps track of their own */
|
||||
public UndoManager undo; // = new UndoManager();
|
||||
|
||||
// saved positions from last time this tab was used
|
||||
public int selectionStart;
|
||||
public int selectionStop;
|
||||
public int scrollPosition;
|
||||
|
||||
public boolean modified;
|
||||
//SketchHistory history; // TODO add history information
|
||||
|
||||
String preprocName; // name of .java file after preproc
|
||||
int preprocOffset; // where this code starts relative to the concat'd code
|
||||
|
||||
|
||||
public SketchCode(String name, File file, int flavor) {
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
this.flavor = flavor;
|
||||
|
||||
try {
|
||||
load();
|
||||
} catch (IOException e) {
|
||||
System.err.println("error while loading code " + name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load this piece of code from a file.
|
||||
*/
|
||||
public void load() throws IOException {
|
||||
program = Base.loadFile(file);
|
||||
modified = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save this piece of code, regardless of whether the modified
|
||||
* flag is set or not.
|
||||
*/
|
||||
public void save() throws IOException {
|
||||
// TODO re-enable history
|
||||
//history.record(s, SketchHistory.SAVE);
|
||||
|
||||
Base.saveFile(program, file);
|
||||
modified = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save this file to another location, used by Sketch.saveAs()
|
||||
*/
|
||||
public void saveAs(File newFile) throws IOException {
|
||||
Base.saveFile(program, newFile);
|
||||
}
|
||||
}
|
357
app/SketchHistory.java
Normal file
357
app/SketchHistory.java
Normal file
@ -0,0 +1,357 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
SketchHistory - handler for storing history information about a project
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
public class SketchHistory {
|
||||
Editor editor;
|
||||
|
||||
// why things have been saved for history
|
||||
static final int RUN = 5;
|
||||
static final int SAVE = 6;
|
||||
static final int AUTOSAVE = 7;
|
||||
static final int BEAUTIFY = 8;
|
||||
|
||||
static final String HISTORY_SEPARATOR =
|
||||
"#################################################";
|
||||
|
||||
JMenu menu;
|
||||
|
||||
// true if the sketch is read-only,
|
||||
// meaning that no history will be recorded
|
||||
boolean readOnlySketch;
|
||||
|
||||
File historyFile;
|
||||
String lastRecorded;
|
||||
|
||||
ActionListener menuListener;
|
||||
|
||||
|
||||
//public SketchHistory(Editor editor) {
|
||||
//this.editor = editor;
|
||||
//}
|
||||
|
||||
public SketchHistory(Sketch sketch) {
|
||||
menu = new JMenu("History");
|
||||
|
||||
menuListener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
retrieve(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Set the path for the current sketch
|
||||
|
||||
public void setPath(String path, boolean readOnlySketch) {
|
||||
this.readOnlySketch = true;
|
||||
|
||||
if (readOnlySketch) return;
|
||||
historyFile = new File(path, "history.gz");
|
||||
}
|
||||
|
||||
|
||||
public void attachMenu(JMenu parent) {
|
||||
//if (Preferences.getBoolean("history.recording")) {
|
||||
parent.add(menu);
|
||||
|
||||
// should leave enabled, since can still get old history
|
||||
// even if the new stuff isn't being recorded
|
||||
//menu.setEnabled(Preferences.getBoolean("history.recording"));
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
/// Check to see if history should be recorded.
|
||||
/// mode is RUN, SAVE, AUTOSAVE, or BEAUTIFY
|
||||
public void record(String program, int mode) {
|
||||
if (readOnlySketch) return;
|
||||
|
||||
if (!Preferences.getBoolean("history.recording")) return;
|
||||
|
||||
if ((lastRecorded != null) &&
|
||||
(lastRecorded.equals(program))) return;
|
||||
|
||||
String modeStr = null;
|
||||
switch (mode) {
|
||||
case RUN: modeStr = "run"; break;
|
||||
case SAVE: modeStr = "save"; break;
|
||||
case AUTOSAVE: modeStr = "autosave"; break;
|
||||
case BEAUTIFY: modeStr = "beautify"; break;
|
||||
}
|
||||
|
||||
try {
|
||||
boolean noPreviousHistory = false;
|
||||
|
||||
ByteArrayOutputStream old = null;
|
||||
if (historyFile.exists()) {
|
||||
InputStream oldStream = new GZIPInputStream(new BufferedInputStream(new FileInputStream(historyFile)));
|
||||
old = new ByteArrayOutputStream();
|
||||
|
||||
int c = oldStream.read();
|
||||
while (c != -1) {
|
||||
old.write(c);
|
||||
c = oldStream.read();
|
||||
}
|
||||
//return out.toByteArray();
|
||||
oldStream.close();
|
||||
|
||||
} else {
|
||||
noPreviousHistory = true; // rebuild menu
|
||||
}
|
||||
|
||||
OutputStream historyStream =
|
||||
new GZIPOutputStream(new FileOutputStream(historyFile));
|
||||
|
||||
if (old != null) {
|
||||
historyStream.write(old.toByteArray());
|
||||
}
|
||||
PrintWriter historyWriter =
|
||||
new PrintWriter(new OutputStreamWriter(historyStream));
|
||||
|
||||
historyWriter.println();
|
||||
historyWriter.println(HISTORY_SEPARATOR);
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
// 2002 06 18 11 43 29
|
||||
// when listing, study for descrepancies.. if all are
|
||||
// 2002, then don't list the year and soforth.
|
||||
// for the other end, if all minutes are unique,
|
||||
// then don't show seconds
|
||||
int year = now.get(Calendar.YEAR);
|
||||
int month = now.get(Calendar.MONTH) + 1;
|
||||
int day = now.get(Calendar.DAY_OF_MONTH);
|
||||
int hour = now.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = now.get(Calendar.MINUTE);
|
||||
int second = now.get(Calendar.SECOND);
|
||||
String parseDate = year + " " + month + " " + day + " " +
|
||||
hour + " " + minute + " " + second;
|
||||
|
||||
String readableDate = now.getTime().toString();
|
||||
|
||||
// increment this so sketchbook won't be mangled
|
||||
// each time this format has to change
|
||||
String historyVersion = "1";
|
||||
//Date date = new Date();
|
||||
//String datestamp = date.toString();
|
||||
|
||||
historyWriter.println(historyVersion + " " + modeStr + " - " +
|
||||
parseDate + " - " + readableDate);
|
||||
historyWriter.println();
|
||||
historyWriter.println(program);
|
||||
historyWriter.flush(); // ??
|
||||
lastRecorded = program;
|
||||
|
||||
//JMenuItem menuItem = new JMenuItem(modeStr + " - " + readableDate);
|
||||
JMenuItem menuItem = new JMenuItem(modeStr + " - " + readableDate);
|
||||
menuItem.addActionListener(menuListener);
|
||||
menu.insert(menuItem, 2);
|
||||
|
||||
historyWriter.flush();
|
||||
historyWriter.close();
|
||||
|
||||
if (noPreviousHistory) {
|
||||
// to get add the actual menu, to get the 'clear' item in there
|
||||
//rebuildMenu(historyFile.getPath());
|
||||
rebuildMenu();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void retrieve(String selection) {
|
||||
//System.out.println("sel '" + selection + "'");
|
||||
String readableDate =
|
||||
selection.substring(selection.indexOf("-") + 2);
|
||||
|
||||
// make history for the current guy
|
||||
record(editor.textarea.getText(), AUTOSAVE);
|
||||
// mark editor text as having been edited
|
||||
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(historyFile))));
|
||||
String line = null;
|
||||
|
||||
int historyCount = 0;
|
||||
String historyList[] = new String[100];
|
||||
|
||||
try {
|
||||
boolean found = false;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//System.out.println("->" + line);
|
||||
if (line.equals(HISTORY_SEPARATOR)) {
|
||||
line = reader.readLine();
|
||||
if (line.indexOf(readableDate) != -1) { // this is the one
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
// read lines until the next separator
|
||||
line = reader.readLine(); // ignored
|
||||
//String sep = System.getProperty("line.separator");
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.equals(HISTORY_SEPARATOR)) break;
|
||||
//textarea.append(line + sep);
|
||||
//buffer.append(line + sep); // JTextPane wants only \n going in
|
||||
buffer.append(line + "\n");
|
||||
//System.out.println("'" + line + "'");
|
||||
}
|
||||
//textarea.editorSetText(buffer.toString());
|
||||
editor.changeText(buffer.toString(), true);
|
||||
lastRecorded = editor.textarea.getText();
|
||||
editor.setSketchModified(false);
|
||||
|
||||
} else {
|
||||
System.err.println("couldn't find history entry for " +
|
||||
"'" + readableDate + "'");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// class HistoryMenuListener implements ActionListener {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// editor.selectHistory(e.getActionCommand);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
//public void rebuildHistoryMenu(String path) {
|
||||
//rebuildHistoryMenu(historyMenu, path);
|
||||
//}
|
||||
|
||||
|
||||
//public void rebuildHistoryMenu(Menu menu, String path) {
|
||||
public void rebuildMenu() { //String path) {
|
||||
//if (!recordingHistory) return;
|
||||
//if (!Preferences.getBoolean("history.recording")) return;
|
||||
|
||||
menu.removeAll();
|
||||
|
||||
//File hfile = new File(path);
|
||||
//if (!hfile.exists()) return; // no history yet
|
||||
if (!historyFile.exists()) return;
|
||||
|
||||
JMenuItem item = new JMenuItem("Clear History");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!historyFile.delete()) {
|
||||
//System.err.println("couldn't erase history");
|
||||
Base.showWarning("History Problem",
|
||||
"Could not erase history", null);
|
||||
}
|
||||
rebuildMenu();
|
||||
//SketchHistory.this.rebuildMenu(historyFile.getPath());
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
menu.addSeparator();
|
||||
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(historyFile))));
|
||||
String line = null;
|
||||
|
||||
int historyCount = 0;
|
||||
String historyList[] = new String[100];
|
||||
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//while (line = reader.readLine()) {
|
||||
//while (true) { line = reader.readLine();
|
||||
//if (line == null) continue;
|
||||
//System.out.println("line: " + line);
|
||||
if (line.equals(HISTORY_SEPARATOR)) {
|
||||
// next line is the good stuff
|
||||
line = reader.readLine();
|
||||
int version =
|
||||
Integer.parseInt(line.substring(0, line.indexOf(' ')));
|
||||
if (version == 1) {
|
||||
String whysub = line.substring(2); // after "1 "
|
||||
String why = whysub.substring(0, whysub.indexOf(" -"));
|
||||
//System.out.println("'" + why + "'");
|
||||
|
||||
String readable = line.substring(line.lastIndexOf("-") + 2);
|
||||
if (historyList.length == historyCount) {
|
||||
String temp[] = new String[historyCount*2];
|
||||
System.arraycopy(historyList, 0, temp, 0, historyCount);
|
||||
historyList = temp;
|
||||
}
|
||||
historyList[historyCount++] = why + " - " + readable;
|
||||
|
||||
} // otherwise don't know what to do
|
||||
}
|
||||
}
|
||||
//System.out.println(line);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// add the items to the menu in reverse order
|
||||
|
||||
//ActionListener historyMenuListener =
|
||||
// new ActionListener() {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// editor.retrieveHistory(e.getActionCommand());
|
||||
//}
|
||||
//};
|
||||
|
||||
for (int i = historyCount-1; i >= 0; --i) {
|
||||
JMenuItem mi = new JMenuItem(historyList[i]);
|
||||
mi.addActionListener(menuListener);
|
||||
menu.add(mi);
|
||||
}
|
||||
|
||||
reader.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
647
app/Sketchbook.java
Normal file
647
app/Sketchbook.java
Normal file
@ -0,0 +1,647 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.*;
|
||||
|
||||
import com.apple.mrj.*;
|
||||
|
||||
|
||||
/**
|
||||
* Handles sketchbook mechanics for the sketch menu and file I/O.
|
||||
*/
|
||||
public class Sketchbook {
|
||||
Editor editor;
|
||||
|
||||
JMenu openMenu;
|
||||
JMenu popupMenu;
|
||||
//JMenu examples;
|
||||
JMenu importMenu;
|
||||
|
||||
// set to true after the first time it's built.
|
||||
// so that the errors while building don't show up again.
|
||||
boolean builtOnce;
|
||||
|
||||
//File sketchbookFolder;
|
||||
//String sketchbookPath; // canonical path
|
||||
|
||||
// last file/directory used for file opening
|
||||
//String handleOpenDirectory;
|
||||
// opted against this.. in imovie, apple always goes
|
||||
// to the "Movies" folder, even if that wasn't the last used
|
||||
|
||||
// these are static because they're used by Sketch
|
||||
static File examplesFolder;
|
||||
static String examplesPath; // canonical path (for comparison)
|
||||
|
||||
static File librariesFolder;
|
||||
static String librariesPath;
|
||||
|
||||
// maps imported packages to their library folder
|
||||
static Hashtable importToLibraryTable = new Hashtable();
|
||||
|
||||
// classpath for all known libraries for p5
|
||||
// (both those in the p5/libs folder and those with lib subfolders
|
||||
// found in the sketchbook)
|
||||
static String librariesClassPath;
|
||||
|
||||
|
||||
public Sketchbook(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
// this shouldn't change throughout.. it may as well be static
|
||||
// but only one instance of sketchbook will be built so who cares
|
||||
examplesFolder = new File(System.getProperty("user.dir"), "examples");
|
||||
examplesPath = examplesFolder.getAbsolutePath();
|
||||
|
||||
librariesFolder = new File(System.getProperty("user.dir"), "libraries");
|
||||
librariesPath = librariesFolder.getAbsolutePath();
|
||||
|
||||
String sketchbookPath = Preferences.get("sketchbook.path");
|
||||
|
||||
// if a value is at least set, first check to see if the
|
||||
// folder exists. if it doesn't, warn the user that the
|
||||
// sketchbook folder is being reset.
|
||||
if (sketchbookPath != null) {
|
||||
File skechbookFolder = new File(sketchbookPath);
|
||||
if (!skechbookFolder.exists()) {
|
||||
Base.showWarning("Sketchbook folder disappeared",
|
||||
"The sketchbook folder no longer exists,\n" +
|
||||
"so a new sketchbook will be created in the\n" +
|
||||
"default location.", null);
|
||||
sketchbookPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (sketchbookPath == null) {
|
||||
// by default, set default sketchbook path to the user's
|
||||
// home folder with 'sketchbook' as a subdirectory of that
|
||||
|
||||
/*
|
||||
File home = new File(System.getProperty("user.home"));
|
||||
|
||||
if (Base.platform == Base.MACOSX) {
|
||||
// on macosx put the sketchbook in the "Documents" folder
|
||||
home = new File(home, "Documents");
|
||||
|
||||
} else if (Base.platform == Base.WINDOWS) {
|
||||
// on windows put the sketchbook in the "My Documents" folder
|
||||
home = new File(home, "My Documents");
|
||||
}
|
||||
*/
|
||||
|
||||
// use a subfolder called 'sketchbook'
|
||||
//File home = Preferences.getProcessingHome();
|
||||
//String folderName = Preferences.get("sketchbook.name.default");
|
||||
//File sketchbookFolder = new File(home, folderName);
|
||||
|
||||
//System.out.println("resetting sketchbook path");
|
||||
File sketchbookFolder = Base.getDefaultSketchbookFolder();
|
||||
Preferences.set("sketchbook.path",
|
||||
sketchbookFolder.getAbsolutePath());
|
||||
|
||||
if (!sketchbookFolder.exists()) sketchbookFolder.mkdirs();
|
||||
}
|
||||
openMenu = new JMenu("Sketchbook");
|
||||
popupMenu = new JMenu("Sketchbook");
|
||||
importMenu = new JMenu("Import Library");
|
||||
}
|
||||
|
||||
|
||||
static public String getSketchbookPath() {
|
||||
return Preferences.get("sketchbook.path");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle creating a sketch folder, return its base .pde file
|
||||
* or null if the operation was cancelled.
|
||||
*/
|
||||
public String handleNew(boolean noPrompt,
|
||||
boolean shift,
|
||||
boolean library) throws IOException {
|
||||
File newbieDir = null;
|
||||
String newbieName = null;
|
||||
|
||||
boolean prompt = Preferences.getBoolean("sketchbook.prompt");
|
||||
if (shift) prompt = !prompt; // reverse behavior if shift is down
|
||||
|
||||
// no sketch has been started, don't prompt for the name if it's
|
||||
// starting up, just make the farker. otherwise if the person hits
|
||||
// 'cancel' i'd have to add a thing to make p5 quit, which is silly.
|
||||
// instead give them an empty sketch, and they can look at examples.
|
||||
// i hate it when imovie makes you start with that goofy dialog box.
|
||||
// unless, ermm, they user tested it and people preferred that as
|
||||
// a way to get started. shite. now i hate myself.
|
||||
//
|
||||
if (noPrompt) prompt = false;
|
||||
|
||||
if (prompt) {
|
||||
//if (!startup) {
|
||||
// prompt for the filename and location for the new sketch
|
||||
|
||||
FileDialog fd = new FileDialog(editor, //new Frame(),
|
||||
//"Create new sketch named",
|
||||
"Create sketch folder named:",
|
||||
FileDialog.SAVE);
|
||||
fd.setDirectory(getSketchbookPath());
|
||||
fd.show();
|
||||
|
||||
String newbieParentDir = fd.getDirectory();
|
||||
newbieName = fd.getFile();
|
||||
if (newbieName == null) return null;
|
||||
|
||||
newbieName = sanitizeName(newbieName);
|
||||
newbieDir = new File(newbieParentDir, newbieName);
|
||||
|
||||
} else {
|
||||
// use a generic name like sketch_031008a, the date plus a char
|
||||
String newbieParentDir = getSketchbookPath();
|
||||
|
||||
int index = 0;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
|
||||
String purty = formatter.format(new Date());
|
||||
do {
|
||||
newbieName = "sketch_" + purty + ((char) ('a' + index));
|
||||
newbieDir = new File(newbieParentDir, newbieName);
|
||||
index++;
|
||||
} while (newbieDir.exists());
|
||||
}
|
||||
|
||||
// make the directory for the new sketch
|
||||
newbieDir.mkdirs();
|
||||
|
||||
// if it's a library, make a library subfolder to tag it as such
|
||||
if (library) {
|
||||
new File(newbieDir, "library").mkdirs();
|
||||
}
|
||||
|
||||
// make an empty pde file
|
||||
File newbieFile = new File(newbieDir, newbieName + ".pde");
|
||||
new FileOutputStream(newbieFile); // create the file
|
||||
|
||||
// TODO this wouldn't be needed if i could figure out how to
|
||||
// associate document icons via a dot-extension/mime-type scenario
|
||||
// help me steve jobs, you're my only hope.
|
||||
|
||||
// jdk13 on osx, or jdk11
|
||||
// though apparently still available for 1.4
|
||||
if (Base.isMacOS()) {
|
||||
MRJFileUtils.setFileTypeAndCreator(newbieFile,
|
||||
MRJOSType.kTypeTEXT,
|
||||
new MRJOSType("Pde1"));
|
||||
// thank you apple, for changing this @#$)(*
|
||||
//com.apple.eio.setFileTypeAndCreator(String filename, int, int)
|
||||
}
|
||||
|
||||
// make a note of a newly added sketch in the sketchbook menu
|
||||
rebuildMenus();
|
||||
|
||||
// now open it up
|
||||
//handleOpen(newbieName, newbieFile, newbieDir);
|
||||
//return newSketch;
|
||||
return newbieFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert to sanitized name and alert the user
|
||||
* if changes were made.
|
||||
*/
|
||||
static public String sanitizeName(String origName) {
|
||||
String newName = sanitizedName(origName);
|
||||
|
||||
if (!newName.equals(origName)) {
|
||||
Base.showMessage("Naming issue",
|
||||
"The sketch name had to be modified.\n" +
|
||||
"You can only use basic letters and numbers\n" +
|
||||
"to name a sketch (ascii only and no spaces,\n" +
|
||||
"it can't start with a number, and should be\n" +
|
||||
"less than 64 characters long)");
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Java classes are pretty limited about what you can use
|
||||
* for their naming. This helper function replaces everything
|
||||
* but A-Z, a-z, and 0-9 with underscores. Also disallows
|
||||
* starting the sketch name with a digit.
|
||||
*/
|
||||
static public String sanitizedName(String origName) {
|
||||
char c[] = origName.toCharArray();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
// can't lead with a digit, so start with an underscore
|
||||
if ((c[0] >= '0') && (c[0] <= '9')) {
|
||||
buffer.append('_');
|
||||
}
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if (((c[i] >= '0') && (c[i] <= '9')) ||
|
||||
((c[i] >= 'a') && (c[i] <= 'z')) ||
|
||||
((c[i] >= 'A') && (c[i] <= 'Z'))) {
|
||||
buffer.append(c[i]);
|
||||
|
||||
} else {
|
||||
buffer.append('_');
|
||||
}
|
||||
}
|
||||
// let's not be ridiculous about the length of filenames
|
||||
if (buffer.length() > 63) {
|
||||
buffer.setLength(63);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public String handleOpen() {
|
||||
// swing's file choosers are ass ugly, so we use the
|
||||
// native (awt peered) dialogs instead
|
||||
FileDialog fd = new FileDialog(editor, //new Frame(),
|
||||
"Open a Processing sketch...",
|
||||
FileDialog.LOAD);
|
||||
//fd.setDirectory(Preferences.get("sketchbook.path"));
|
||||
fd.setDirectory(getSketchbookPath());
|
||||
|
||||
// only show .pde files as eligible bachelors
|
||||
// TODO this doesn't seem to ever be used. AWESOME.
|
||||
fd.setFilenameFilter(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
//System.out.println("check filter on " + dir + " " + name);
|
||||
return name.toLowerCase().endsWith(".pde");
|
||||
}
|
||||
});
|
||||
|
||||
// gimme some money
|
||||
fd.show();
|
||||
|
||||
// what in the hell yu want, boy?
|
||||
String directory = fd.getDirectory();
|
||||
String filename = fd.getFile();
|
||||
|
||||
// user cancelled selection
|
||||
if (filename == null) return null;
|
||||
|
||||
// this may come in handy sometime
|
||||
//handleOpenDirectory = directory;
|
||||
|
||||
File selection = new File(directory, filename);
|
||||
return selection.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rebuild the menu full of sketches based on the
|
||||
* contents of the sketchbook.
|
||||
*
|
||||
* Creates a separate JMenu object for the popup,
|
||||
* because it seems that after calling "getPopupMenu"
|
||||
* the menu will disappear from its original location.
|
||||
*/
|
||||
public void rebuildMenus() {
|
||||
try {
|
||||
// rebuild file/open and the toolbar popup menus
|
||||
buildMenu(openMenu);
|
||||
builtOnce = true; // disable error messages while loading
|
||||
buildMenu(popupMenu);
|
||||
|
||||
// rebuild the "import library" menu
|
||||
librariesClassPath = "";
|
||||
importMenu.removeAll();
|
||||
if (addLibraries(importMenu, new File(getSketchbookPath()))) {
|
||||
importMenu.addSeparator();
|
||||
}
|
||||
if (addLibraries(importMenu, examplesFolder)) {
|
||||
importMenu.addSeparator();
|
||||
}
|
||||
addLibraries(importMenu, librariesFolder);
|
||||
//System.out.println("libraries cp is now " + librariesClassPath);
|
||||
|
||||
} catch (IOException e) {
|
||||
Base.showWarning("Problem while building sketchbook menu",
|
||||
"There was a problem with building the\n" +
|
||||
"sketchbook menu. Things might get a little\n" +
|
||||
"kooky around here.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void buildMenu(JMenu menu) {
|
||||
JMenuItem item;
|
||||
|
||||
// rebuild the popup menu
|
||||
menu.removeAll();
|
||||
|
||||
//item = new JMenuItem("Open...");
|
||||
item = Editor.newJMenuItem("Open...", 'O', false);
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.handleOpen(null);
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
menu.addSeparator();
|
||||
|
||||
try {
|
||||
boolean sketches =
|
||||
addSketches(menu, new File(getSketchbookPath()));
|
||||
if (sketches) menu.addSeparator();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
JMenu examplesMenu = new JMenu("Examples");
|
||||
addSketches(examplesMenu, examplesFolder);
|
||||
menu.add(examplesMenu);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
/*
|
||||
// don't do this until it's finished
|
||||
// libraries don't show up as proper sketches anyway
|
||||
try {
|
||||
if (Preferences.getBoolean("export.library")) {
|
||||
JMenu librariesMenu = new JMenu("Libraries");
|
||||
addSketches(librariesMenu, librariesFolder);
|
||||
menu.add(librariesMenu);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public JMenu getOpenMenu() {
|
||||
if (openMenu == null) rebuildMenus();
|
||||
return openMenu;
|
||||
}
|
||||
|
||||
|
||||
public JPopupMenu getPopupMenu() {
|
||||
if (popupMenu == null) rebuildMenus();
|
||||
return popupMenu.getPopupMenu();
|
||||
}
|
||||
|
||||
|
||||
public JMenu getImportMenu() {
|
||||
return importMenu;
|
||||
}
|
||||
|
||||
|
||||
protected boolean addSketches(JMenu menu, File folder) throws IOException {
|
||||
// skip .DS_Store files, etc
|
||||
if (!folder.isDirectory()) return false;
|
||||
|
||||
String list[] = folder.list();
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null) return false;
|
||||
|
||||
// alphabetize list, since it's not always alpha order
|
||||
// use cheapie bubble-style sort which should be fine
|
||||
// since not a tone of files, and things will mostly be sorted
|
||||
// or may be completely sorted already by the os
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
int who = i;
|
||||
for (int j = i+1; j < list.length; j++) {
|
||||
if (list[j].compareToIgnoreCase(list[who]) < 0) {
|
||||
who = j; // this guy is earlier in the alphabet
|
||||
}
|
||||
}
|
||||
if (who != i) { // swap with someone if changes made
|
||||
String temp = list[who];
|
||||
list[who] = list[i];
|
||||
list[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
//SketchbookMenuListener listener =
|
||||
//new SketchbookMenuListener(folder.getAbsolutePath());
|
||||
|
||||
ActionListener listener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.handleOpen(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
|
||||
boolean ifound = false;
|
||||
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if ((list[i].charAt(0) == '.') ||
|
||||
list[i].equals("CVS")) continue;
|
||||
|
||||
File subfolder = new File(folder, list[i]);
|
||||
File lib = new File(subfolder, "library");
|
||||
File entry = new File(subfolder, list[i] + ".pde");
|
||||
// if a .pde file of the same prefix as the folder exists..
|
||||
if (entry.exists()) {
|
||||
String sanityCheck = sanitizedName(list[i]);
|
||||
if (!sanityCheck.equals(list[i])) {
|
||||
if (!builtOnce) {
|
||||
String mess =
|
||||
"The sketch \"" + list[i] + "\" cannot be used.\n" +
|
||||
"Sketch names must contain only basic letters and numbers.\n" +
|
||||
"(ascii only and no spaces, and it cannot start with a number)";
|
||||
Base.showMessage("Ignoring bad sketch name", mess);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
JMenuItem item = new JMenuItem(list[i]);
|
||||
item.addActionListener(listener);
|
||||
item.setActionCommand(entry.getAbsolutePath());
|
||||
menu.add(item);
|
||||
ifound = true;
|
||||
|
||||
} else { // might contain other dirs, get recursive
|
||||
JMenu submenu = new JMenu(list[i]);
|
||||
// needs to be separate var
|
||||
// otherwise would set ifound to false
|
||||
boolean found = addSketches(submenu, subfolder); //, false);
|
||||
if (found) {
|
||||
menu.add(submenu);
|
||||
ifound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ifound; // actually ignored, but..
|
||||
}
|
||||
|
||||
|
||||
protected boolean addLibraries(JMenu menu, File folder) throws IOException {
|
||||
// skip .DS_Store files, etc
|
||||
if (!folder.isDirectory()) return false;
|
||||
|
||||
String list[] = folder.list();
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null) return false;
|
||||
|
||||
// alphabetize list, since it's not always alpha order
|
||||
// use cheapie bubble-style sort which should be fine
|
||||
// since not a tone of files, and things will mostly be sorted
|
||||
// or may be completely sorted already by the os
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
int who = i;
|
||||
for (int j = i+1; j < list.length; j++) {
|
||||
if (list[j].compareToIgnoreCase(list[who]) < 0) {
|
||||
who = j; // this guy is earlier in the alphabet
|
||||
}
|
||||
}
|
||||
if (who != i) { // swap with someone if changes made
|
||||
String temp = list[who];
|
||||
list[who] = list[i];
|
||||
list[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
ActionListener listener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.importLibrary(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
|
||||
boolean ifound = false;
|
||||
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if ((list[i].charAt(0) == '.') ||
|
||||
list[i].equals("CVS")) continue;
|
||||
|
||||
File subfolder = new File(folder, list[i]);
|
||||
File exported = new File(subfolder, "library");
|
||||
File entry = new File(exported, list[i] + ".jar");
|
||||
// if a .jar file of the same prefix as the folder exists
|
||||
// inside the 'library' subfolder of the sketch
|
||||
if (entry.exists()) {
|
||||
String sanityCheck = sanitizedName(list[i]);
|
||||
if (!sanityCheck.equals(list[i])) {
|
||||
String mess =
|
||||
"The library \"" + list[i] + "\" cannot be used.\n" +
|
||||
"Library names must contain only basic letters and numbers.\n" +
|
||||
"(ascii only and no spaces, and it cannot start with a number)";
|
||||
Base.showMessage("Ignoring bad sketch name", mess);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the path for all .jar files in this code folder
|
||||
String libraryClassPath =
|
||||
Compiler.contentsToClassPath(exported);
|
||||
// grab all jars and classes from this folder,
|
||||
// and append them to the library classpath
|
||||
librariesClassPath +=
|
||||
File.pathSeparatorChar + libraryClassPath;
|
||||
// need to associate each import with a library folder
|
||||
String packages[] =
|
||||
Compiler.packageListFromClassPath(libraryClassPath);
|
||||
for (int k = 0; k < packages.length; k++) {
|
||||
importToLibraryTable.put(packages[k], exported);
|
||||
}
|
||||
|
||||
JMenuItem item = new JMenuItem(list[i]);
|
||||
item.addActionListener(listener);
|
||||
item.setActionCommand(entry.getAbsolutePath());
|
||||
menu.add(item);
|
||||
ifound = true;
|
||||
|
||||
} else { // might contain other dirs, get recursive
|
||||
JMenu submenu = new JMenu(list[i]);
|
||||
// needs to be separate var
|
||||
// otherwise would set ifound to false
|
||||
boolean found = addLibraries(submenu, subfolder); //, false);
|
||||
if (found) {
|
||||
menu.add(submenu);
|
||||
ifound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ifound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear out projects that are empty.
|
||||
*/
|
||||
public void clean() {
|
||||
//if (!Preferences.getBoolean("sketchbook.auto_clean")) return;
|
||||
|
||||
File sketchbookFolder = new File(getSketchbookPath());
|
||||
if (!sketchbookFolder.exists()) return;
|
||||
|
||||
//String entries[] = new File(userPath).list();
|
||||
String entries[] = sketchbookFolder.list();
|
||||
if (entries != null) {
|
||||
for (int j = 0; j < entries.length; j++) {
|
||||
//System.out.println(entries[j] + " " + entries.length);
|
||||
if (entries[j].charAt(0) == '.') continue;
|
||||
|
||||
//File prey = new File(userPath, entries[j]);
|
||||
File prey = new File(sketchbookFolder, entries[j]);
|
||||
File pde = new File(prey, entries[j] + ".pde");
|
||||
|
||||
// make sure this is actually a sketch folder with a .pde,
|
||||
// not a .DS_Store file or another random user folder
|
||||
|
||||
if (pde.exists() &&
|
||||
(Base.calcFolderSize(prey) == 0)) {
|
||||
//System.out.println("i want to remove " + prey);
|
||||
|
||||
if (Preferences.getBoolean("sketchbook.auto_clean")) {
|
||||
Base.removeDir(prey);
|
||||
|
||||
} else { // otherwise prompt the user
|
||||
String prompt =
|
||||
"Remove empty sketch titled \"" + entries[j] + "\"?";
|
||||
|
||||
Object[] options = { "Yes", "No" };
|
||||
int result =
|
||||
JOptionPane.showOptionDialog(editor,
|
||||
prompt,
|
||||
"Housekeeping",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
if (result == JOptionPane.YES_OPTION) {
|
||||
Base.removeDir(prey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
app/SwingWorker.java
Normal file
131
app/SwingWorker.java
Normal file
@ -0,0 +1,131 @@
|
||||
package processing.app;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* This is the 3rd version of SwingWorker (also known as
|
||||
* SwingWorker 3), an abstract class that you subclass to
|
||||
* perform GUI-related work in a dedicated thread. For
|
||||
* instructions on and examples of using this class, see:
|
||||
*
|
||||
* http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
|
||||
*
|
||||
* Note that the API changed slightly in the 3rd version:
|
||||
* You must now invoke start() on the SwingWorker after
|
||||
* creating it.
|
||||
*/
|
||||
public abstract class SwingWorker {
|
||||
private Object value; // see getValue(), setValue()
|
||||
|
||||
/**
|
||||
* Class to maintain reference to current worker thread
|
||||
* under separate synchronization control.
|
||||
*/
|
||||
private static class ThreadVar {
|
||||
private Thread thread;
|
||||
ThreadVar(Thread t) { thread = t; }
|
||||
synchronized Thread get() { return thread; }
|
||||
synchronized void clear() { thread = null; }
|
||||
}
|
||||
|
||||
private ThreadVar threadVar;
|
||||
|
||||
/**
|
||||
* Get the value produced by the worker thread, or null if it
|
||||
* hasn't been constructed yet.
|
||||
*/
|
||||
protected synchronized Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value produced by worker thread
|
||||
*/
|
||||
private synchronized void setValue(Object x) {
|
||||
value = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the value to be returned by the <code>get</code> method.
|
||||
*/
|
||||
public abstract Object construct();
|
||||
|
||||
/**
|
||||
* Called on the event dispatching thread (not on the worker thread)
|
||||
* after the <code>construct</code> method has returned.
|
||||
*/
|
||||
public void finished() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A new method that interrupts the worker thread. Call this method
|
||||
* to force the worker to stop what it's doing.
|
||||
*/
|
||||
public void interrupt() {
|
||||
Thread t = threadVar.get();
|
||||
if (t != null) {
|
||||
t.interrupt();
|
||||
}
|
||||
threadVar.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value created by the <code>construct</code> method.
|
||||
* Returns null if either the constructing thread or the current
|
||||
* thread was interrupted before a value was produced.
|
||||
*
|
||||
* @return the value created by the <code>construct</code> method
|
||||
*/
|
||||
public Object get() {
|
||||
while (true) {
|
||||
Thread t = threadVar.get();
|
||||
if (t == null) {
|
||||
return getValue();
|
||||
}
|
||||
try {
|
||||
t.join();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt(); // propagate
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start a thread that will call the <code>construct</code> method
|
||||
* and then exit.
|
||||
*/
|
||||
public SwingWorker() {
|
||||
final Runnable doFinished = new Runnable() {
|
||||
public void run() { finished(); }
|
||||
};
|
||||
|
||||
Runnable doConstruct = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
setValue(construct());
|
||||
}
|
||||
finally {
|
||||
threadVar.clear();
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(doFinished);
|
||||
}
|
||||
};
|
||||
|
||||
Thread t = new Thread(doConstruct);
|
||||
threadVar = new ThreadVar(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the worker thread.
|
||||
*/
|
||||
public void start() {
|
||||
Thread t = threadVar.get();
|
||||
if (t != null) {
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
143
app/UpdateCheck.java
Executable file
143
app/UpdateCheck.java
Executable file
@ -0,0 +1,143 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2005 Ben Fry and Casey Reas
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.*;
|
||||
|
||||
import com.apple.mrj.*;
|
||||
import com.ice.jni.registry.*;
|
||||
|
||||
//import processing.core.*;
|
||||
|
||||
|
||||
/**
|
||||
* Threaded class to check for updates in the background.
|
||||
* <P>
|
||||
* This is the class that handles the mind control and stuff for
|
||||
* spying on our users and stealing their personal information.
|
||||
* A random ID number is generated for each user, and hits the server
|
||||
* to check for updates. Also included is the operating system and
|
||||
* its version and the version of Java being used to run Processing.
|
||||
* <P>
|
||||
* The ID number also helps provide us a general idea of how many
|
||||
* people are using Processing, which helps us when writing grant
|
||||
* proposals and that kind of thing so that we can keep Processing free.
|
||||
*/
|
||||
public class UpdateCheck implements Runnable {
|
||||
Editor editor;
|
||||
String downloadURL = "http://arduino.berlios.de/latest.txt";
|
||||
|
||||
static final long ONE_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
|
||||
public UpdateCheck(Editor editor) {
|
||||
this.editor = editor;
|
||||
Thread thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
//System.out.println("checking for updates...");
|
||||
|
||||
// generate a random id in case none exists yet
|
||||
Random r = new Random();
|
||||
long id = r.nextLong();
|
||||
|
||||
String idString = Preferences.get("update.id");
|
||||
if (idString != null) {
|
||||
id = Long.parseLong(idString);
|
||||
} else {
|
||||
Preferences.set("update.id", String.valueOf(id));
|
||||
}
|
||||
|
||||
String info =
|
||||
URLEncoder.encode(id + "\t" +
|
||||
Base.VERSION+ "\t" +
|
||||
System.getProperty("java.version") + "\t" +
|
||||
System.getProperty("java.vendor") + "\t" +
|
||||
System.getProperty("os.name") + "\t" +
|
||||
System.getProperty("os.version") + "\t" +
|
||||
System.getProperty("os.arch"));
|
||||
|
||||
try {
|
||||
int latest = readInt(downloadURL + "?" + info);
|
||||
|
||||
String lastString = Preferences.get("update.last");
|
||||
long now = System.currentTimeMillis();
|
||||
if (lastString != null) {
|
||||
long when = Long.parseLong(lastString);
|
||||
if (now - when < ONE_DAY) {
|
||||
// don't annoy the shit outta people
|
||||
return;
|
||||
}
|
||||
}
|
||||
Preferences.set("update.last", String.valueOf(now));
|
||||
|
||||
String prompt =
|
||||
"A new version of Processing is available,\n" +
|
||||
"would you like to visit the Processing download page?";
|
||||
|
||||
if (latest > Base.VERSION) {
|
||||
Object[] options = { "Yes", "No" };
|
||||
int result = JOptionPane.showOptionDialog(editor,
|
||||
prompt,
|
||||
"Update",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
if (result == JOptionPane.YES_OPTION) {
|
||||
Base.openURL("http://processing.org/download/");
|
||||
|
||||
//} else if (result == JOptionPane.NO_OPTION) {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//e.printStackTrace();
|
||||
//System.err.println("Error while trying to check for an update.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int readInt(String filename) throws Exception {
|
||||
URL url = new URL(filename);
|
||||
InputStream stream = url.openStream();
|
||||
InputStreamReader isr = new InputStreamReader(stream);
|
||||
BufferedReader reader = new BufferedReader(isr);
|
||||
return Integer.parseInt(reader.readLine());
|
||||
}
|
||||
}
|
300
app/exportapplet.txt
Normal file
300
app/exportapplet.txt
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
// make sure the user didn't hide the sketch folder
|
||||
ensureExistence();
|
||||
|
||||
zipFileContents = new Hashtable();
|
||||
|
||||
// nuke the old applet folder because it can cause trouble
|
||||
File appletFolder = new File(folder, "applet");
|
||||
Base.removeDir(appletFolder);
|
||||
appletFolder.mkdirs();
|
||||
|
||||
// build the sketch
|
||||
String foundName = build(appletFolder.getPath(), name);
|
||||
|
||||
// (already reported) error during export, exit this function
|
||||
if (foundName == null) return false;
|
||||
|
||||
// if name != exportSketchName, then that's weirdness
|
||||
// BUG unfortunately, that can also be a bug in the preproc :(
|
||||
if (!name.equals(foundName)) {
|
||||
Base.showWarning("Error during export",
|
||||
"Sketch name is " + name + " but the sketch\n" +
|
||||
"name in the code was " + foundName, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
int wide = PApplet.DEFAULT_WIDTH;
|
||||
int high = PApplet.DEFAULT_HEIGHT;
|
||||
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
|
||||
// this matches against any uses of the size() function,
|
||||
// whether they contain numbers of variables or whatever.
|
||||
// this way, no warning is shown if size() isn't actually
|
||||
// used in the applet, which is the case especially for
|
||||
// beginners that are cutting/pasting from the reference.
|
||||
// modified for 83 to match size(XXX, ddd so that it'll
|
||||
// properly handle size(200, 200) and size(200, 200, P3D)
|
||||
String sizing =
|
||||
"[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)";
|
||||
Pattern pattern = compiler.compile(sizing);
|
||||
|
||||
// adds a space at the beginning, in case size() is the very
|
||||
// first thing in the program (very common), since the regexp
|
||||
// needs to check for things in front of it.
|
||||
PatternMatcherInput input =
|
||||
new PatternMatcherInput(" " + code[0].program);
|
||||
if (matcher.contains(input, pattern)) {
|
||||
MatchResult result = matcher.getMatch();
|
||||
try {
|
||||
wide = Integer.parseInt(result.group(1).toString());
|
||||
high = Integer.parseInt(result.group(2).toString());
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
// found a reference to size, but it didn't
|
||||
// seem to contain numbers
|
||||
final String message =
|
||||
"The size of this applet could not automatically be\n" +
|
||||
"determined from your code. You'll have to edit the\n" +
|
||||
"HTML file to set the size of the applet.";
|
||||
|
||||
Base.showWarning("Could not find applet size", message, null);
|
||||
}
|
||||
} // else no size() command found
|
||||
|
||||
// originally tried to grab this with a regexp matcher,
|
||||
// but it wouldn't span over multiple lines for the match.
|
||||
// this could prolly be forced, but since that's the case
|
||||
// better just to parse by hand.
|
||||
StringBuffer dbuffer = new StringBuffer();
|
||||
String lines[] = PApplet.split(code[0].program, '\n');
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (lines[i].trim().startsWith("/**")) { // this is our comment
|
||||
// some smartass put the whole thing on the same line
|
||||
//if (lines[j].indexOf("*/") != -1) break;
|
||||
|
||||
for (int j = i+1; j < lines.length; j++) {
|
||||
if (lines[j].trim().endsWith("*/")) {
|
||||
// remove the */ from the end, and any extra *s
|
||||
// in case there's also content on this line
|
||||
// nah, don't bother.. make them use the three lines
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
while ((offset < lines[j].length()) &&
|
||||
((lines[j].charAt(offset) == '*') ||
|
||||
(lines[j].charAt(offset) == ' '))) {
|
||||
offset++;
|
||||
}
|
||||
// insert the return into the html to help w/ line breaks
|
||||
dbuffer.append(lines[j].substring(offset) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
String description = dbuffer.toString();
|
||||
|
||||
StringBuffer sources = new StringBuffer();
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
sources.append("<a href=\"" + code[i].file.getName() + "\">" +
|
||||
code[i].name + "</a> ");
|
||||
}
|
||||
|
||||
File htmlOutputFile = new File(appletFolder, "index.html");
|
||||
FileOutputStream fos = new FileOutputStream(htmlOutputFile);
|
||||
PrintStream ps = new PrintStream(fos);
|
||||
|
||||
// @@sketch@@, @@width@@, @@height@@, @@archive@@, @@source@@
|
||||
// and now @@description@@
|
||||
|
||||
InputStream is = null;
|
||||
// if there is an applet.html file in the sketch folder, use that
|
||||
File customHtml = new File(folder, "applet.html");
|
||||
if (customHtml.exists()) {
|
||||
is = new FileInputStream(customHtml);
|
||||
}
|
||||
if (is == null) {
|
||||
is = Base.getStream("applet.html");
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.indexOf("@@") != -1) {
|
||||
StringBuffer sb = new StringBuffer(line);
|
||||
int index = 0;
|
||||
while ((index = sb.indexOf("@@sketch@@")) != -1) {
|
||||
sb.replace(index, index + "@@sketch@@".length(),
|
||||
name);
|
||||
}
|
||||
while ((index = sb.indexOf("@@source@@")) != -1) {
|
||||
sb.replace(index, index + "@@source@@".length(),
|
||||
sources.toString());
|
||||
}
|
||||
while ((index = sb.indexOf("@@archive@@")) != -1) {
|
||||
sb.replace(index, index + "@@archive@@".length(),
|
||||
name + ".jar");
|
||||
}
|
||||
while ((index = sb.indexOf("@@width@@")) != -1) {
|
||||
sb.replace(index, index + "@@width@@".length(),
|
||||
String.valueOf(wide));
|
||||
}
|
||||
while ((index = sb.indexOf("@@height@@")) != -1) {
|
||||
sb.replace(index, index + "@@height@@".length(),
|
||||
String.valueOf(high));
|
||||
}
|
||||
while ((index = sb.indexOf("@@description@@")) != -1) {
|
||||
sb.replace(index, index + "@@description@@".length(),
|
||||
description);
|
||||
}
|
||||
line = sb.toString();
|
||||
}
|
||||
ps.println(line);
|
||||
}
|
||||
|
||||
reader.close();
|
||||
ps.flush();
|
||||
ps.close();
|
||||
|
||||
// copy the loading gif to the applet
|
||||
String LOADING_IMAGE = "loading.gif";
|
||||
File loadingImage = new File(folder, LOADING_IMAGE);
|
||||
if (!loadingImage.exists()) {
|
||||
loadingImage = new File("lib", LOADING_IMAGE);
|
||||
}
|
||||
Base.copyFile(loadingImage, new File(appletFolder, LOADING_IMAGE));
|
||||
|
||||
// copy the source files to the target, since we like
|
||||
// to encourage people to share their code
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
try {
|
||||
Base.copyFile(code[i].file,
|
||||
new File(appletFolder, code[i].file.getName()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// create new .jar file
|
||||
FileOutputStream zipOutputFile =
|
||||
new FileOutputStream(new File(appletFolder, name + ".jar"));
|
||||
ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
|
||||
ZipEntry entry;
|
||||
|
||||
// add the manifest file
|
||||
addManifest(zos);
|
||||
|
||||
// add the contents of the code folder to the jar
|
||||
// unpacks all jar files
|
||||
//File codeFolder = new File(folder, "code");
|
||||
if (codeFolder.exists()) {
|
||||
String includes = Compiler.contentsToClassPath(codeFolder);
|
||||
packClassPathIntoZipFile(includes, zos);
|
||||
}
|
||||
|
||||
// add contents of 'library' folders to the jar file
|
||||
// if a file called 'export.txt' is in there, it contains
|
||||
// a list of the files that should be exported.
|
||||
// otherwise, all files are exported.
|
||||
Enumeration en = importedLibraries.elements();
|
||||
while (en.hasMoreElements()) {
|
||||
// in the list is a File object that points the
|
||||
// library sketch's "library" folder
|
||||
File libraryFolder = (File)en.nextElement();
|
||||
File exportSettings = new File(libraryFolder, "export.txt");
|
||||
String exportList[] = null;
|
||||
if (exportSettings.exists()) {
|
||||
String info[] = Base.loadStrings(exportSettings);
|
||||
for (int i = 0; i < info.length; i++) {
|
||||
if (info[i].startsWith("applet")) {
|
||||
int idx = info[i].indexOf('='); // get applet= or applet =
|
||||
String commas = info[i].substring(idx+1).trim();
|
||||
exportList = PApplet.split(commas, ", ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exportList = libraryFolder.list();
|
||||
}
|
||||
for (int i = 0; i < exportList.length; i++) {
|
||||
if (exportList[i].equals(".") ||
|
||||
exportList[i].equals("..")) continue;
|
||||
|
||||
exportList[i] = PApplet.trim(exportList[i]);
|
||||
if (exportList[i].equals("")) continue;
|
||||
|
||||
File exportFile = new File(libraryFolder, exportList[i]);
|
||||
if (!exportFile.exists()) {
|
||||
System.err.println("File " + exportList[i] + " does not exist");
|
||||
|
||||
} else if (exportFile.isDirectory()) {
|
||||
System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
|
||||
|
||||
} else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
|
||||
exportFile.getName().toLowerCase().endsWith(".jar")) {
|
||||
packClassPathIntoZipFile(exportFile.getAbsolutePath(), zos);
|
||||
|
||||
} else { // just copy the file over.. prolly a .dll or something
|
||||
Base.copyFile(exportFile,
|
||||
new File(appletFolder, exportFile.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String bagelJar = "lib/core.jar";
|
||||
packClassPathIntoZipFile(bagelJar, zos);
|
||||
|
||||
// files to include from data directory
|
||||
// TODO this needs to be recursive
|
||||
if (dataFolder.exists()) {
|
||||
String dataFiles[] = dataFolder.list();
|
||||
for (int i = 0; i < dataFiles.length; i++) {
|
||||
// don't export hidden files
|
||||
// skipping dot prefix removes all: . .. .DS_Store
|
||||
if (dataFiles[i].charAt(0) == '.') continue;
|
||||
|
||||
entry = new ZipEntry(dataFiles[i]);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(Base.grabFile(new File(dataFolder, dataFiles[i])));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// add the project's .class files to the jar
|
||||
// just grabs everything from the build directory
|
||||
// since there may be some inner classes
|
||||
// (add any .class files from the applet dir, then delete them)
|
||||
// TODO this needs to be recursive (for packages)
|
||||
String classfiles[] = appletFolder.list();
|
||||
for (int i = 0; i < classfiles.length; i++) {
|
||||
if (classfiles[i].endsWith(".class")) {
|
||||
entry = new ZipEntry(classfiles[i]);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(Base.grabFile(new File(appletFolder, classfiles[i])));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// remove the .class files from the applet folder. if they're not
|
||||
// removed, the msjvm will complain about an illegal access error,
|
||||
// since the classes are outside the jar file.
|
||||
for (int i = 0; i < classfiles.length; i++) {
|
||||
if (classfiles[i].endsWith(".class")) {
|
||||
File deadguy = new File(appletFolder, classfiles[i]);
|
||||
if (!deadguy.delete()) {
|
||||
Base.showWarning("Could not delete",
|
||||
classfiles[i] + " could not \n" +
|
||||
"be deleted from the applet folder. \n" +
|
||||
"You'll need to remove it by hand.", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close up the jar file
|
||||
zos.flush();
|
||||
zos.close();
|
||||
|
||||
Base.openFolder(appletFolder);
|
||||
return true;
|
||||
*/
|
9
app/preproc/.cvsignore
Normal file
9
app/preproc/.cvsignore
Normal file
@ -0,0 +1,9 @@
|
||||
*Lexer.java
|
||||
*Recognizer.java
|
||||
*TokenTypes.java
|
||||
*TokenTypes.txt
|
||||
*TreeParser.java
|
||||
*TreeParserTokenTypes.java
|
||||
*TreeParserTokenTypes.txt
|
||||
expanded*.g
|
||||
|
132
app/preproc/ExtendedCommonASTWithHiddenTokens.java
Normal file
132
app/preproc/ExtendedCommonASTWithHiddenTokens.java
Normal file
@ -0,0 +1,132 @@
|
||||
package antlr;
|
||||
|
||||
/* ANTLR Translator Generator
|
||||
* Project led by Terence Parr at http://www.jGuru.com
|
||||
* Software rights: http://www.antlr.org/RIGHTS.html
|
||||
*
|
||||
* $Id: ExtendedCommonASTWithHiddenTokens.java,v 1.1 2005/04/09 02:30:36 benfry Exp $
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import antlr.*;
|
||||
import antlr.collections.*;
|
||||
import antlr.collections.impl.*;
|
||||
|
||||
/** A CommonAST whose initialization copies hidden token
|
||||
* information from the Token used to create a node.
|
||||
*/
|
||||
public class ExtendedCommonASTWithHiddenTokens
|
||||
extends CommonASTWithHiddenTokens {
|
||||
|
||||
public ExtendedCommonASTWithHiddenTokens() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ExtendedCommonASTWithHiddenTokens(Token tok) {
|
||||
super(tok);
|
||||
}
|
||||
|
||||
public void initialize(AST ast) {
|
||||
ExtendedCommonASTWithHiddenTokens a =
|
||||
(ExtendedCommonASTWithHiddenTokens)ast;
|
||||
super.initialize(a);
|
||||
hiddenBefore = a.getHiddenBefore();
|
||||
hiddenAfter = a.getHiddenAfter();
|
||||
}
|
||||
|
||||
public String getHiddenAfterString() {
|
||||
|
||||
CommonHiddenStreamToken t;
|
||||
StringBuffer hiddenAfterString = new StringBuffer(100);
|
||||
|
||||
for ( t = hiddenAfter ; t != null ; t = t.getHiddenAfter() ) {
|
||||
hiddenAfterString.append(t.getText());
|
||||
}
|
||||
|
||||
return hiddenAfterString.toString();
|
||||
}
|
||||
|
||||
public String getHiddenBeforeString() {
|
||||
|
||||
antlr.CommonHiddenStreamToken
|
||||
child = null,
|
||||
parent = hiddenBefore;
|
||||
|
||||
// if there aren't any hidden tokens here, quietly return
|
||||
//
|
||||
if (parent == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// traverse back to the head of the list of tokens before this node
|
||||
do {
|
||||
child = parent;
|
||||
parent = child.getHiddenBefore();
|
||||
} while (parent != null);
|
||||
|
||||
// dump that list
|
||||
|
||||
StringBuffer hiddenBeforeString = new StringBuffer(100);
|
||||
|
||||
for ( CommonHiddenStreamToken t = child; t != null ;
|
||||
t = t.getHiddenAfter() ) {
|
||||
hiddenBeforeString.append(t.getText());
|
||||
}
|
||||
|
||||
return hiddenBeforeString.toString();
|
||||
}
|
||||
|
||||
public void xmlSerializeNode(Writer out)
|
||||
throws IOException {
|
||||
StringBuffer buf = new StringBuffer(100);
|
||||
buf.append("<");
|
||||
buf.append(getClass().getName() + " ");
|
||||
|
||||
buf.append("hiddenBeforeString=\"" +
|
||||
encode(getHiddenBeforeString()) +
|
||||
"\" text=\"" + encode(getText()) + "\" type=\"" +
|
||||
getType() + "\" hiddenAfterString=\"" +
|
||||
encode(getHiddenAfterString()) + "\"/>");
|
||||
out.write(buf.toString());
|
||||
}
|
||||
|
||||
public void xmlSerializeRootOpen(Writer out)
|
||||
throws IOException {
|
||||
StringBuffer buf = new StringBuffer(100);
|
||||
buf.append("<");
|
||||
buf.append(getClass().getName() + " ");
|
||||
buf.append("hiddenBeforeString=\"" +
|
||||
encode(getHiddenBeforeString()) +
|
||||
"\" text=\"" + encode(getText()) + "\" type=\"" +
|
||||
getType() + "\" hiddenAfterString=\"" +
|
||||
encode(getHiddenAfterString()) + "\">\n");
|
||||
out.write(buf.toString());
|
||||
}
|
||||
|
||||
public void xmlSerializeRootClose(Writer out)
|
||||
throws IOException {
|
||||
out.write("</" + getClass().getName() + ">\n");
|
||||
}
|
||||
|
||||
public void xmlSerialize(Writer out) throws IOException {
|
||||
// print out this node and all siblings
|
||||
for (AST node = this;
|
||||
node != null;
|
||||
node = node.getNextSibling()) {
|
||||
if (node.getFirstChild() == null) {
|
||||
// print guts (class name, attributes)
|
||||
((BaseAST)node).xmlSerializeNode(out);
|
||||
}
|
||||
else {
|
||||
((BaseAST)node).xmlSerializeRootOpen(out);
|
||||
|
||||
// print children
|
||||
((BaseAST)node.getFirstChild()).xmlSerialize(out);
|
||||
|
||||
// print end tag
|
||||
((BaseAST)node).xmlSerializeRootClose(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1899
app/preproc/JavaLexer.java
Normal file
1899
app/preproc/JavaLexer.java
Normal file
File diff suppressed because it is too large
Load Diff
5050
app/preproc/JavaRecognizer.java
Normal file
5050
app/preproc/JavaRecognizer.java
Normal file
File diff suppressed because it is too large
Load Diff
157
app/preproc/JavaTokenTypes.java
Normal file
157
app/preproc/JavaTokenTypes.java
Normal file
@ -0,0 +1,157 @@
|
||||
// $ANTLR 2.7.2: "java.g" -> "JavaLexer.java"$
|
||||
|
||||
package antlr.java;
|
||||
|
||||
public interface JavaTokenTypes {
|
||||
int EOF = 1;
|
||||
int NULL_TREE_LOOKAHEAD = 3;
|
||||
int BLOCK = 4;
|
||||
int MODIFIERS = 5;
|
||||
int OBJBLOCK = 6;
|
||||
int SLIST = 7;
|
||||
int CTOR_DEF = 8;
|
||||
int METHOD_DEF = 9;
|
||||
int VARIABLE_DEF = 10;
|
||||
int INSTANCE_INIT = 11;
|
||||
int STATIC_INIT = 12;
|
||||
int TYPE = 13;
|
||||
int CLASS_DEF = 14;
|
||||
int INTERFACE_DEF = 15;
|
||||
int PACKAGE_DEF = 16;
|
||||
int ARRAY_DECLARATOR = 17;
|
||||
int EXTENDS_CLAUSE = 18;
|
||||
int IMPLEMENTS_CLAUSE = 19;
|
||||
int PARAMETERS = 20;
|
||||
int PARAMETER_DEF = 21;
|
||||
int LABELED_STAT = 22;
|
||||
int TYPECAST = 23;
|
||||
int INDEX_OP = 24;
|
||||
int POST_INC = 25;
|
||||
int POST_DEC = 26;
|
||||
int METHOD_CALL = 27;
|
||||
int EXPR = 28;
|
||||
int ARRAY_INIT = 29;
|
||||
int IMPORT = 30;
|
||||
int UNARY_MINUS = 31;
|
||||
int UNARY_PLUS = 32;
|
||||
int CASE_GROUP = 33;
|
||||
int ELIST = 34;
|
||||
int FOR_INIT = 35;
|
||||
int FOR_CONDITION = 36;
|
||||
int FOR_ITERATOR = 37;
|
||||
int EMPTY_STAT = 38;
|
||||
int FINAL = 39;
|
||||
int ABSTRACT = 40;
|
||||
int STRICTFP = 41;
|
||||
int SUPER_CTOR_CALL = 42;
|
||||
int CTOR_CALL = 43;
|
||||
int LITERAL_package = 44;
|
||||
int SEMI = 45;
|
||||
int LITERAL_import = 46;
|
||||
int LBRACK = 47;
|
||||
int RBRACK = 48;
|
||||
int LITERAL_void = 49;
|
||||
int LITERAL_boolean = 50;
|
||||
int LITERAL_byte = 51;
|
||||
int LITERAL_char = 52;
|
||||
int LITERAL_short = 53;
|
||||
int LITERAL_int = 54;
|
||||
int LITERAL_float = 55;
|
||||
int LITERAL_long = 56;
|
||||
int LITERAL_double = 57;
|
||||
int IDENT = 58;
|
||||
int DOT = 59;
|
||||
int STAR = 60;
|
||||
int LITERAL_private = 61;
|
||||
int LITERAL_public = 62;
|
||||
int LITERAL_protected = 63;
|
||||
int LITERAL_static = 64;
|
||||
int LITERAL_transient = 65;
|
||||
int LITERAL_native = 66;
|
||||
int LITERAL_threadsafe = 67;
|
||||
int LITERAL_synchronized = 68;
|
||||
int LITERAL_volatile = 69;
|
||||
int LITERAL_class = 70;
|
||||
int LITERAL_extends = 71;
|
||||
int LITERAL_interface = 72;
|
||||
int LCURLY = 73;
|
||||
int RCURLY = 74;
|
||||
int COMMA = 75;
|
||||
int LITERAL_implements = 76;
|
||||
int LPAREN = 77;
|
||||
int RPAREN = 78;
|
||||
int LITERAL_this = 79;
|
||||
int LITERAL_super = 80;
|
||||
int ASSIGN = 81;
|
||||
int LITERAL_throws = 82;
|
||||
int COLON = 83;
|
||||
int LITERAL_if = 84;
|
||||
int LITERAL_else = 85;
|
||||
int LITERAL_for = 86;
|
||||
int LITERAL_while = 87;
|
||||
int LITERAL_do = 88;
|
||||
int LITERAL_break = 89;
|
||||
int LITERAL_continue = 90;
|
||||
int LITERAL_return = 91;
|
||||
int LITERAL_switch = 92;
|
||||
int LITERAL_throw = 93;
|
||||
int LITERAL_assert = 94;
|
||||
int LITERAL_case = 95;
|
||||
int LITERAL_default = 96;
|
||||
int LITERAL_try = 97;
|
||||
int LITERAL_finally = 98;
|
||||
int LITERAL_catch = 99;
|
||||
int PLUS_ASSIGN = 100;
|
||||
int MINUS_ASSIGN = 101;
|
||||
int STAR_ASSIGN = 102;
|
||||
int DIV_ASSIGN = 103;
|
||||
int MOD_ASSIGN = 104;
|
||||
int SR_ASSIGN = 105;
|
||||
int BSR_ASSIGN = 106;
|
||||
int SL_ASSIGN = 107;
|
||||
int BAND_ASSIGN = 108;
|
||||
int BXOR_ASSIGN = 109;
|
||||
int BOR_ASSIGN = 110;
|
||||
int QUESTION = 111;
|
||||
int LOR = 112;
|
||||
int LAND = 113;
|
||||
int BOR = 114;
|
||||
int BXOR = 115;
|
||||
int BAND = 116;
|
||||
int NOT_EQUAL = 117;
|
||||
int EQUAL = 118;
|
||||
int LT = 119;
|
||||
int GT = 120;
|
||||
int LE = 121;
|
||||
int GE = 122;
|
||||
int LITERAL_instanceof = 123;
|
||||
int SL = 124;
|
||||
int SR = 125;
|
||||
int BSR = 126;
|
||||
int PLUS = 127;
|
||||
int MINUS = 128;
|
||||
int DIV = 129;
|
||||
int MOD = 130;
|
||||
int INC = 131;
|
||||
int DEC = 132;
|
||||
int BNOT = 133;
|
||||
int LNOT = 134;
|
||||
int LITERAL_true = 135;
|
||||
int LITERAL_false = 136;
|
||||
int LITERAL_null = 137;
|
||||
int LITERAL_new = 138;
|
||||
int NUM_INT = 139;
|
||||
int CHAR_LITERAL = 140;
|
||||
int STRING_LITERAL = 141;
|
||||
int NUM_FLOAT = 142;
|
||||
int NUM_LONG = 143;
|
||||
int NUM_DOUBLE = 144;
|
||||
int WS = 145;
|
||||
int SL_COMMENT = 146;
|
||||
int ML_COMMENT = 147;
|
||||
int ESC = 148;
|
||||
int HEX_DIGIT = 149;
|
||||
int VOCAB = 150;
|
||||
int EXPONENT = 151;
|
||||
int FLOAT_SUFFIX = 152;
|
||||
}
|
151
app/preproc/JavaTokenTypes.txt
Normal file
151
app/preproc/JavaTokenTypes.txt
Normal file
@ -0,0 +1,151 @@
|
||||
// $ANTLR 2.7.2: java.g -> JavaTokenTypes.txt$
|
||||
Java // output token vocab name
|
||||
BLOCK=4
|
||||
MODIFIERS=5
|
||||
OBJBLOCK=6
|
||||
SLIST=7
|
||||
CTOR_DEF=8
|
||||
METHOD_DEF=9
|
||||
VARIABLE_DEF=10
|
||||
INSTANCE_INIT=11
|
||||
STATIC_INIT=12
|
||||
TYPE=13
|
||||
CLASS_DEF=14
|
||||
INTERFACE_DEF=15
|
||||
PACKAGE_DEF=16
|
||||
ARRAY_DECLARATOR=17
|
||||
EXTENDS_CLAUSE=18
|
||||
IMPLEMENTS_CLAUSE=19
|
||||
PARAMETERS=20
|
||||
PARAMETER_DEF=21
|
||||
LABELED_STAT=22
|
||||
TYPECAST=23
|
||||
INDEX_OP=24
|
||||
POST_INC=25
|
||||
POST_DEC=26
|
||||
METHOD_CALL=27
|
||||
EXPR=28
|
||||
ARRAY_INIT=29
|
||||
IMPORT=30
|
||||
UNARY_MINUS=31
|
||||
UNARY_PLUS=32
|
||||
CASE_GROUP=33
|
||||
ELIST=34
|
||||
FOR_INIT=35
|
||||
FOR_CONDITION=36
|
||||
FOR_ITERATOR=37
|
||||
EMPTY_STAT=38
|
||||
FINAL="final"=39
|
||||
ABSTRACT="abstract"=40
|
||||
STRICTFP="strictfp"=41
|
||||
SUPER_CTOR_CALL=42
|
||||
CTOR_CALL=43
|
||||
LITERAL_package="package"=44
|
||||
SEMI=45
|
||||
LITERAL_import="import"=46
|
||||
LBRACK=47
|
||||
RBRACK=48
|
||||
LITERAL_void="void"=49
|
||||
LITERAL_boolean="boolean"=50
|
||||
LITERAL_byte="byte"=51
|
||||
LITERAL_char="char"=52
|
||||
LITERAL_short="short"=53
|
||||
LITERAL_int="int"=54
|
||||
LITERAL_float="float"=55
|
||||
LITERAL_long="long"=56
|
||||
LITERAL_double="double"=57
|
||||
IDENT=58
|
||||
DOT=59
|
||||
STAR=60
|
||||
LITERAL_private="private"=61
|
||||
LITERAL_public="public"=62
|
||||
LITERAL_protected="protected"=63
|
||||
LITERAL_static="static"=64
|
||||
LITERAL_transient="transient"=65
|
||||
LITERAL_native="native"=66
|
||||
LITERAL_threadsafe="threadsafe"=67
|
||||
LITERAL_synchronized="synchronized"=68
|
||||
LITERAL_volatile="volatile"=69
|
||||
LITERAL_class="class"=70
|
||||
LITERAL_extends="extends"=71
|
||||
LITERAL_interface="interface"=72
|
||||
LCURLY=73
|
||||
RCURLY=74
|
||||
COMMA=75
|
||||
LITERAL_implements="implements"=76
|
||||
LPAREN=77
|
||||
RPAREN=78
|
||||
LITERAL_this="this"=79
|
||||
LITERAL_super="super"=80
|
||||
ASSIGN=81
|
||||
LITERAL_throws="throws"=82
|
||||
COLON=83
|
||||
LITERAL_if="if"=84
|
||||
LITERAL_else="else"=85
|
||||
LITERAL_for="for"=86
|
||||
LITERAL_while="while"=87
|
||||
LITERAL_do="do"=88
|
||||
LITERAL_break="break"=89
|
||||
LITERAL_continue="continue"=90
|
||||
LITERAL_return="return"=91
|
||||
LITERAL_switch="switch"=92
|
||||
LITERAL_throw="throw"=93
|
||||
LITERAL_assert="assert"=94
|
||||
LITERAL_case="case"=95
|
||||
LITERAL_default="default"=96
|
||||
LITERAL_try="try"=97
|
||||
LITERAL_finally="finally"=98
|
||||
LITERAL_catch="catch"=99
|
||||
PLUS_ASSIGN=100
|
||||
MINUS_ASSIGN=101
|
||||
STAR_ASSIGN=102
|
||||
DIV_ASSIGN=103
|
||||
MOD_ASSIGN=104
|
||||
SR_ASSIGN=105
|
||||
BSR_ASSIGN=106
|
||||
SL_ASSIGN=107
|
||||
BAND_ASSIGN=108
|
||||
BXOR_ASSIGN=109
|
||||
BOR_ASSIGN=110
|
||||
QUESTION=111
|
||||
LOR=112
|
||||
LAND=113
|
||||
BOR=114
|
||||
BXOR=115
|
||||
BAND=116
|
||||
NOT_EQUAL=117
|
||||
EQUAL=118
|
||||
LT=119
|
||||
GT=120
|
||||
LE=121
|
||||
GE=122
|
||||
LITERAL_instanceof="instanceof"=123
|
||||
SL=124
|
||||
SR=125
|
||||
BSR=126
|
||||
PLUS=127
|
||||
MINUS=128
|
||||
DIV=129
|
||||
MOD=130
|
||||
INC=131
|
||||
DEC=132
|
||||
BNOT=133
|
||||
LNOT=134
|
||||
LITERAL_true="true"=135
|
||||
LITERAL_false="false"=136
|
||||
LITERAL_null="null"=137
|
||||
LITERAL_new="new"=138
|
||||
NUM_INT=139
|
||||
CHAR_LITERAL=140
|
||||
STRING_LITERAL=141
|
||||
NUM_FLOAT=142
|
||||
NUM_LONG=143
|
||||
NUM_DOUBLE=144
|
||||
WS=145
|
||||
SL_COMMENT=146
|
||||
ML_COMMENT=147
|
||||
ESC=148
|
||||
HEX_DIGIT=149
|
||||
VOCAB=150
|
||||
EXPONENT=151
|
||||
FLOAT_SUFFIX=152
|
922
app/preproc/PdeEmitter.java
Normal file
922
app/preproc/PdeEmitter.java
Normal file
@ -0,0 +1,922 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
|
||||
/* Based on original code copyright (c) 2003 Andy Tripp <atripp@comcast.net>.
|
||||
* shipped under GPL with permission.
|
||||
*/
|
||||
|
||||
import antlr.*;
|
||||
import antlr.collections.*;
|
||||
import antlr.collections.impl.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* PDEEmitter: A class that can take an ANTLR Java AST and produce
|
||||
* reasonably formatted Java code from it. To use it, create a
|
||||
* PDEEmitter object, call setOut() if you want to print to something
|
||||
* other than System.out, and then call print(), passing the
|
||||
* AST. Typically, the AST node that you pass would be the root of a
|
||||
* tree - the ROOT_ID node that represents a Java file.
|
||||
*/
|
||||
|
||||
public class PdeEmitter implements PdeTokenTypes
|
||||
{
|
||||
private PrintStream out = System.out;
|
||||
private PrintStream debug = System.err;
|
||||
private static int ALL = -1;
|
||||
private java.util.Stack stack = new java.util.Stack();
|
||||
private static String[] tokenNames;
|
||||
private final static int ROOT_ID = 0;
|
||||
static {
|
||||
setupTokenNames();
|
||||
}
|
||||
|
||||
/*
|
||||
private static Hashtable publicMethods;
|
||||
private static final String publicMethodList[] = {
|
||||
"setup", "draw", //"loop",
|
||||
"mousePressed", "mouseReleased", "mouseClicked",
|
||||
"mouseEntered", "mouseExited",
|
||||
"mouseMoved", "mouseDragged",
|
||||
"keyPressed", "keyReleased", "keyTyped"
|
||||
};
|
||||
|
||||
static {
|
||||
publicMethods = new Hashtable();
|
||||
for (int i = 0; i < publicMethodList.length; i++) {
|
||||
publicMethods.put(publicMethodList[i], new Object());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Map each AST token type to a String
|
||||
private static void setupTokenNames() {
|
||||
tokenNames = new String[200];
|
||||
for (int i=0; i<tokenNames.length; i++) {
|
||||
tokenNames[i] = "ERROR:" + i;
|
||||
}
|
||||
|
||||
tokenNames[POST_INC]="++";
|
||||
tokenNames[POST_DEC]="--";
|
||||
tokenNames[UNARY_MINUS]="-";
|
||||
tokenNames[UNARY_PLUS]="+";
|
||||
tokenNames[STAR]="*";
|
||||
tokenNames[ASSIGN]="=";
|
||||
tokenNames[PLUS_ASSIGN]="+=";
|
||||
tokenNames[MINUS_ASSIGN]="-=";
|
||||
tokenNames[STAR_ASSIGN]="*=";
|
||||
tokenNames[DIV_ASSIGN]="/=";
|
||||
tokenNames[MOD_ASSIGN]="%=";
|
||||
tokenNames[SR_ASSIGN]=">>=";
|
||||
tokenNames[BSR_ASSIGN]=">>>=";
|
||||
tokenNames[SL_ASSIGN]="<<=";
|
||||
tokenNames[BAND_ASSIGN]="&=";
|
||||
tokenNames[BXOR_ASSIGN]="^=";
|
||||
tokenNames[BOR_ASSIGN]="|=";
|
||||
tokenNames[QUESTION]="?";
|
||||
tokenNames[LOR]="||";
|
||||
tokenNames[LAND]="&&";
|
||||
tokenNames[BOR]="|";
|
||||
tokenNames[BXOR]="^";
|
||||
tokenNames[BAND]="&";
|
||||
tokenNames[NOT_EQUAL]="!=";
|
||||
tokenNames[EQUAL]="==";
|
||||
tokenNames[LT]="<";
|
||||
tokenNames[GT]=">";
|
||||
tokenNames[LE]="<=";
|
||||
tokenNames[GE]=">=";
|
||||
tokenNames[SL]="<<";
|
||||
tokenNames[SR]=">>";
|
||||
tokenNames[BSR]=">>>";
|
||||
tokenNames[PLUS]="+";
|
||||
tokenNames[MINUS]="-";
|
||||
tokenNames[DIV]="/";
|
||||
tokenNames[MOD]="%";
|
||||
tokenNames[INC]="++";
|
||||
tokenNames[DEC]="--";
|
||||
tokenNames[BNOT]="~";
|
||||
tokenNames[LNOT]="!";
|
||||
tokenNames[FINAL]="final";
|
||||
tokenNames[ABSTRACT]="abstract";
|
||||
tokenNames[LITERAL_package]="package";
|
||||
tokenNames[LITERAL_import]="import";
|
||||
tokenNames[LITERAL_void]="void";
|
||||
tokenNames[LITERAL_boolean]="boolean";
|
||||
tokenNames[LITERAL_byte]="byte";
|
||||
tokenNames[LITERAL_char]="char";
|
||||
tokenNames[LITERAL_short]="short";
|
||||
tokenNames[LITERAL_int]="int";
|
||||
tokenNames[LITERAL_float]="float";
|
||||
tokenNames[LITERAL_long]="long";
|
||||
tokenNames[LITERAL_double]="double";
|
||||
tokenNames[LITERAL_private]="private";
|
||||
tokenNames[LITERAL_public]="public";
|
||||
tokenNames[LITERAL_protected]="protected";
|
||||
tokenNames[LITERAL_static]="static";
|
||||
tokenNames[LITERAL_transient]="transient";
|
||||
tokenNames[LITERAL_native]="native";
|
||||
tokenNames[LITERAL_threadsafe]="threadsafe";
|
||||
tokenNames[LITERAL_synchronized]="synchronized";
|
||||
tokenNames[LITERAL_volatile]="volatile";
|
||||
tokenNames[LITERAL_class]="class";
|
||||
tokenNames[LITERAL_extends]="extends";
|
||||
tokenNames[LITERAL_interface]="interface";
|
||||
tokenNames[LITERAL_implements]="implements";
|
||||
tokenNames[LITERAL_throws]="throws";
|
||||
tokenNames[LITERAL_if]="if";
|
||||
tokenNames[LITERAL_else]="else";
|
||||
tokenNames[LITERAL_for]="for";
|
||||
tokenNames[LITERAL_while]="while";
|
||||
tokenNames[LITERAL_do]="do";
|
||||
tokenNames[LITERAL_break]="break";
|
||||
tokenNames[LITERAL_continue]="continue";
|
||||
tokenNames[LITERAL_return]="return";
|
||||
tokenNames[LITERAL_switch]="switch";
|
||||
tokenNames[LITERAL_throw]="throw";
|
||||
tokenNames[LITERAL_case]="case";
|
||||
tokenNames[LITERAL_default]="default";
|
||||
tokenNames[LITERAL_try]="try";
|
||||
tokenNames[LITERAL_finally]="finally";
|
||||
tokenNames[LITERAL_catch]="catch";
|
||||
tokenNames[LITERAL_instanceof]="instanceof";
|
||||
tokenNames[LITERAL_this]="this";
|
||||
tokenNames[LITERAL_super]="super";
|
||||
tokenNames[LITERAL_true]="true";
|
||||
tokenNames[LITERAL_false]="false";
|
||||
tokenNames[LITERAL_null]="null";
|
||||
tokenNames[LITERAL_new]="new";
|
||||
tokenNames[LITERAL_color]="int"; // PDE specific alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a PrintStream to print to. System.out is the default.
|
||||
* @param out the PrintStream to print to
|
||||
*/
|
||||
public void setOut(PrintStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
private String name(AST ast) {
|
||||
return tokenNames[ast.getType()];
|
||||
}
|
||||
private String name(int type) {
|
||||
return tokenNames[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a child of the given AST that has the given type
|
||||
* @returns a child AST of the given type. If it can't find a child of the
|
||||
* given type, return null.
|
||||
*/
|
||||
private AST getChild(AST ast, int childType) {
|
||||
AST child = ast.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child.getType() == childType) {
|
||||
// debug.println("getChild: found:" + name(ast));
|
||||
return child;
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to after the AST node passed in.
|
||||
* Most hidden tokens are dumped from this function.
|
||||
*/
|
||||
private void dumpHiddenAfter(AST ast) {
|
||||
dumpHiddenTokens(((antlr.CommonASTWithHiddenTokens)ast).getHiddenAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to before the AST node passed in.
|
||||
* The only time hidden tokens need to be dumped with this function is when
|
||||
* dealing parts of the tree where automatic tree construction was
|
||||
* turned off with the ! operator in the grammar file and the nodes were
|
||||
* manually constructed in such a way that the usual tokens don't have the
|
||||
* necessary hiddenAfter links.
|
||||
*/
|
||||
private void dumpHiddenBefore(AST ast) {
|
||||
|
||||
antlr.CommonHiddenStreamToken
|
||||
child = null,
|
||||
parent = ((antlr.CommonASTWithHiddenTokens)ast).getHiddenBefore();
|
||||
|
||||
// if there aren't any hidden tokens here, quietly return
|
||||
//
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// traverse back to the head of the list of tokens before this node
|
||||
do {
|
||||
child = parent;
|
||||
parent = child.getHiddenBefore();
|
||||
} while (parent != null);
|
||||
|
||||
// dump that list
|
||||
dumpHiddenTokens(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to from the token passed in.
|
||||
*/
|
||||
private void dumpHiddenTokens(antlr.CommonHiddenStreamToken t) {
|
||||
for ( ; t != null ; t=PdePreprocessor.filter.getHiddenAfter(t) ) {
|
||||
out.print(t.getText());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the children of the given AST
|
||||
* @param ast The AST to print
|
||||
* @returns true iff anything was printed
|
||||
*/
|
||||
private boolean printChildren(AST ast) throws RunnerException {
|
||||
boolean ret = false;
|
||||
AST child = ast.getFirstChild();
|
||||
while (child != null) {
|
||||
ret = true;
|
||||
print(child);
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether an AST has any children or not.
|
||||
* @return true iff the AST has at least one child
|
||||
*/
|
||||
private boolean hasChildren(AST ast) {
|
||||
return (ast.getFirstChild() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the best node in the subtree for printing. This really means
|
||||
* the next node which could potentially have hiddenBefore data. It's
|
||||
* usually the first printable leaf, but not always.
|
||||
*
|
||||
* @param includeThisNode Should this node be included in the search?
|
||||
* If false, only descendants are searched.
|
||||
*
|
||||
* @return the first printable leaf node in an AST
|
||||
*/
|
||||
private AST getBestPrintableNode(AST ast, boolean includeThisNode) {
|
||||
AST child;
|
||||
|
||||
if (includeThisNode) {
|
||||
child = ast;
|
||||
} else {
|
||||
child = ast.getFirstChild();
|
||||
}
|
||||
|
||||
if (child != null) {
|
||||
|
||||
switch (child.getType()) {
|
||||
|
||||
// the following node types are printing nodes that print before
|
||||
// any children, but then also recurse over children. So they
|
||||
// may have hiddenBefore chains that need to be printed first. Many
|
||||
// statements and all unary expression types qualify. Return these
|
||||
// nodes directly
|
||||
case CLASS_DEF:
|
||||
case LITERAL_if:
|
||||
case LITERAL_for:
|
||||
case LITERAL_while:
|
||||
case LITERAL_do:
|
||||
case LITERAL_break:
|
||||
case LITERAL_continue:
|
||||
case LITERAL_return:
|
||||
case LITERAL_switch:
|
||||
case LITERAL_try:
|
||||
case LITERAL_throw:
|
||||
case LITERAL_synchronized:
|
||||
case LITERAL_assert:
|
||||
case BNOT:
|
||||
case LNOT:
|
||||
case INC:
|
||||
case DEC:
|
||||
case UNARY_MINUS:
|
||||
case UNARY_PLUS:
|
||||
return child;
|
||||
|
||||
// Some non-terminal node types (at the moment, I only know of
|
||||
// MODIFIERS, but there may be other such types), can be
|
||||
// leaves in the tree but not have any children. If this is
|
||||
// such a node, move on to the next sibling.
|
||||
case MODIFIERS:
|
||||
if (child.getFirstChild() == null ) {
|
||||
return getBestPrintableNode(child.getNextSibling(), false);
|
||||
}
|
||||
// new jikes doesn't like fallthrough, so just duplicated here:
|
||||
return getBestPrintableNode(child, false);
|
||||
|
||||
default:
|
||||
return getBestPrintableNode(child, false);
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a binary operator
|
||||
*/
|
||||
private void printBinaryOperator(AST ast) throws RunnerException {
|
||||
print(ast.getFirstChild());
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild().getNextSibling());
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the given AST. Call this function to print your PDE code.
|
||||
*
|
||||
* It works by making recursive calls to print children.
|
||||
* So the code below is one big "switch" statement on the passed AST type.
|
||||
*/
|
||||
public void print (AST ast) throws RunnerException {
|
||||
if (ast == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AST parent = null;
|
||||
if (!stack.isEmpty()) {
|
||||
parent = (AST) stack.peek();
|
||||
}
|
||||
stack.push(ast);
|
||||
|
||||
AST child1 = ast.getFirstChild();
|
||||
AST child2 = null;
|
||||
AST child3 = null;
|
||||
if (child1 != null) {
|
||||
child2 = child1.getNextSibling();
|
||||
if (child2 != null) {
|
||||
child3 = child2.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
switch(ast.getType()) {
|
||||
// The top of the tree looks like this:
|
||||
// ROOT_ID "Whatever.java"
|
||||
// package
|
||||
// imports
|
||||
// class definition
|
||||
case ROOT_ID:
|
||||
dumpHiddenTokens(PdePreprocessor.filter.getInitialHiddenToken());
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
// supporting a "package" statement in a PDE program has
|
||||
// a bunch of issues with it that need to dealt in the compilation
|
||||
// code too, so this isn't actually tested.
|
||||
case PACKAGE_DEF:
|
||||
out.print("package");
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild());
|
||||
break;
|
||||
|
||||
// IMPORT has exactly one child
|
||||
case IMPORT:
|
||||
out.print("import");
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild());
|
||||
break;
|
||||
|
||||
case CLASS_DEF:
|
||||
case INTERFACE_DEF:
|
||||
print(getChild(ast, MODIFIERS));
|
||||
if (ast.getType() == CLASS_DEF) {
|
||||
out.print("class");
|
||||
} else {
|
||||
out.print("interface");
|
||||
}
|
||||
dumpHiddenBefore(getChild(ast, IDENT));
|
||||
print(getChild(ast, IDENT));
|
||||
print(getChild(ast, EXTENDS_CLAUSE));
|
||||
print(getChild(ast, IMPLEMENTS_CLAUSE));
|
||||
print(getChild(ast, OBJBLOCK));
|
||||
break;
|
||||
|
||||
case EXTENDS_CLAUSE:
|
||||
if (hasChildren(ast)) {
|
||||
out.print("extends");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
printChildren(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
case IMPLEMENTS_CLAUSE:
|
||||
if (hasChildren(ast)) {
|
||||
out.print("implements");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
printChildren(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
// DOT always has exactly two children.
|
||||
case DOT:
|
||||
print(child1);
|
||||
out.print(".");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
break;
|
||||
|
||||
case MODIFIERS:
|
||||
case OBJBLOCK:
|
||||
case CTOR_DEF:
|
||||
//case METHOD_DEF:
|
||||
case PARAMETERS:
|
||||
case PARAMETER_DEF:
|
||||
case VARIABLE_DEF:
|
||||
case TYPE:
|
||||
case SLIST:
|
||||
case ELIST:
|
||||
case ARRAY_DECLARATOR:
|
||||
case TYPECAST:
|
||||
case EXPR:
|
||||
case ARRAY_INIT:
|
||||
case FOR_INIT:
|
||||
case FOR_CONDITION:
|
||||
case FOR_ITERATOR:
|
||||
case METHOD_CALL:
|
||||
case INSTANCE_INIT:
|
||||
case INDEX_OP:
|
||||
case SUPER_CTOR_CALL:
|
||||
case CTOR_CALL:
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case METHOD_DEF:
|
||||
// kids seem to be: MODIFIERS TYPE setup PARAMETERS
|
||||
//AST parent = (AST) stack.peek();
|
||||
AST modifiersChild = ast.getFirstChild();
|
||||
AST typeChild = modifiersChild.getNextSibling();
|
||||
AST methodNameChild = typeChild.getNextSibling();
|
||||
AST parametersChild = methodNameChild.getNextSibling();
|
||||
|
||||
// to output, use print(child) on each of the four
|
||||
|
||||
/*
|
||||
// 1. figure out if this is setup, draw, or loop
|
||||
String methodName = methodNameChild.getText();
|
||||
if (publicMethods.get(methodName) != null) {
|
||||
// make sure this feller is public
|
||||
boolean foundPublic = false;
|
||||
AST child = modifiersChild.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child.getText().equals("public")) {
|
||||
foundPublic = true;
|
||||
child = null;
|
||||
} else {
|
||||
//out.print("." + child.getText() + ".");
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
if (!foundPublic) {
|
||||
out.print("public ");
|
||||
}
|
||||
*/
|
||||
|
||||
// if this method doesn't have a specifier, make it public
|
||||
// (useful for setup/keyPressed/etc)
|
||||
boolean foundSpecifier = false;
|
||||
AST child = modifiersChild.getFirstChild();
|
||||
while (child != null) {
|
||||
String childText = child.getText();
|
||||
if (childText.equals("public") ||
|
||||
childText.equals("protected") ||
|
||||
childText.equals("private")) {
|
||||
foundSpecifier = true;
|
||||
child = null;
|
||||
} else {
|
||||
//out.print("." + child.getText() + ".");
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
if (!foundSpecifier) {
|
||||
out.print("public ");
|
||||
}
|
||||
printChildren(ast); // everything is fine
|
||||
break;
|
||||
|
||||
// if we have two children, it's of the form "a=0"
|
||||
// if just one child, it's of the form "=0" (where the
|
||||
// lhs is above this AST).
|
||||
case ASSIGN:
|
||||
if (child2 != null) {
|
||||
print(child1);
|
||||
out.print("=");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
}
|
||||
else {
|
||||
out.print("=");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
}
|
||||
break;
|
||||
|
||||
// binary operators:
|
||||
case PLUS:
|
||||
case MINUS:
|
||||
case DIV:
|
||||
case MOD:
|
||||
case NOT_EQUAL:
|
||||
case EQUAL:
|
||||
case LT:
|
||||
case GT:
|
||||
case LE:
|
||||
case GE:
|
||||
case LOR:
|
||||
case LAND:
|
||||
case BOR:
|
||||
case BXOR:
|
||||
case BAND:
|
||||
case SL:
|
||||
case SR:
|
||||
case BSR:
|
||||
case LITERAL_instanceof:
|
||||
case PLUS_ASSIGN:
|
||||
case MINUS_ASSIGN:
|
||||
case STAR_ASSIGN:
|
||||
case DIV_ASSIGN:
|
||||
case MOD_ASSIGN:
|
||||
case SR_ASSIGN:
|
||||
case BSR_ASSIGN:
|
||||
case SL_ASSIGN:
|
||||
case BAND_ASSIGN:
|
||||
case BXOR_ASSIGN:
|
||||
case BOR_ASSIGN:
|
||||
printBinaryOperator(ast);
|
||||
break;
|
||||
|
||||
|
||||
case LITERAL_for:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case POST_INC:
|
||||
case POST_DEC:
|
||||
print(child1);
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// unary operators:
|
||||
case BNOT:
|
||||
case LNOT:
|
||||
case INC:
|
||||
case DEC:
|
||||
case UNARY_MINUS:
|
||||
case UNARY_PLUS:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case LITERAL_new:
|
||||
out.print("new");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
print(child2);
|
||||
// "new String[] {...}": the stuff in {} is child3
|
||||
if (child3 != null) {
|
||||
print(child3);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_return:
|
||||
out.print("return");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case STATIC_INIT:
|
||||
out.print("static");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case LITERAL_switch:
|
||||
out.print("switch");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case CASE_GROUP:
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_case:
|
||||
out.print("case");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_default:
|
||||
out.print("default");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case NUM_INT:
|
||||
case CHAR_LITERAL:
|
||||
case STRING_LITERAL:
|
||||
case NUM_FLOAT:
|
||||
out.print(ast.getText());
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_private:
|
||||
case LITERAL_public:
|
||||
case LITERAL_protected:
|
||||
case LITERAL_static:
|
||||
case LITERAL_transient:
|
||||
case LITERAL_native:
|
||||
case LITERAL_threadsafe:
|
||||
case LITERAL_synchronized:
|
||||
case LITERAL_volatile:
|
||||
case FINAL:
|
||||
case ABSTRACT:
|
||||
case LITERAL_package:
|
||||
case LITERAL_void:
|
||||
case LITERAL_boolean:
|
||||
case LITERAL_byte:
|
||||
case LITERAL_char:
|
||||
case LITERAL_short:
|
||||
case LITERAL_int:
|
||||
case LITERAL_float:
|
||||
case LITERAL_long:
|
||||
case LITERAL_double:
|
||||
case LITERAL_true:
|
||||
case LITERAL_false:
|
||||
case LITERAL_null:
|
||||
case SEMI:
|
||||
case LITERAL_this:
|
||||
case LITERAL_super:
|
||||
case LITERAL_continue:
|
||||
case LITERAL_break:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case EMPTY_STAT:
|
||||
case EMPTY_FIELD:
|
||||
break;
|
||||
|
||||
// yuck: Distinguish between "import x.y.*" and "x = 1 * 3"
|
||||
case STAR:
|
||||
if (hasChildren(ast)) { // the binary mult. operator
|
||||
printBinaryOperator(ast);
|
||||
}
|
||||
else { // the special "*" in import:
|
||||
out.print("*");
|
||||
dumpHiddenAfter(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_throws:
|
||||
out.print("throws");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_if:
|
||||
out.print("if");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1); // the "if" condition: an EXPR
|
||||
print(child2); // the "then" clause is an SLIST
|
||||
if (child3 != null) {
|
||||
out.print("else");
|
||||
dumpHiddenBefore(getBestPrintableNode(child3, true));
|
||||
print(child3); // optional "else" clause: an SLIST
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_while:
|
||||
out.print("while");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_do:
|
||||
out.print("do");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1); // an SLIST
|
||||
out.print("while");
|
||||
dumpHiddenBefore(getBestPrintableNode(child2, false));
|
||||
print(child2); // an EXPR
|
||||
break;
|
||||
|
||||
case LITERAL_try:
|
||||
out.print("try");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_catch:
|
||||
out.print("catch");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
// the first child is the "try" and the second is the SLIST
|
||||
case LITERAL_finally:
|
||||
out.print("finally");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_throw:
|
||||
out.print("throw");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
// the dreaded trinary operator
|
||||
case QUESTION:
|
||||
print(child1);
|
||||
out.print("?");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
print(child3);
|
||||
break;
|
||||
|
||||
// pde specific or modified tokens start here
|
||||
|
||||
// Image -> BImage, Font -> BFont as appropriate
|
||||
case IDENT:
|
||||
/*
|
||||
if (ast.getText().equals("Image") &&
|
||||
Preferences.getBoolean("preproc.substitute_image")) { //, true)) {
|
||||
out.print("BImage");
|
||||
} else if (ast.getText().equals("Font") &&
|
||||
Preferences.getBoolean("preproc.substitute_font")) { //, true)) {
|
||||
out.print("BFont");
|
||||
} else {
|
||||
*/
|
||||
out.print(ast.getText());
|
||||
//}
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// the color datatype is just an alias for int
|
||||
case LITERAL_color:
|
||||
out.print("int");
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case WEBCOLOR_LITERAL:
|
||||
if (ast.getText().length() != 6) {
|
||||
System.err.println("Internal error: incorrect length of webcolor " +
|
||||
"literal should have been detected sooner.");
|
||||
break;
|
||||
}
|
||||
out.print("0xff" + ast.getText());
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// allow for stuff like int(43.2).
|
||||
case CONSTRUCTOR_CAST:
|
||||
|
||||
AST nonTerminalTypeNode = child1;
|
||||
AST terminalTypeNode = child1.getFirstChild();
|
||||
AST exprToCast = child2;
|
||||
|
||||
/*
|
||||
// if this is a string type, add .valueOf()
|
||||
if (nonTerminalTypeNode.getType() == PdeRecognizer.TYPE &&
|
||||
terminalTypeNode.getText().equals("String")) {
|
||||
|
||||
out.print(terminalTypeNode.getText() + ".valueOf");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
|
||||
// if the expresion to be cast is a string literal, try and parse it.
|
||||
//
|
||||
// ideally, we'd be able to do this for all expressions with a
|
||||
// string type, not just string literals. however, the parser
|
||||
// doesn't currently track expression type, and for full
|
||||
// functionality, we'd need to do semantic analysis to handle
|
||||
// imports so that we could know the return types of method calls.
|
||||
//
|
||||
} else if (exprToCast.getFirstChild().getType() == STRING_LITERAL ) {
|
||||
|
||||
switch (terminalTypeNode.getType()) {
|
||||
|
||||
case PdeRecognizer.LITERAL_byte:
|
||||
out.print("Byte.parseByte");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_double:
|
||||
out.print("(new Double");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
out.print(exprToCast.getFirstChild().getText() + ").doubleValue()");
|
||||
dumpHiddenAfter(exprToCast.getFirstChild());
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_float:
|
||||
out.print("(new Float");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
out.print(exprToCast.getFirstChild().getText() + ").floatValue()");
|
||||
dumpHiddenAfter(exprToCast.getFirstChild());
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_int:
|
||||
case PdeRecognizer.LITERAL_color:
|
||||
out.print("Integer.parseInt");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_long:
|
||||
out.print("Long.parseLong");
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_short:
|
||||
out.print("Short.parseShort");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RunnerException(Compiler.SUPER_BADNESS);
|
||||
}
|
||||
|
||||
// for builtin types, use regular casting syntax
|
||||
} else {
|
||||
*/
|
||||
|
||||
// result of below is (int)(4.0
|
||||
//out.print("(");
|
||||
//out.print(terminalTypeNode.getText() + ")"); // typename
|
||||
//dumpHiddenAfter(terminalTypeNode);
|
||||
//print(exprToCast);
|
||||
//}
|
||||
|
||||
//out.print("(");
|
||||
String pooType = terminalTypeNode.getText();
|
||||
out.print("PApplet.to" +
|
||||
Character.toUpperCase(pooType.charAt(0)) +
|
||||
pooType.substring(1));
|
||||
dumpHiddenAfter(terminalTypeNode); // the left paren
|
||||
print(exprToCast);
|
||||
//out.print("x)");
|
||||
|
||||
break;
|
||||
|
||||
|
||||
// making floating point literals default to floats, not doubles
|
||||
case NUM_DOUBLE:
|
||||
out.print(ast.getText());
|
||||
if (Preferences.getBoolean("preproc.substitute_floats")) { //, true) ) {
|
||||
out.print("f");
|
||||
}
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
debug.println("Invalid type:" + ast.getType());
|
||||
break;
|
||||
|
||||
|
||||
/* The following are tokens, but I don't think JavaRecognizer
|
||||
ever produces an AST with one of these types:
|
||||
case COMMA:
|
||||
case LITERAL_implements:
|
||||
case LITERAL_class:
|
||||
case LITERAL_extends:
|
||||
case EOF:
|
||||
case NULL_TREE_LOOKAHEAD:
|
||||
case BLOCK:
|
||||
case LABELED_STAT: // refuse to implement on moral grounds :)
|
||||
case LITERAL_import:
|
||||
case LBRACK:
|
||||
case RBRACK:
|
||||
case LCURLY:
|
||||
case RCURLY:
|
||||
case LPAREN:
|
||||
case RPAREN:
|
||||
case LITERAL_else: // else is a child of "if" AST
|
||||
case COLON: // part of the trinary operator
|
||||
case WS: // whitespace
|
||||
case ESC:
|
||||
case HEX_DIGIT:
|
||||
case VOCAB:
|
||||
|
||||
case EXPONENT: // exponents and float suffixes are left in the NUM_FLOAT
|
||||
case FLOAT_SUFFIX
|
||||
*/
|
||||
}
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
1935
app/preproc/PdeLexer.java
Normal file
1935
app/preproc/PdeLexer.java
Normal file
File diff suppressed because it is too large
Load Diff
163
app/preproc/PdePartialTokenTypes.java
Normal file
163
app/preproc/PdePartialTokenTypes.java
Normal file
@ -0,0 +1,163 @@
|
||||
// $ANTLR 2.7.2: "expandedpde.g" -> "PdeRecognizer.java"$
|
||||
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
public interface PdePartialTokenTypes {
|
||||
int EOF = 1;
|
||||
int NULL_TREE_LOOKAHEAD = 3;
|
||||
int BLOCK = 4;
|
||||
int MODIFIERS = 5;
|
||||
int OBJBLOCK = 6;
|
||||
int SLIST = 7;
|
||||
int CTOR_DEF = 8;
|
||||
int METHOD_DEF = 9;
|
||||
int VARIABLE_DEF = 10;
|
||||
int INSTANCE_INIT = 11;
|
||||
int STATIC_INIT = 12;
|
||||
int TYPE = 13;
|
||||
int CLASS_DEF = 14;
|
||||
int INTERFACE_DEF = 15;
|
||||
int PACKAGE_DEF = 16;
|
||||
int ARRAY_DECLARATOR = 17;
|
||||
int EXTENDS_CLAUSE = 18;
|
||||
int IMPLEMENTS_CLAUSE = 19;
|
||||
int PARAMETERS = 20;
|
||||
int PARAMETER_DEF = 21;
|
||||
int LABELED_STAT = 22;
|
||||
int TYPECAST = 23;
|
||||
int INDEX_OP = 24;
|
||||
int POST_INC = 25;
|
||||
int POST_DEC = 26;
|
||||
int METHOD_CALL = 27;
|
||||
int EXPR = 28;
|
||||
int ARRAY_INIT = 29;
|
||||
int IMPORT = 30;
|
||||
int UNARY_MINUS = 31;
|
||||
int UNARY_PLUS = 32;
|
||||
int CASE_GROUP = 33;
|
||||
int ELIST = 34;
|
||||
int FOR_INIT = 35;
|
||||
int FOR_CONDITION = 36;
|
||||
int FOR_ITERATOR = 37;
|
||||
int EMPTY_STAT = 38;
|
||||
int FINAL = 39;
|
||||
int ABSTRACT = 40;
|
||||
int STRICTFP = 41;
|
||||
int SUPER_CTOR_CALL = 42;
|
||||
int CTOR_CALL = 43;
|
||||
int LITERAL_package = 44;
|
||||
int SEMI = 45;
|
||||
int LITERAL_import = 46;
|
||||
int LBRACK = 47;
|
||||
int RBRACK = 48;
|
||||
int LITERAL_void = 49;
|
||||
int LITERAL_boolean = 50;
|
||||
int LITERAL_byte = 51;
|
||||
int LITERAL_char = 52;
|
||||
int LITERAL_short = 53;
|
||||
int LITERAL_int = 54;
|
||||
int LITERAL_float = 55;
|
||||
int LITERAL_long = 56;
|
||||
int LITERAL_double = 57;
|
||||
int IDENT = 58;
|
||||
int DOT = 59;
|
||||
int STAR = 60;
|
||||
int LITERAL_private = 61;
|
||||
int LITERAL_public = 62;
|
||||
int LITERAL_protected = 63;
|
||||
int LITERAL_static = 64;
|
||||
int LITERAL_transient = 65;
|
||||
int LITERAL_native = 66;
|
||||
int LITERAL_threadsafe = 67;
|
||||
int LITERAL_synchronized = 68;
|
||||
int LITERAL_volatile = 69;
|
||||
int LITERAL_class = 70;
|
||||
int LITERAL_extends = 71;
|
||||
int LITERAL_interface = 72;
|
||||
int LCURLY = 73;
|
||||
int RCURLY = 74;
|
||||
int COMMA = 75;
|
||||
int LITERAL_implements = 76;
|
||||
int LPAREN = 77;
|
||||
int RPAREN = 78;
|
||||
int LITERAL_this = 79;
|
||||
int LITERAL_super = 80;
|
||||
int ASSIGN = 81;
|
||||
int LITERAL_throws = 82;
|
||||
int COLON = 83;
|
||||
int LITERAL_if = 84;
|
||||
int LITERAL_else = 85;
|
||||
int LITERAL_for = 86;
|
||||
int LITERAL_while = 87;
|
||||
int LITERAL_do = 88;
|
||||
int LITERAL_break = 89;
|
||||
int LITERAL_continue = 90;
|
||||
int LITERAL_return = 91;
|
||||
int LITERAL_switch = 92;
|
||||
int LITERAL_throw = 93;
|
||||
int LITERAL_assert = 94;
|
||||
int LITERAL_case = 95;
|
||||
int LITERAL_default = 96;
|
||||
int LITERAL_try = 97;
|
||||
int LITERAL_finally = 98;
|
||||
int LITERAL_catch = 99;
|
||||
int PLUS_ASSIGN = 100;
|
||||
int MINUS_ASSIGN = 101;
|
||||
int STAR_ASSIGN = 102;
|
||||
int DIV_ASSIGN = 103;
|
||||
int MOD_ASSIGN = 104;
|
||||
int SR_ASSIGN = 105;
|
||||
int BSR_ASSIGN = 106;
|
||||
int SL_ASSIGN = 107;
|
||||
int BAND_ASSIGN = 108;
|
||||
int BXOR_ASSIGN = 109;
|
||||
int BOR_ASSIGN = 110;
|
||||
int QUESTION = 111;
|
||||
int LOR = 112;
|
||||
int LAND = 113;
|
||||
int BOR = 114;
|
||||
int BXOR = 115;
|
||||
int BAND = 116;
|
||||
int NOT_EQUAL = 117;
|
||||
int EQUAL = 118;
|
||||
int LT = 119;
|
||||
int GT = 120;
|
||||
int LE = 121;
|
||||
int GE = 122;
|
||||
int LITERAL_instanceof = 123;
|
||||
int SL = 124;
|
||||
int SR = 125;
|
||||
int BSR = 126;
|
||||
int PLUS = 127;
|
||||
int MINUS = 128;
|
||||
int DIV = 129;
|
||||
int MOD = 130;
|
||||
int INC = 131;
|
||||
int DEC = 132;
|
||||
int BNOT = 133;
|
||||
int LNOT = 134;
|
||||
int LITERAL_true = 135;
|
||||
int LITERAL_false = 136;
|
||||
int LITERAL_null = 137;
|
||||
int LITERAL_new = 138;
|
||||
int NUM_INT = 139;
|
||||
int CHAR_LITERAL = 140;
|
||||
int STRING_LITERAL = 141;
|
||||
int NUM_FLOAT = 142;
|
||||
int NUM_LONG = 143;
|
||||
int NUM_DOUBLE = 144;
|
||||
int WS = 145;
|
||||
int SL_COMMENT = 146;
|
||||
int ML_COMMENT = 147;
|
||||
int ESC = 148;
|
||||
int HEX_DIGIT = 149;
|
||||
int VOCAB = 150;
|
||||
int EXPONENT = 151;
|
||||
int FLOAT_SUFFIX = 152;
|
||||
int CONSTRUCTOR_CAST = 153;
|
||||
int EMPTY_FIELD = 154;
|
||||
int WEBCOLOR_LITERAL = 155;
|
||||
int LITERAL_color = 156;
|
||||
}
|
155
app/preproc/PdePartialTokenTypes.txt
Normal file
155
app/preproc/PdePartialTokenTypes.txt
Normal file
@ -0,0 +1,155 @@
|
||||
// $ANTLR 2.7.2: expandedpde.g -> PdePartialTokenTypes.txt$
|
||||
PdePartial // output token vocab name
|
||||
BLOCK=4
|
||||
MODIFIERS=5
|
||||
OBJBLOCK=6
|
||||
SLIST=7
|
||||
CTOR_DEF=8
|
||||
METHOD_DEF=9
|
||||
VARIABLE_DEF=10
|
||||
INSTANCE_INIT=11
|
||||
STATIC_INIT=12
|
||||
TYPE=13
|
||||
CLASS_DEF=14
|
||||
INTERFACE_DEF=15
|
||||
PACKAGE_DEF=16
|
||||
ARRAY_DECLARATOR=17
|
||||
EXTENDS_CLAUSE=18
|
||||
IMPLEMENTS_CLAUSE=19
|
||||
PARAMETERS=20
|
||||
PARAMETER_DEF=21
|
||||
LABELED_STAT=22
|
||||
TYPECAST=23
|
||||
INDEX_OP=24
|
||||
POST_INC=25
|
||||
POST_DEC=26
|
||||
METHOD_CALL=27
|
||||
EXPR=28
|
||||
ARRAY_INIT=29
|
||||
IMPORT=30
|
||||
UNARY_MINUS=31
|
||||
UNARY_PLUS=32
|
||||
CASE_GROUP=33
|
||||
ELIST=34
|
||||
FOR_INIT=35
|
||||
FOR_CONDITION=36
|
||||
FOR_ITERATOR=37
|
||||
EMPTY_STAT=38
|
||||
FINAL="final"=39
|
||||
ABSTRACT="abstract"=40
|
||||
STRICTFP="strictfp"=41
|
||||
SUPER_CTOR_CALL=42
|
||||
CTOR_CALL=43
|
||||
LITERAL_package="package"=44
|
||||
SEMI=45
|
||||
LITERAL_import="import"=46
|
||||
LBRACK=47
|
||||
RBRACK=48
|
||||
LITERAL_void="void"=49
|
||||
LITERAL_boolean="boolean"=50
|
||||
LITERAL_byte="byte"=51
|
||||
LITERAL_char="char"=52
|
||||
LITERAL_short="short"=53
|
||||
LITERAL_int="int"=54
|
||||
LITERAL_float="float"=55
|
||||
LITERAL_long="long"=56
|
||||
LITERAL_double="double"=57
|
||||
IDENT=58
|
||||
DOT=59
|
||||
STAR=60
|
||||
LITERAL_private="private"=61
|
||||
LITERAL_public="public"=62
|
||||
LITERAL_protected="protected"=63
|
||||
LITERAL_static="static"=64
|
||||
LITERAL_transient="transient"=65
|
||||
LITERAL_native="native"=66
|
||||
LITERAL_threadsafe="threadsafe"=67
|
||||
LITERAL_synchronized="synchronized"=68
|
||||
LITERAL_volatile="volatile"=69
|
||||
LITERAL_class="class"=70
|
||||
LITERAL_extends="extends"=71
|
||||
LITERAL_interface="interface"=72
|
||||
LCURLY=73
|
||||
RCURLY=74
|
||||
COMMA=75
|
||||
LITERAL_implements="implements"=76
|
||||
LPAREN=77
|
||||
RPAREN=78
|
||||
LITERAL_this="this"=79
|
||||
LITERAL_super="super"=80
|
||||
ASSIGN=81
|
||||
LITERAL_throws="throws"=82
|
||||
COLON=83
|
||||
LITERAL_if="if"=84
|
||||
LITERAL_else="else"=85
|
||||
LITERAL_for="for"=86
|
||||
LITERAL_while="while"=87
|
||||
LITERAL_do="do"=88
|
||||
LITERAL_break="break"=89
|
||||
LITERAL_continue="continue"=90
|
||||
LITERAL_return="return"=91
|
||||
LITERAL_switch="switch"=92
|
||||
LITERAL_throw="throw"=93
|
||||
LITERAL_assert="assert"=94
|
||||
LITERAL_case="case"=95
|
||||
LITERAL_default="default"=96
|
||||
LITERAL_try="try"=97
|
||||
LITERAL_finally="finally"=98
|
||||
LITERAL_catch="catch"=99
|
||||
PLUS_ASSIGN=100
|
||||
MINUS_ASSIGN=101
|
||||
STAR_ASSIGN=102
|
||||
DIV_ASSIGN=103
|
||||
MOD_ASSIGN=104
|
||||
SR_ASSIGN=105
|
||||
BSR_ASSIGN=106
|
||||
SL_ASSIGN=107
|
||||
BAND_ASSIGN=108
|
||||
BXOR_ASSIGN=109
|
||||
BOR_ASSIGN=110
|
||||
QUESTION=111
|
||||
LOR=112
|
||||
LAND=113
|
||||
BOR=114
|
||||
BXOR=115
|
||||
BAND=116
|
||||
NOT_EQUAL=117
|
||||
EQUAL=118
|
||||
LT=119
|
||||
GT=120
|
||||
LE=121
|
||||
GE=122
|
||||
LITERAL_instanceof="instanceof"=123
|
||||
SL=124
|
||||
SR=125
|
||||
BSR=126
|
||||
PLUS=127
|
||||
MINUS=128
|
||||
DIV=129
|
||||
MOD=130
|
||||
INC=131
|
||||
DEC=132
|
||||
BNOT=133
|
||||
LNOT=134
|
||||
LITERAL_true="true"=135
|
||||
LITERAL_false="false"=136
|
||||
LITERAL_null="null"=137
|
||||
LITERAL_new="new"=138
|
||||
NUM_INT=139
|
||||
CHAR_LITERAL=140
|
||||
STRING_LITERAL=141
|
||||
NUM_FLOAT=142
|
||||
NUM_LONG=143
|
||||
NUM_DOUBLE=144
|
||||
WS=145
|
||||
SL_COMMENT=146
|
||||
ML_COMMENT=147
|
||||
ESC=148
|
||||
HEX_DIGIT=149
|
||||
VOCAB=150
|
||||
EXPONENT=151
|
||||
FLOAT_SUFFIX=152
|
||||
CONSTRUCTOR_CAST=153
|
||||
EMPTY_FIELD=154
|
||||
WEBCOLOR_LITERAL=155
|
||||
LITERAL_color="color"=156
|
419
app/preproc/PdePreprocessor.java
Normal file
419
app/preproc/PdePreprocessor.java
Normal file
@ -0,0 +1,419 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PdePreprocessor - wrapper for default ANTLR-generated parser
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
ANTLR-generated parser and several supporting classes written
|
||||
by Dan Mosedale via funding from the Interaction Institute IVREA.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
//import processing.core.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import antlr.*;
|
||||
import antlr.collections.*;
|
||||
import antlr.collections.impl.*;
|
||||
|
||||
import com.oroinc.text.regex.*;
|
||||
|
||||
|
||||
public class PdePreprocessor {
|
||||
|
||||
static final int JDK11 = 0;
|
||||
static final int JDK13 = 1;
|
||||
static final int JDK14 = 2;
|
||||
|
||||
static String defaultImports[][] = new String[3][];
|
||||
|
||||
// these ones have the .* at the end, since a class name
|
||||
// might be at the end instead of .* whcih would make trouble
|
||||
// other classes using this can lop of the . and anything after
|
||||
// it to produce a package name consistently.
|
||||
public String extraImports[];
|
||||
|
||||
// imports just from the code folder, treated differently
|
||||
// than the others, since the imports are auto-generated.
|
||||
public String codeFolderImports[];
|
||||
|
||||
static public final int STATIC = 0; // formerly BEGINNER
|
||||
static public final int ACTIVE = 1; // formerly INTERMEDIATE
|
||||
static public final int JAVA = 2; // formerly ADVANCED
|
||||
// static to make it easier for the antlr preproc to get at it
|
||||
static public int programType = -1;
|
||||
|
||||
Reader programReader;
|
||||
String buildPath;
|
||||
|
||||
// used for calling the ASTFactory to get the root node
|
||||
private static final int ROOT_ID = 0;
|
||||
|
||||
|
||||
/**
|
||||
* These may change in-between (if the prefs panel adds this option)
|
||||
* so grab them here on construction.
|
||||
*/
|
||||
public PdePreprocessor() {
|
||||
defaultImports[JDK11] =
|
||||
Base.split(Preferences.get("preproc.imports.jdk11"), ',');
|
||||
defaultImports[JDK13] =
|
||||
Base.split(Preferences.get("preproc.imports.jdk13"), ',');
|
||||
defaultImports[JDK14] =
|
||||
Base.split(Preferences.get("preproc.imports.jdk14"), ',');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by PdeEmitter.dumpHiddenTokens()
|
||||
*/
|
||||
public static TokenStreamCopyingHiddenTokenFilter filter;
|
||||
|
||||
|
||||
/**
|
||||
* preprocesses a pde file and write out a java file
|
||||
* @return the classname of the exported Java
|
||||
*/
|
||||
//public String write(String program, String buildPath, String name,
|
||||
// String extraImports[]) throws java.lang.Exception {
|
||||
public String write(String program, String buildPath,
|
||||
String name, String codeFolderPackages[])
|
||||
throws java.lang.Exception {
|
||||
// if the program ends with no CR or LF an OutOfMemoryError will happen.
|
||||
// not gonna track down the bug now, so here's a hack for it:
|
||||
if ((program.length() > 0) &&
|
||||
program.charAt(program.length()-1) != '\n') {
|
||||
program += "\n";
|
||||
}
|
||||
|
||||
if (Preferences.getBoolean("preproc.substitute_unicode")) {
|
||||
// check for non-ascii chars (these will be/must be in unicode format)
|
||||
char p[] = program.toCharArray();
|
||||
int unicodeCount = 0;
|
||||
for (int i = 0; i < p.length; i++) {
|
||||
if (p[i] > 127) unicodeCount++;
|
||||
}
|
||||
// if non-ascii chars are in there, convert to unicode escapes
|
||||
if (unicodeCount != 0) {
|
||||
// add unicodeCount * 5.. replacing each unicode char
|
||||
// with six digit uXXXX sequence (xxxx is in hex)
|
||||
// (except for nbsp chars which will be a replaced with a space)
|
||||
int index = 0;
|
||||
char p2[] = new char[p.length + unicodeCount*5];
|
||||
for (int i = 0; i < p.length; i++) {
|
||||
if (p[i] < 128) {
|
||||
p2[index++] = p[i];
|
||||
|
||||
} else if (p[i] == 160) { // unicode for non-breaking space
|
||||
p2[index++] = ' ';
|
||||
|
||||
} else {
|
||||
int c = p[i];
|
||||
p2[index++] = '\\';
|
||||
p2[index++] = 'u';
|
||||
char str[] = Integer.toHexString(c).toCharArray();
|
||||
// add leading zeros, so that the length is 4
|
||||
//for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
|
||||
for (int m = 0; m < 4 - str.length; m++) p2[index++] = '0';
|
||||
System.arraycopy(str, 0, p2, index, str.length);
|
||||
index += str.length;
|
||||
}
|
||||
}
|
||||
program = new String(p2, 0, index);
|
||||
}
|
||||
}
|
||||
|
||||
// if this guy has his own imports, need to remove them
|
||||
// just in case it's not an advanced mode sketch
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
//String mess = "^\\s*(import\\s+\\S+\\s*;)";
|
||||
String mess = "^\\s*(import\\s+)(\\S+)(\\s*;)";
|
||||
java.util.Vector imports = new java.util.Vector();
|
||||
|
||||
Pattern pattern = null;
|
||||
try {
|
||||
pattern = compiler.compile(mess);
|
||||
} catch (MalformedPatternException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
do {
|
||||
PatternMatcherInput input = new PatternMatcherInput(program);
|
||||
if (!matcher.contains(input, pattern)) break;
|
||||
|
||||
MatchResult result = matcher.getMatch();
|
||||
String piece1 = result.group(1).toString();
|
||||
String piece2 = result.group(2).toString(); // the package name
|
||||
String piece3 = result.group(3).toString();
|
||||
String piece = piece1 + piece2 + piece3;
|
||||
int len = piece.length();
|
||||
|
||||
//imports.add(piece);
|
||||
imports.add(piece2);
|
||||
int idx = program.indexOf(piece);
|
||||
// just remove altogether?
|
||||
program = program.substring(0, idx) + program.substring(idx + len);
|
||||
|
||||
//System.out.println("removing " + piece);
|
||||
|
||||
} while (true);
|
||||
|
||||
extraImports = new String[imports.size()];
|
||||
imports.copyInto(extraImports);
|
||||
|
||||
// if using opengl, add it to the special imports
|
||||
/*
|
||||
if (Preferences.get("renderer").equals("opengl")) {
|
||||
extraImports = new String[imports.size() + 1];
|
||||
imports.copyInto(extraImports);
|
||||
extraImports[extraImports.length - 1] = "processing.opengl.*";
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if (codeFolderPackages != null) {
|
||||
extraImports = new String[importsCount + codeFolderPackages.length];
|
||||
imports.copyInto(extraImports);
|
||||
for (int i = 0; i < codeFolderPackages.length; i++) {
|
||||
extraImports[importsCount + i] = codeFolderPackages[i] + ".*";
|
||||
}
|
||||
codeFolderImports = null;
|
||||
}
|
||||
*/
|
||||
|
||||
if (codeFolderPackages != null) {
|
||||
codeFolderImports = new String[codeFolderPackages.length];
|
||||
for (int i = 0; i < codeFolderPackages.length; i++) {
|
||||
codeFolderImports[i] = codeFolderPackages[i] + ".*";
|
||||
}
|
||||
} else {
|
||||
codeFolderImports = null;
|
||||
}
|
||||
|
||||
// do this after the program gets re-combobulated
|
||||
this.programReader = new StringReader(program);
|
||||
this.buildPath = buildPath;
|
||||
|
||||
// create a lexer with the stream reader, and tell it to handle
|
||||
// hidden tokens (eg whitespace, comments) since we want to pass these
|
||||
// through so that the line numbers when the compiler reports errors
|
||||
// match those that will be highlighted in the PDE IDE
|
||||
//
|
||||
PdeLexer lexer = new PdeLexer(programReader);
|
||||
lexer.setTokenObjectClass("antlr.CommonHiddenStreamToken");
|
||||
|
||||
// create the filter for hidden tokens and specify which tokens to
|
||||
// hide and which to copy to the hidden text
|
||||
//
|
||||
filter = new TokenStreamCopyingHiddenTokenFilter(lexer);
|
||||
filter.hide(PdeRecognizer.SL_COMMENT);
|
||||
filter.hide(PdeRecognizer.ML_COMMENT);
|
||||
filter.hide(PdeRecognizer.WS);
|
||||
filter.copy(PdeRecognizer.SEMI);
|
||||
filter.copy(PdeRecognizer.LPAREN);
|
||||
filter.copy(PdeRecognizer.RPAREN);
|
||||
filter.copy(PdeRecognizer.LCURLY);
|
||||
filter.copy(PdeRecognizer.RCURLY);
|
||||
filter.copy(PdeRecognizer.COMMA);
|
||||
filter.copy(PdeRecognizer.RBRACK);
|
||||
filter.copy(PdeRecognizer.LBRACK);
|
||||
filter.copy(PdeRecognizer.COLON);
|
||||
|
||||
// create a parser and set what sort of AST should be generated
|
||||
//
|
||||
PdeRecognizer parser = new PdeRecognizer(filter);
|
||||
|
||||
// use our extended AST class
|
||||
//
|
||||
parser.setASTNodeClass("antlr.ExtendedCommonASTWithHiddenTokens");
|
||||
|
||||
// start parsing at the compilationUnit non-terminal
|
||||
//
|
||||
parser.pdeProgram();
|
||||
|
||||
// set up the AST for traversal by PdeEmitter
|
||||
//
|
||||
ASTFactory factory = new ASTFactory();
|
||||
AST parserAST = parser.getAST();
|
||||
AST rootNode = factory.create(ROOT_ID, "AST ROOT");
|
||||
rootNode.setFirstChild(parserAST);
|
||||
|
||||
// unclear if this actually works, but it's worth a shot
|
||||
//
|
||||
//((CommonAST)parserAST).setVerboseStringConversion(
|
||||
// true, parser.getTokenNames());
|
||||
// (made to use the static version because of jikes 1.22 warning)
|
||||
CommonAST.setVerboseStringConversion(true, parser.getTokenNames());
|
||||
|
||||
// if this is an advanced program, the classname is already defined.
|
||||
//
|
||||
if (programType == JAVA) {
|
||||
name = getFirstClassName(parserAST);
|
||||
}
|
||||
|
||||
// if 'null' was passed in for the name, but this isn't
|
||||
// a 'java' mode class, then there's a problem, so punt.
|
||||
//
|
||||
if (name == null) return null;
|
||||
|
||||
// output the code
|
||||
//
|
||||
PdeEmitter emitter = new PdeEmitter();
|
||||
File streamFile = new File(buildPath, name + ".java");
|
||||
PrintStream stream = new PrintStream(new FileOutputStream(streamFile));
|
||||
|
||||
//writeHeader(stream, extraImports, name);
|
||||
writeHeader(stream, name);
|
||||
|
||||
emitter.setOut(stream);
|
||||
emitter.print(rootNode);
|
||||
|
||||
writeFooter(stream);
|
||||
stream.close();
|
||||
|
||||
// if desired, serialize the parse tree to an XML file. can
|
||||
// be viewed usefully with Mozilla or IE
|
||||
|
||||
if (Preferences.getBoolean("preproc.output_parse_tree")) {
|
||||
|
||||
stream = new PrintStream(new FileOutputStream("parseTree.xml"));
|
||||
stream.println("<?xml version=\"1.0\"?>");
|
||||
stream.println("<document>");
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream);
|
||||
if (parserAST != null) {
|
||||
((CommonAST)parserAST).xmlSerialize(writer);
|
||||
}
|
||||
writer.flush();
|
||||
stream.println("</document>");
|
||||
writer.close();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write any required header material (eg imports, class decl stuff)
|
||||
*
|
||||
* @param out PrintStream to write it to.
|
||||
* @param exporting Is this being exported from PDE?
|
||||
* @param name Name of the class being created.
|
||||
*/
|
||||
void writeHeader(PrintStream out, String className) {
|
||||
|
||||
// must include processing.core
|
||||
out.print("import processing.core.*; ");
|
||||
|
||||
// emit emports that are needed for classes from the code folder
|
||||
if (extraImports != null) {
|
||||
for (int i = 0; i < extraImports.length; i++) {
|
||||
out.print("import " + extraImports[i] + "; ");
|
||||
}
|
||||
}
|
||||
|
||||
if (codeFolderImports != null) {
|
||||
for (int i = 0; i < codeFolderImports.length; i++) {
|
||||
out.print("import " + codeFolderImports[i] + "; ");
|
||||
}
|
||||
}
|
||||
|
||||
// emit standard imports (read from pde.properties)
|
||||
// for each language level that's being used.
|
||||
String jdkVersionStr = Preferences.get("preproc.jdk_version");
|
||||
|
||||
int jdkVersion = JDK11; // default
|
||||
if (jdkVersionStr.equals("1.3")) { jdkVersion = JDK13; };
|
||||
if (jdkVersionStr.equals("1.4")) { jdkVersion = JDK14; };
|
||||
|
||||
for (int i = 0; i <= jdkVersion; i++) {
|
||||
for (int j = 0; j < defaultImports[i].length; j++) {
|
||||
out.print("import " + defaultImports[i][j] + ".*; ");
|
||||
}
|
||||
}
|
||||
|
||||
//boolean opengl = Preferences.get("renderer").equals("opengl");
|
||||
//if (opengl) {
|
||||
//out.println("import processing.opengl.*; ");
|
||||
//}
|
||||
|
||||
if (programType < JAVA) {
|
||||
// open the class definition
|
||||
out.print("public class " + className + " extends ");
|
||||
//if (opengl) {
|
||||
//out.print("PAppletGL");
|
||||
//} else {
|
||||
out.print("PApplet");
|
||||
//}
|
||||
out.print(" {");
|
||||
|
||||
if (programType == STATIC) {
|
||||
// now that size() and background() can go inside of draw()
|
||||
// actually, use setup(), because when running externally
|
||||
// the applet size needs to be set before the window is drawn,
|
||||
// meaning that after setup() things need to be ducky.
|
||||
//out.print("public void draw() {");
|
||||
out.print("public void setup() {");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write any necessary closing text.
|
||||
*
|
||||
* @param out PrintStream to write it to.
|
||||
*/
|
||||
void writeFooter(PrintStream out) {
|
||||
|
||||
if (programType == STATIC) {
|
||||
// close off draw() definition
|
||||
out.print("noLoop(); ");
|
||||
out.print("}");
|
||||
}
|
||||
|
||||
if (programType < JAVA) {
|
||||
// close off the class definition
|
||||
out.print("}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static String advClassName = "";
|
||||
|
||||
/**
|
||||
* Find the first CLASS_DEF node in the tree, and return the name of the
|
||||
* class in question.
|
||||
*
|
||||
* XXXdmose right now, we're using a little hack to the grammar to get
|
||||
* this info. In fact, we should be descending the AST passed in.
|
||||
*/
|
||||
String getFirstClassName(AST ast) {
|
||||
|
||||
String t = advClassName;
|
||||
advClassName = "";
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
4345
app/preproc/PdeRecognizer.java
Normal file
4345
app/preproc/PdeRecognizer.java
Normal file
File diff suppressed because it is too large
Load Diff
163
app/preproc/PdeTokenTypes.java
Normal file
163
app/preproc/PdeTokenTypes.java
Normal file
@ -0,0 +1,163 @@
|
||||
// $ANTLR 2.7.2: "expandedpde.g" -> "PdeRecognizer.java"$
|
||||
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
public interface PdeTokenTypes {
|
||||
int EOF = 1;
|
||||
int NULL_TREE_LOOKAHEAD = 3;
|
||||
int BLOCK = 4;
|
||||
int MODIFIERS = 5;
|
||||
int OBJBLOCK = 6;
|
||||
int SLIST = 7;
|
||||
int CTOR_DEF = 8;
|
||||
int METHOD_DEF = 9;
|
||||
int VARIABLE_DEF = 10;
|
||||
int INSTANCE_INIT = 11;
|
||||
int STATIC_INIT = 12;
|
||||
int TYPE = 13;
|
||||
int CLASS_DEF = 14;
|
||||
int INTERFACE_DEF = 15;
|
||||
int PACKAGE_DEF = 16;
|
||||
int ARRAY_DECLARATOR = 17;
|
||||
int EXTENDS_CLAUSE = 18;
|
||||
int IMPLEMENTS_CLAUSE = 19;
|
||||
int PARAMETERS = 20;
|
||||
int PARAMETER_DEF = 21;
|
||||
int LABELED_STAT = 22;
|
||||
int TYPECAST = 23;
|
||||
int INDEX_OP = 24;
|
||||
int POST_INC = 25;
|
||||
int POST_DEC = 26;
|
||||
int METHOD_CALL = 27;
|
||||
int EXPR = 28;
|
||||
int ARRAY_INIT = 29;
|
||||
int IMPORT = 30;
|
||||
int UNARY_MINUS = 31;
|
||||
int UNARY_PLUS = 32;
|
||||
int CASE_GROUP = 33;
|
||||
int ELIST = 34;
|
||||
int FOR_INIT = 35;
|
||||
int FOR_CONDITION = 36;
|
||||
int FOR_ITERATOR = 37;
|
||||
int EMPTY_STAT = 38;
|
||||
int FINAL = 39;
|
||||
int ABSTRACT = 40;
|
||||
int STRICTFP = 41;
|
||||
int SUPER_CTOR_CALL = 42;
|
||||
int CTOR_CALL = 43;
|
||||
int LITERAL_package = 44;
|
||||
int SEMI = 45;
|
||||
int LITERAL_import = 46;
|
||||
int LBRACK = 47;
|
||||
int RBRACK = 48;
|
||||
int LITERAL_void = 49;
|
||||
int LITERAL_boolean = 50;
|
||||
int LITERAL_byte = 51;
|
||||
int LITERAL_char = 52;
|
||||
int LITERAL_short = 53;
|
||||
int LITERAL_int = 54;
|
||||
int LITERAL_float = 55;
|
||||
int LITERAL_long = 56;
|
||||
int LITERAL_double = 57;
|
||||
int IDENT = 58;
|
||||
int DOT = 59;
|
||||
int STAR = 60;
|
||||
int LITERAL_private = 61;
|
||||
int LITERAL_public = 62;
|
||||
int LITERAL_protected = 63;
|
||||
int LITERAL_static = 64;
|
||||
int LITERAL_transient = 65;
|
||||
int LITERAL_native = 66;
|
||||
int LITERAL_threadsafe = 67;
|
||||
int LITERAL_synchronized = 68;
|
||||
int LITERAL_volatile = 69;
|
||||
int LITERAL_class = 70;
|
||||
int LITERAL_extends = 71;
|
||||
int LITERAL_interface = 72;
|
||||
int LCURLY = 73;
|
||||
int RCURLY = 74;
|
||||
int COMMA = 75;
|
||||
int LITERAL_implements = 76;
|
||||
int LPAREN = 77;
|
||||
int RPAREN = 78;
|
||||
int LITERAL_this = 79;
|
||||
int LITERAL_super = 80;
|
||||
int ASSIGN = 81;
|
||||
int LITERAL_throws = 82;
|
||||
int COLON = 83;
|
||||
int LITERAL_if = 84;
|
||||
int LITERAL_else = 85;
|
||||
int LITERAL_for = 86;
|
||||
int LITERAL_while = 87;
|
||||
int LITERAL_do = 88;
|
||||
int LITERAL_break = 89;
|
||||
int LITERAL_continue = 90;
|
||||
int LITERAL_return = 91;
|
||||
int LITERAL_switch = 92;
|
||||
int LITERAL_throw = 93;
|
||||
int LITERAL_assert = 94;
|
||||
int LITERAL_case = 95;
|
||||
int LITERAL_default = 96;
|
||||
int LITERAL_try = 97;
|
||||
int LITERAL_finally = 98;
|
||||
int LITERAL_catch = 99;
|
||||
int PLUS_ASSIGN = 100;
|
||||
int MINUS_ASSIGN = 101;
|
||||
int STAR_ASSIGN = 102;
|
||||
int DIV_ASSIGN = 103;
|
||||
int MOD_ASSIGN = 104;
|
||||
int SR_ASSIGN = 105;
|
||||
int BSR_ASSIGN = 106;
|
||||
int SL_ASSIGN = 107;
|
||||
int BAND_ASSIGN = 108;
|
||||
int BXOR_ASSIGN = 109;
|
||||
int BOR_ASSIGN = 110;
|
||||
int QUESTION = 111;
|
||||
int LOR = 112;
|
||||
int LAND = 113;
|
||||
int BOR = 114;
|
||||
int BXOR = 115;
|
||||
int BAND = 116;
|
||||
int NOT_EQUAL = 117;
|
||||
int EQUAL = 118;
|
||||
int LT = 119;
|
||||
int GT = 120;
|
||||
int LE = 121;
|
||||
int GE = 122;
|
||||
int LITERAL_instanceof = 123;
|
||||
int SL = 124;
|
||||
int SR = 125;
|
||||
int BSR = 126;
|
||||
int PLUS = 127;
|
||||
int MINUS = 128;
|
||||
int DIV = 129;
|
||||
int MOD = 130;
|
||||
int INC = 131;
|
||||
int DEC = 132;
|
||||
int BNOT = 133;
|
||||
int LNOT = 134;
|
||||
int LITERAL_true = 135;
|
||||
int LITERAL_false = 136;
|
||||
int LITERAL_null = 137;
|
||||
int LITERAL_new = 138;
|
||||
int NUM_INT = 139;
|
||||
int CHAR_LITERAL = 140;
|
||||
int STRING_LITERAL = 141;
|
||||
int NUM_FLOAT = 142;
|
||||
int NUM_LONG = 143;
|
||||
int NUM_DOUBLE = 144;
|
||||
int WS = 145;
|
||||
int SL_COMMENT = 146;
|
||||
int ML_COMMENT = 147;
|
||||
int ESC = 148;
|
||||
int HEX_DIGIT = 149;
|
||||
int VOCAB = 150;
|
||||
int EXPONENT = 151;
|
||||
int FLOAT_SUFFIX = 152;
|
||||
int CONSTRUCTOR_CAST = 153;
|
||||
int EMPTY_FIELD = 154;
|
||||
int WEBCOLOR_LITERAL = 155;
|
||||
int LITERAL_color = 156;
|
||||
}
|
155
app/preproc/PdeTokenTypes.txt
Normal file
155
app/preproc/PdeTokenTypes.txt
Normal file
@ -0,0 +1,155 @@
|
||||
// $ANTLR 2.7.2: expandedpde.g -> PdeTokenTypes.txt$
|
||||
Pde // output token vocab name
|
||||
BLOCK=4
|
||||
MODIFIERS=5
|
||||
OBJBLOCK=6
|
||||
SLIST=7
|
||||
CTOR_DEF=8
|
||||
METHOD_DEF=9
|
||||
VARIABLE_DEF=10
|
||||
INSTANCE_INIT=11
|
||||
STATIC_INIT=12
|
||||
TYPE=13
|
||||
CLASS_DEF=14
|
||||
INTERFACE_DEF=15
|
||||
PACKAGE_DEF=16
|
||||
ARRAY_DECLARATOR=17
|
||||
EXTENDS_CLAUSE=18
|
||||
IMPLEMENTS_CLAUSE=19
|
||||
PARAMETERS=20
|
||||
PARAMETER_DEF=21
|
||||
LABELED_STAT=22
|
||||
TYPECAST=23
|
||||
INDEX_OP=24
|
||||
POST_INC=25
|
||||
POST_DEC=26
|
||||
METHOD_CALL=27
|
||||
EXPR=28
|
||||
ARRAY_INIT=29
|
||||
IMPORT=30
|
||||
UNARY_MINUS=31
|
||||
UNARY_PLUS=32
|
||||
CASE_GROUP=33
|
||||
ELIST=34
|
||||
FOR_INIT=35
|
||||
FOR_CONDITION=36
|
||||
FOR_ITERATOR=37
|
||||
EMPTY_STAT=38
|
||||
FINAL="final"=39
|
||||
ABSTRACT="abstract"=40
|
||||
STRICTFP="strictfp"=41
|
||||
SUPER_CTOR_CALL=42
|
||||
CTOR_CALL=43
|
||||
LITERAL_package="package"=44
|
||||
SEMI=45
|
||||
LITERAL_import="import"=46
|
||||
LBRACK=47
|
||||
RBRACK=48
|
||||
LITERAL_void="void"=49
|
||||
LITERAL_boolean="boolean"=50
|
||||
LITERAL_byte="byte"=51
|
||||
LITERAL_char="char"=52
|
||||
LITERAL_short="short"=53
|
||||
LITERAL_int="int"=54
|
||||
LITERAL_float="float"=55
|
||||
LITERAL_long="long"=56
|
||||
LITERAL_double="double"=57
|
||||
IDENT=58
|
||||
DOT=59
|
||||
STAR=60
|
||||
LITERAL_private="private"=61
|
||||
LITERAL_public="public"=62
|
||||
LITERAL_protected="protected"=63
|
||||
LITERAL_static="static"=64
|
||||
LITERAL_transient="transient"=65
|
||||
LITERAL_native="native"=66
|
||||
LITERAL_threadsafe="threadsafe"=67
|
||||
LITERAL_synchronized="synchronized"=68
|
||||
LITERAL_volatile="volatile"=69
|
||||
LITERAL_class="class"=70
|
||||
LITERAL_extends="extends"=71
|
||||
LITERAL_interface="interface"=72
|
||||
LCURLY=73
|
||||
RCURLY=74
|
||||
COMMA=75
|
||||
LITERAL_implements="implements"=76
|
||||
LPAREN=77
|
||||
RPAREN=78
|
||||
LITERAL_this="this"=79
|
||||
LITERAL_super="super"=80
|
||||
ASSIGN=81
|
||||
LITERAL_throws="throws"=82
|
||||
COLON=83
|
||||
LITERAL_if="if"=84
|
||||
LITERAL_else="else"=85
|
||||
LITERAL_for="for"=86
|
||||
LITERAL_while="while"=87
|
||||
LITERAL_do="do"=88
|
||||
LITERAL_break="break"=89
|
||||
LITERAL_continue="continue"=90
|
||||
LITERAL_return="return"=91
|
||||
LITERAL_switch="switch"=92
|
||||
LITERAL_throw="throw"=93
|
||||
LITERAL_assert="assert"=94
|
||||
LITERAL_case="case"=95
|
||||
LITERAL_default="default"=96
|
||||
LITERAL_try="try"=97
|
||||
LITERAL_finally="finally"=98
|
||||
LITERAL_catch="catch"=99
|
||||
PLUS_ASSIGN=100
|
||||
MINUS_ASSIGN=101
|
||||
STAR_ASSIGN=102
|
||||
DIV_ASSIGN=103
|
||||
MOD_ASSIGN=104
|
||||
SR_ASSIGN=105
|
||||
BSR_ASSIGN=106
|
||||
SL_ASSIGN=107
|
||||
BAND_ASSIGN=108
|
||||
BXOR_ASSIGN=109
|
||||
BOR_ASSIGN=110
|
||||
QUESTION=111
|
||||
LOR=112
|
||||
LAND=113
|
||||
BOR=114
|
||||
BXOR=115
|
||||
BAND=116
|
||||
NOT_EQUAL=117
|
||||
EQUAL=118
|
||||
LT=119
|
||||
GT=120
|
||||
LE=121
|
||||
GE=122
|
||||
LITERAL_instanceof="instanceof"=123
|
||||
SL=124
|
||||
SR=125
|
||||
BSR=126
|
||||
PLUS=127
|
||||
MINUS=128
|
||||
DIV=129
|
||||
MOD=130
|
||||
INC=131
|
||||
DEC=132
|
||||
BNOT=133
|
||||
LNOT=134
|
||||
LITERAL_true="true"=135
|
||||
LITERAL_false="false"=136
|
||||
LITERAL_null="null"=137
|
||||
LITERAL_new="new"=138
|
||||
NUM_INT=139
|
||||
CHAR_LITERAL=140
|
||||
STRING_LITERAL=141
|
||||
NUM_FLOAT=142
|
||||
NUM_LONG=143
|
||||
NUM_DOUBLE=144
|
||||
WS=145
|
||||
SL_COMMENT=146
|
||||
ML_COMMENT=147
|
||||
ESC=148
|
||||
HEX_DIGIT=149
|
||||
VOCAB=150
|
||||
EXPONENT=151
|
||||
FLOAT_SUFFIX=152
|
||||
CONSTRUCTOR_CAST=153
|
||||
EMPTY_FIELD=154
|
||||
WEBCOLOR_LITERAL=155
|
||||
LITERAL_color="color"=156
|
106
app/preproc/README.txt
Normal file
106
app/preproc/README.txt
Normal file
@ -0,0 +1,106 @@
|
||||
The PDE Preprocessor is based on the Java Grammar that comes with
|
||||
ANTLR 2.7.2. Moving it forward to a new version of the grammar
|
||||
shouldn't be too difficult.
|
||||
|
||||
Here's some info about the various files in this directory:
|
||||
|
||||
java.g: this is the ANTLR grammar for Java 1.3/1.4 from the ANTLR
|
||||
distribution. It is in the public domain. The only change to this
|
||||
file from the original this file is the uncommenting of the clauses
|
||||
required to support assert().
|
||||
|
||||
java.tree.g: this describes the Abstract Syntax Tree (AST) generated
|
||||
by java.g. It is only here as a reference for coders hacking on the
|
||||
preprocessor, it is not built or used at all. Note that pde.g
|
||||
overrides some of the java.g rules so that in PDE ASTs, there are a
|
||||
few minor differences. Also in the public domain.
|
||||
|
||||
pde.g: this is the grammar and lexer for the PDE language itself. It
|
||||
subclasses the java.g grammar and lexer. There are a couple of
|
||||
overrides to java.g that I hope to convince the ANTLR folks to fold
|
||||
back into their grammar, but most of this file is highly specific to
|
||||
PDE itself.
|
||||
|
||||
PdeEmitter.java: this class traverses the AST generated by the PDE
|
||||
Recognizer, and emits it as Java code, doing any necessary
|
||||
transformations along the way. It is based on JavaEmitter.java,
|
||||
available from antlr.org, written by Andy Tripp <atripp@comcast.net>,
|
||||
who has given permission for it to be distributed under the GPL.
|
||||
|
||||
ExtendedCommonASTWithHiddenTokens.java: this adds a necessary
|
||||
initialize() method, as well as a number of methods to allow for XML
|
||||
serialization of the parse tree in a such a way that the hidden tokens
|
||||
are visible. Much of the code is taken from the original
|
||||
CommonASTWithHiddenTokens class. I hope to convince the ANTLR folks
|
||||
to fold these changes back into that class so that this file will be
|
||||
unnecessary.
|
||||
|
||||
TokenStreamCopyingHiddenTokenFilter.java: this class provides
|
||||
TokenStreamHiddenTokenFilters with the concept of tokens which can be
|
||||
copied so that they are seen by both the hidden token stream as well
|
||||
as the parser itself. This is useful when one wants to use an
|
||||
existing parser (like the Java parser included with ANTLR) that throws
|
||||
away some tokens to create a parse tree which can be used to spit out
|
||||
a copy of the code with only minor modifications. Partially derived
|
||||
from ANTLR code. I hope to convince the ANTLR folks to fold this
|
||||
functionality back into ANTLR proper as well.
|
||||
|
||||
whitespace_test.pde: a torture test to ensure that the preprocessor is
|
||||
correctly preserving whitespace, comments, and other hidden tokens
|
||||
correctly. See the comments in the code for details about how to run
|
||||
the test.
|
||||
|
||||
All other files in this directory are generated at build time by ANTLR
|
||||
itself. The ANTLR manual goes into a fair amount of detail about the
|
||||
what each type of file is for.
|
||||
|
||||
|
||||
....
|
||||
|
||||
|
||||
Current Preprocessor Subsitutions:
|
||||
|
||||
"compiler.substitute_floats" (currently "substitute_f")
|
||||
- treat doubles as floats, i.e. 12.3 becomes 12.3f so that people
|
||||
don't have to add f after their numbers all the time. this is
|
||||
confusing for beginners.
|
||||
|
||||
"compiler.enhanced_casting"
|
||||
- byte(), char(), int(), float() works for casting. this is basic in
|
||||
the current implementation, but should be expanded as described
|
||||
above. color() works similarly to int(), however there is also a
|
||||
*function* called color(r, g, b) in p5. will this cause trouble?
|
||||
|
||||
"compiler.color_datattype"
|
||||
- 'color' is aliased to 'int' as a datatype to represent ARGB packed
|
||||
into a single int, commonly used in p5 for pixels[] and other color
|
||||
operations. this is just a search/replace type thing, and it can be
|
||||
used interchangeably with int.
|
||||
|
||||
"compiler.web_colors" (currently "inline_web_colors")
|
||||
- color c = #cc0080; should unpack to 0xffcc0080 (the ff at the top is
|
||||
so that the color is opaque), which is just an int.
|
||||
|
||||
Other preprocessor functionality
|
||||
|
||||
- detects what 'mode' the program is in: static (no function brackets
|
||||
at all, just assumes everything is in draw), active (setup plus draw
|
||||
or loop), and java mode (full java support).
|
||||
http://proce55ing.net/reference/environment/index.html
|
||||
|
||||
- size and background are pulled from draw mode programs and placed
|
||||
into setup(). this has a problem if size() is based on a variable,
|
||||
which we try to avoid people doing, but would like to be able to
|
||||
support it (perhaps by requiring the size() to be final?)
|
||||
|
||||
- currently does a godawful scrambling of the comments so that the
|
||||
substitution doesn't try to run on them. this also causes lots of
|
||||
bizarro bugs.
|
||||
|
||||
Possible?
|
||||
|
||||
- would be nice to just type code wherever, mixing a 'static' style
|
||||
app with a few functions. would be simpler for starting out. but it
|
||||
seems that the declarations would have to be pulled out, but that
|
||||
all seems problematic. or maybe it could all be inside a static { }
|
||||
block. but that wouldn't seem to work either.
|
221
app/preproc/TokenStreamCopyingHiddenTokenFilter.java
Normal file
221
app/preproc/TokenStreamCopyingHiddenTokenFilter.java
Normal file
@ -0,0 +1,221 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
package antlr;
|
||||
//package processing.app.preproc;
|
||||
|
||||
|
||||
import antlr.*;
|
||||
import antlr.collections.impl.BitSet;
|
||||
|
||||
/**
|
||||
* This class provides TokenStreamHiddenTokenFilters with the concept of
|
||||
* tokens which can be copied so that they are seen by both the hidden token
|
||||
* stream as well as the parser itself. This is useful when one wants to use
|
||||
* an existing parser (like the Java parser included with ANTLR) that throws
|
||||
* away some tokens to create a parse tree which can be used to spit out
|
||||
* a copy of the code with only minor modifications.
|
||||
*
|
||||
* This code is partially derived from the public domain ANLTR TokenStream
|
||||
*/
|
||||
public class TokenStreamCopyingHiddenTokenFilter
|
||||
extends TokenStreamHiddenTokenFilter
|
||||
implements TokenStream {
|
||||
|
||||
protected BitSet copyMask;
|
||||
CommonHiddenStreamToken hiddenCopy = null;
|
||||
|
||||
public TokenStreamCopyingHiddenTokenFilter(TokenStream input) {
|
||||
super(input);
|
||||
copyMask = new BitSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that all tokens of type tokenType should be copied. The copy
|
||||
* is put in the stream of hidden tokens, and the original is returned in the
|
||||
* stream of normal tokens.
|
||||
*
|
||||
* @param tokenType integer representing the token type to copied
|
||||
*/
|
||||
public void copy(int tokenType) {
|
||||
copyMask.add(tokenType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of the important parts of the given token. Note that this
|
||||
* does NOT copy the hiddenBefore and hiddenAfter fields.
|
||||
*
|
||||
* @param t token to partially clone
|
||||
* @return newly created partial clone
|
||||
*/
|
||||
public CommonHiddenStreamToken partialCloneToken(CommonHiddenStreamToken t) {
|
||||
|
||||
CommonHiddenStreamToken u = new CommonHiddenStreamToken(t.getType(),
|
||||
t.getText());
|
||||
u.setColumn(t.getColumn());
|
||||
u.setLine(t.getLine());
|
||||
u.setFilename(t.getFilename());
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
public void linkAndCopyToken(CommonHiddenStreamToken prev,
|
||||
CommonHiddenStreamToken monitored) {
|
||||
// create a copy of the token in the lookahead for use as hidden token
|
||||
hiddenCopy = partialCloneToken(LA(1));
|
||||
|
||||
// attach copy to the previous token, whether hidden or monitored
|
||||
prev.setHiddenAfter(hiddenCopy);
|
||||
|
||||
// if previous token was hidden, set the hiddenBefore pointer of the
|
||||
// copy to point back to it
|
||||
if (prev != monitored) {
|
||||
hiddenCopy.setHiddenBefore(prev);
|
||||
}
|
||||
|
||||
// we don't want the non-hidden copy to link back to the hidden
|
||||
// copy on the next pass through this function, so we leave
|
||||
// lastHiddenToken alone
|
||||
|
||||
//System.err.println("hidden copy: " + hiddenCopy.toString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private void consumeFirst() throws TokenStreamException {
|
||||
consume(); // get first token of input stream
|
||||
|
||||
// Handle situation where hidden or discarded tokens
|
||||
// appear first in input stream
|
||||
CommonHiddenStreamToken p=null;
|
||||
|
||||
// while hidden, copied, or discarded scarf tokens
|
||||
while ( hideMask.member(LA(1).getType()) ||
|
||||
discardMask.member(LA(1).getType()) ||
|
||||
copyMask.member(LA(1).getType()) ) {
|
||||
|
||||
// if we've hit one of the tokens that needs to be copied, we copy it
|
||||
// and then break out of the loop, because the parser needs to see it
|
||||
// too
|
||||
//
|
||||
if (copyMask.member(LA(1).getType())) {
|
||||
|
||||
// copy the token in the lookahead
|
||||
hiddenCopy = partialCloneToken(LA(1));
|
||||
|
||||
// if there's an existing token before this, link that and the
|
||||
// copy together
|
||||
if (p != null) {
|
||||
p.setHiddenAfter(hiddenCopy);
|
||||
hiddenCopy.setHiddenBefore(p); // double-link
|
||||
}
|
||||
|
||||
lastHiddenToken = hiddenCopy;
|
||||
if (firstHidden == null) {
|
||||
firstHidden = hiddenCopy;
|
||||
}
|
||||
|
||||
// we don't want to consume this token, because it also needs to
|
||||
// be passed through to the parser, so break out of the while look
|
||||
// entirely
|
||||
//
|
||||
break;
|
||||
} else if (hideMask.member(LA(1).getType())) {
|
||||
if (p != null) {
|
||||
p.setHiddenAfter(LA(1));
|
||||
LA(1).setHiddenBefore(p); // double-link
|
||||
}
|
||||
p = LA(1);
|
||||
|
||||
lastHiddenToken = p;
|
||||
if (firstHidden == null) {
|
||||
firstHidden = p; // record hidden token if first
|
||||
}
|
||||
}
|
||||
consume();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the next monitored token.
|
||||
* Test the token following the monitored token.
|
||||
* If following is another monitored token, save it
|
||||
* for the next invocation of nextToken (like a single
|
||||
* lookahead token) and return it then.
|
||||
* If following is unmonitored, nondiscarded (hidden)
|
||||
* channel token, add it to the monitored token.
|
||||
*
|
||||
* Note: EOF must be a monitored Token.
|
||||
*/
|
||||
public Token nextToken() throws TokenStreamException {
|
||||
// handle an initial condition; don't want to get lookahead
|
||||
// token of this splitter until first call to nextToken
|
||||
if (LA(1) == null) {
|
||||
consumeFirst();
|
||||
}
|
||||
|
||||
//System.err.println();
|
||||
|
||||
// we always consume hidden tokens after monitored, thus,
|
||||
// upon entry LA(1) is a monitored token.
|
||||
CommonHiddenStreamToken monitored = LA(1);
|
||||
|
||||
// point to hidden tokens found during last invocation
|
||||
monitored.setHiddenBefore(lastHiddenToken);
|
||||
lastHiddenToken = null;
|
||||
|
||||
// Look for hidden tokens, hook them into list emanating
|
||||
// from the monitored tokens.
|
||||
consume();
|
||||
CommonHiddenStreamToken prev = monitored;
|
||||
|
||||
// deal with as many not-purely-monitored tokens as possible
|
||||
while ( hideMask.member(LA(1).getType()) ||
|
||||
discardMask.member(LA(1).getType()) ||
|
||||
copyMask.member(LA(1).getType()) ) {
|
||||
|
||||
if (copyMask.member(LA(1).getType())) {
|
||||
|
||||
// copy the token and link it backwards
|
||||
if (hiddenCopy != null) {
|
||||
linkAndCopyToken(hiddenCopy, monitored);
|
||||
} else {
|
||||
linkAndCopyToken(prev, monitored);
|
||||
}
|
||||
|
||||
// we now need to parse it as a monitored token, so we return, which
|
||||
// avoids the consume() call at the end of this loop. the next call
|
||||
// will parse it as a monitored token.
|
||||
//System.err.println("returned: " + monitored.toString());
|
||||
return monitored;
|
||||
|
||||
} else if (hideMask.member(LA(1).getType())) {
|
||||
|
||||
// attach the hidden token to the monitored in a chain
|
||||
// link forwards
|
||||
prev.setHiddenAfter(LA(1));
|
||||
|
||||
// link backwards
|
||||
if (prev != monitored) { //hidden cannot point to monitored tokens
|
||||
LA(1).setHiddenBefore(prev);
|
||||
} else if (hiddenCopy != null) {
|
||||
hiddenCopy.setHiddenAfter(LA(1));
|
||||
LA(1).setHiddenBefore(hiddenCopy);
|
||||
hiddenCopy = null;
|
||||
}
|
||||
|
||||
//System.err.println("hidden: " + prev.getHiddenAfter().toString() + "\" after: " + prev.toString());
|
||||
prev = lastHiddenToken = LA(1);
|
||||
}
|
||||
|
||||
consume();
|
||||
}
|
||||
|
||||
// remember the last hidden token for next time around
|
||||
if (hiddenCopy != null) {
|
||||
lastHiddenToken = hiddenCopy;
|
||||
hiddenCopy = null;
|
||||
}
|
||||
|
||||
//System.err.println("returned: " + monitored.toString());
|
||||
return monitored;
|
||||
}
|
||||
}
|
11
app/preproc/clean.sh
Executable file
11
app/preproc/clean.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -f *Lexer.java
|
||||
rm -f *Recognizer.java
|
||||
rm -f *TokenTypes.java
|
||||
rm -f *TokenTypes.txt
|
||||
rm -f *TreeParser.java
|
||||
rm -f *TreeParserTokenTypes.java
|
||||
rm -f *TreeParserTokenTypes.txt
|
||||
rm -f expanded*.g
|
||||
|
1112
app/preproc/expandedpde.g
Normal file
1112
app/preproc/expandedpde.g
Normal file
File diff suppressed because it is too large
Load Diff
1276
app/preproc/java.g
Normal file
1276
app/preproc/java.g
Normal file
File diff suppressed because it is too large
Load Diff
326
app/preproc/java.tree.g
Normal file
326
app/preproc/java.tree.g
Normal file
@ -0,0 +1,326 @@
|
||||
package antlr;
|
||||
|
||||
|
||||
/** Java 1.3 AST Recognizer Grammar
|
||||
*
|
||||
* Author: (see java.g preamble)
|
||||
*
|
||||
* This grammar is in the PUBLIC DOMAIN
|
||||
*/
|
||||
class JavaTreeParser extends TreeParser;
|
||||
|
||||
options {
|
||||
importVocab = Java;
|
||||
}
|
||||
|
||||
compilationUnit
|
||||
: (packageDefinition)?
|
||||
(importDefinition)*
|
||||
(typeDefinition)*
|
||||
;
|
||||
|
||||
packageDefinition
|
||||
: #( PACKAGE_DEF identifier )
|
||||
;
|
||||
|
||||
importDefinition
|
||||
: #( IMPORT identifierStar )
|
||||
;
|
||||
|
||||
typeDefinition
|
||||
: #(CLASS_DEF modifiers IDENT extendsClause implementsClause objBlock )
|
||||
| #(INTERFACE_DEF modifiers IDENT extendsClause interfaceBlock )
|
||||
;
|
||||
|
||||
typeSpec
|
||||
: #(TYPE typeSpecArray)
|
||||
;
|
||||
|
||||
typeSpecArray
|
||||
: #( ARRAY_DECLARATOR typeSpecArray )
|
||||
| type
|
||||
;
|
||||
|
||||
type: identifier
|
||||
| builtInType
|
||||
;
|
||||
|
||||
builtInType
|
||||
: "void"
|
||||
| "boolean"
|
||||
| "byte"
|
||||
| "char"
|
||||
| "short"
|
||||
| "int"
|
||||
| "float"
|
||||
| "long"
|
||||
| "double"
|
||||
;
|
||||
|
||||
modifiers
|
||||
: #( MODIFIERS (modifier)* )
|
||||
;
|
||||
|
||||
modifier
|
||||
: "private"
|
||||
| "public"
|
||||
| "protected"
|
||||
| "static"
|
||||
| "transient"
|
||||
| "final"
|
||||
| "abstract"
|
||||
| "native"
|
||||
| "threadsafe"
|
||||
| "synchronized"
|
||||
| "const"
|
||||
| "volatile"
|
||||
| "strictfp"
|
||||
;
|
||||
|
||||
extendsClause
|
||||
: #(EXTENDS_CLAUSE (identifier)* )
|
||||
;
|
||||
|
||||
implementsClause
|
||||
: #(IMPLEMENTS_CLAUSE (identifier)* )
|
||||
;
|
||||
|
||||
|
||||
interfaceBlock
|
||||
: #( OBJBLOCK
|
||||
( methodDecl
|
||||
| variableDef
|
||||
)*
|
||||
)
|
||||
;
|
||||
|
||||
objBlock
|
||||
: #( OBJBLOCK
|
||||
( ctorDef
|
||||
| methodDef
|
||||
| variableDef
|
||||
| typeDefinition
|
||||
| #(STATIC_INIT slist)
|
||||
| #(INSTANCE_INIT slist)
|
||||
)*
|
||||
)
|
||||
;
|
||||
|
||||
ctorDef
|
||||
: #(CTOR_DEF modifiers methodHead (slist)?)
|
||||
;
|
||||
|
||||
methodDecl
|
||||
: #(METHOD_DEF modifiers typeSpec methodHead)
|
||||
;
|
||||
|
||||
methodDef
|
||||
: #(METHOD_DEF modifiers typeSpec methodHead (slist)?)
|
||||
;
|
||||
|
||||
variableDef
|
||||
: #(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
|
||||
;
|
||||
|
||||
parameterDef
|
||||
: #(PARAMETER_DEF modifiers typeSpec IDENT )
|
||||
;
|
||||
|
||||
objectinitializer
|
||||
: #(INSTANCE_INIT slist)
|
||||
;
|
||||
|
||||
variableDeclarator
|
||||
: IDENT
|
||||
| LBRACK variableDeclarator
|
||||
;
|
||||
|
||||
varInitializer
|
||||
: #(ASSIGN initializer)
|
||||
|
|
||||
;
|
||||
|
||||
initializer
|
||||
: expression
|
||||
| arrayInitializer
|
||||
;
|
||||
|
||||
arrayInitializer
|
||||
: #(ARRAY_INIT (initializer)*)
|
||||
;
|
||||
|
||||
methodHead
|
||||
: IDENT #( PARAMETERS (parameterDef)* ) (throwsClause)?
|
||||
;
|
||||
|
||||
throwsClause
|
||||
: #( "throws" (identifier)* )
|
||||
;
|
||||
|
||||
identifier
|
||||
: IDENT
|
||||
| #( DOT identifier IDENT )
|
||||
;
|
||||
|
||||
identifierStar
|
||||
: IDENT
|
||||
| #( DOT identifier (STAR|IDENT) )
|
||||
;
|
||||
|
||||
slist
|
||||
: #( SLIST (stat)* )
|
||||
;
|
||||
|
||||
stat: typeDefinition
|
||||
| variableDef
|
||||
| expression
|
||||
| #(LABELED_STAT IDENT stat)
|
||||
| #("if" expression stat (stat)? )
|
||||
| #( "for"
|
||||
#(FOR_INIT (variableDef | elist)?)
|
||||
#(FOR_CONDITION (expression)?)
|
||||
#(FOR_ITERATOR (elist)?)
|
||||
stat
|
||||
)
|
||||
| #("while" expression stat)
|
||||
| #("do" stat expression)
|
||||
| #("break" (IDENT)? )
|
||||
| #("continue" (IDENT)? )
|
||||
| #("return" (expression)? )
|
||||
| #("switch" expression (caseGroup)*)
|
||||
| #("throw" expression)
|
||||
| #("synchronized" expression stat)
|
||||
| tryBlock
|
||||
| slist // nested SLIST
|
||||
// uncomment to make assert JDK 1.4 stuff work
|
||||
| #("assert" expression (expression)?)
|
||||
| EMPTY_STAT
|
||||
;
|
||||
|
||||
caseGroup
|
||||
: #(CASE_GROUP (#("case" expression) | "default")+ slist)
|
||||
;
|
||||
|
||||
tryBlock
|
||||
: #( "try" slist (handler)* (#("finally" slist))? )
|
||||
;
|
||||
|
||||
handler
|
||||
: #( "catch" parameterDef slist )
|
||||
;
|
||||
|
||||
elist
|
||||
: #( ELIST (expression)* )
|
||||
;
|
||||
|
||||
expression
|
||||
: #(EXPR expr)
|
||||
;
|
||||
|
||||
expr: #(QUESTION expr expr expr) // trinary operator
|
||||
| #(ASSIGN expr expr) // binary operators...
|
||||
| #(PLUS_ASSIGN expr expr)
|
||||
| #(MINUS_ASSIGN expr expr)
|
||||
| #(STAR_ASSIGN expr expr)
|
||||
| #(DIV_ASSIGN expr expr)
|
||||
| #(MOD_ASSIGN expr expr)
|
||||
| #(SR_ASSIGN expr expr)
|
||||
| #(BSR_ASSIGN expr expr)
|
||||
| #(SL_ASSIGN expr expr)
|
||||
| #(BAND_ASSIGN expr expr)
|
||||
| #(BXOR_ASSIGN expr expr)
|
||||
| #(BOR_ASSIGN expr expr)
|
||||
| #(LOR expr expr)
|
||||
| #(LAND expr expr)
|
||||
| #(BOR expr expr)
|
||||
| #(BXOR expr expr)
|
||||
| #(BAND expr expr)
|
||||
| #(NOT_EQUAL expr expr)
|
||||
| #(EQUAL expr expr)
|
||||
| #(LT expr expr)
|
||||
| #(GT expr expr)
|
||||
| #(LE expr expr)
|
||||
| #(GE expr expr)
|
||||
| #(SL expr expr)
|
||||
| #(SR expr expr)
|
||||
| #(BSR expr expr)
|
||||
| #(PLUS expr expr)
|
||||
| #(MINUS expr expr)
|
||||
| #(DIV expr expr)
|
||||
| #(MOD expr expr)
|
||||
| #(STAR expr expr)
|
||||
| #(INC expr)
|
||||
| #(DEC expr)
|
||||
| #(POST_INC expr)
|
||||
| #(POST_DEC expr)
|
||||
| #(BNOT expr)
|
||||
| #(LNOT expr)
|
||||
| #("instanceof" expr expr)
|
||||
| #(UNARY_MINUS expr)
|
||||
| #(UNARY_PLUS expr)
|
||||
| primaryExpression
|
||||
;
|
||||
|
||||
primaryExpression
|
||||
: IDENT
|
||||
| #( DOT
|
||||
( expr
|
||||
( IDENT
|
||||
| arrayIndex
|
||||
| "this"
|
||||
| "class"
|
||||
| #( "new" IDENT elist )
|
||||
| "super"
|
||||
)
|
||||
| #(ARRAY_DECLARATOR typeSpecArray)
|
||||
| builtInType ("class")?
|
||||
)
|
||||
)
|
||||
| arrayIndex
|
||||
| #(METHOD_CALL primaryExpression elist)
|
||||
| ctorCall
|
||||
| #(TYPECAST typeSpec expr)
|
||||
| newExpression
|
||||
| constant
|
||||
| "super"
|
||||
| "true"
|
||||
| "false"
|
||||
| "this"
|
||||
| "null"
|
||||
| typeSpec // type name used with instanceof
|
||||
;
|
||||
|
||||
ctorCall
|
||||
: #( CTOR_CALL elist )
|
||||
| #( SUPER_CTOR_CALL
|
||||
( elist
|
||||
| primaryExpression elist
|
||||
)
|
||||
)
|
||||
;
|
||||
|
||||
arrayIndex
|
||||
: #(INDEX_OP expr expression)
|
||||
;
|
||||
|
||||
constant
|
||||
: NUM_INT
|
||||
| CHAR_LITERAL
|
||||
| STRING_LITERAL
|
||||
| NUM_FLOAT
|
||||
| NUM_DOUBLE
|
||||
| NUM_LONG
|
||||
;
|
||||
|
||||
newExpression
|
||||
: #( "new" type
|
||||
( newArrayDeclarator (arrayInitializer)?
|
||||
| elist (objBlock)?
|
||||
)
|
||||
)
|
||||
|
||||
;
|
||||
|
||||
newArrayDeclarator
|
||||
: #( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
|
||||
;
|
3
app/preproc/make.sh
Executable file
3
app/preproc/make.sh
Executable file
@ -0,0 +1,3 @@
|
||||
java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool java.g
|
||||
# now build the pde stuff that extends the java classes
|
||||
java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool -glib java.g pde.g
|
304
app/preproc/pde.g
Normal file
304
app/preproc/pde.g
Normal file
@ -0,0 +1,304 @@
|
||||
/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
header {
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
}
|
||||
|
||||
class PdeRecognizer extends JavaRecognizer;
|
||||
|
||||
options {
|
||||
importVocab = Java;
|
||||
exportVocab = PdePartial;
|
||||
|
||||
codeGenMakeSwitchThreshold=10; // this is set high for debugging
|
||||
codeGenBitsetTestThreshold=10; // this is set high for debugging
|
||||
|
||||
// developers may to want to set this to true for better
|
||||
// debugging messages, however, doing so disables highlighting errors
|
||||
// in the editor.
|
||||
defaultErrorHandler = false; //true;
|
||||
}
|
||||
|
||||
tokens {
|
||||
CONSTRUCTOR_CAST; EMPTY_FIELD;
|
||||
}
|
||||
|
||||
pdeProgram
|
||||
// only java mode programs will have their own public classes or
|
||||
// imports (and they must have at least one)
|
||||
: ( "public" "class" | "import" ) => javaProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.JAVA; }
|
||||
|
||||
// the syntactic predicate here looks for any minimal (thus
|
||||
// the non-greedy qualifier) number of fields, followed by
|
||||
// the tokens that represent the definition of loop() or
|
||||
// some other member function. java mode programs may have such
|
||||
// definitions, but they won't reach this point, having already been
|
||||
// selected in the previous alternative. static mode programs
|
||||
// don't have member functions.
|
||||
//
|
||||
| ( ( options {greedy=false;}: possiblyEmptyField)* "void" IDENT LPAREN )
|
||||
=> activeProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.ACTIVE; }
|
||||
|
||||
| staticProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.STATIC; }
|
||||
;
|
||||
|
||||
// advanced mode is really just a normal java file
|
||||
javaProgram
|
||||
: compilationUnit
|
||||
;
|
||||
|
||||
activeProgram
|
||||
: (possiblyEmptyField)+
|
||||
;
|
||||
|
||||
staticProgram
|
||||
: (statement)*
|
||||
;
|
||||
|
||||
// copy of the java.g rule with WEBCOLOR_LITERAL added
|
||||
constant
|
||||
: NUM_INT
|
||||
| CHAR_LITERAL
|
||||
| STRING_LITERAL
|
||||
| NUM_FLOAT
|
||||
| NUM_LONG
|
||||
| NUM_DOUBLE
|
||||
| webcolor_literal
|
||||
;
|
||||
|
||||
// of the form #cc008f in PDE
|
||||
webcolor_literal
|
||||
: w:WEBCOLOR_LITERAL
|
||||
{ Preferences.getBoolean("preproc.web_colors") &&
|
||||
w.getText().length() == 6 }? // must be exactly 6 hex digits
|
||||
;
|
||||
|
||||
// copy of the java.g builtInType rule
|
||||
builtInConsCastType
|
||||
: "void"
|
||||
| "boolean"
|
||||
| "byte"
|
||||
| "char"
|
||||
| "short"
|
||||
| "int"
|
||||
| "float"
|
||||
| "long"
|
||||
| "double"
|
||||
;
|
||||
|
||||
// our types include the java types and "color". this is separated into two
|
||||
// rules so that constructor casts can just use the original typelist, since
|
||||
// we don't want to support the color type as a constructor cast.
|
||||
//
|
||||
builtInType
|
||||
: builtInConsCastType
|
||||
| "color" // aliased to an int in PDE
|
||||
{ Preferences.getBoolean("preproc.color_datatype") }?
|
||||
;
|
||||
|
||||
// constructor style casts.
|
||||
constructorCast!
|
||||
: t:consCastTypeSpec[true]
|
||||
LPAREN!
|
||||
e:expression
|
||||
RPAREN!
|
||||
// if this is a string literal, make sure the type we're trying to cast
|
||||
// to is one of the supported ones
|
||||
//
|
||||
{ #e.getType() != STRING_LITERAL ||
|
||||
( #t.getType() == LITERAL_byte ||
|
||||
#t.getType() == LITERAL_double ||
|
||||
#t.getType() == LITERAL_float ||
|
||||
#t.getType() == LITERAL_int ||
|
||||
#t.getType() == LITERAL_long ||
|
||||
#t.getType() == LITERAL_short ) }?
|
||||
// create the node
|
||||
//
|
||||
{#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);}
|
||||
;
|
||||
|
||||
// A list of types that be used as the destination type in a constructor-style
|
||||
// cast. Ideally, this would include all class types, not just "String".
|
||||
// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be
|
||||
// a method call or a constructor cast without have a table of all valid
|
||||
// types or methods, which requires semantic analysis (eg processing of import
|
||||
// statements). So we accept the set of built-in types plus "String".
|
||||
//
|
||||
consCastTypeSpec[boolean addImagNode]
|
||||
// : stringTypeSpec[addImagNode]
|
||||
// | builtInConsCastTypeSpec[addImagNode]
|
||||
: builtInConsCastTypeSpec[addImagNode]
|
||||
// trying to remove String() cast [fry]
|
||||
;
|
||||
|
||||
//stringTypeSpec[boolean addImagNode]
|
||||
// : id:IDENT { #id.getText().equals("String") }?
|
||||
// {
|
||||
// if ( addImagNode ) {
|
||||
// #stringTypeSpec = #(#[TYPE,"TYPE"],
|
||||
// #stringTypeSpec);
|
||||
// }
|
||||
// }
|
||||
// ;
|
||||
|
||||
builtInConsCastTypeSpec[boolean addImagNode]
|
||||
: builtInConsCastType
|
||||
{
|
||||
if ( addImagNode ) {
|
||||
#builtInConsCastTypeSpec = #(#[TYPE,"TYPE"],
|
||||
#builtInConsCastTypeSpec);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule
|
||||
// that can generate a method call from an expression that starts with this
|
||||
// token
|
||||
//
|
||||
colorMethodCall
|
||||
: c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color
|
||||
lp:LPAREN^ {#lp.setType(METHOD_CALL);}
|
||||
argList
|
||||
RPAREN!
|
||||
;
|
||||
|
||||
// copy of the java.g rule with added constructorCast and colorMethodCall
|
||||
// alternatives
|
||||
primaryExpression
|
||||
: (consCastTypeSpec[false] LPAREN) => constructorCast
|
||||
{ Preferences.getBoolean("preproc.enhanced_casting") }?
|
||||
| identPrimary ( options {greedy=true;} : DOT^ "class" )?
|
||||
| constant
|
||||
| "true"
|
||||
| "false"
|
||||
| "null"
|
||||
| newExpression
|
||||
| "this"
|
||||
| "super"
|
||||
| LPAREN! assignmentExpression RPAREN!
|
||||
| colorMethodCall
|
||||
// look for int.class and int[].class
|
||||
| builtInType
|
||||
( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
|
||||
DOT^ "class"
|
||||
;
|
||||
|
||||
// the below variable rule hacks are needed so that it's possible for the
|
||||
// emitter to correctly output variable declarations of the form "float a, b"
|
||||
// from the AST. This means that our AST has a somewhat different form in
|
||||
// these rules than the java one does, and this new form may have its own
|
||||
// semantic issues. But it seems to fix the comma declaration issues.
|
||||
//
|
||||
variableDefinitions![AST mods, AST t]
|
||||
: vd:variableDeclarator[getASTFactory().dupTree(mods),
|
||||
getASTFactory().dupTree(t)]
|
||||
{#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods,
|
||||
t, vd);}
|
||||
;
|
||||
variableDeclarator[AST mods, AST t]
|
||||
: ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
|
||||
v:varInitializer (COMMA!)? )+
|
||||
;
|
||||
|
||||
// java.g builds syntax trees with an inconsistent structure. override one of
|
||||
// the rules there to fix this.
|
||||
//
|
||||
explicitConstructorInvocation!
|
||||
: t:"this" LPAREN a1:argList RPAREN SEMI
|
||||
{#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"],
|
||||
#t, #a1);}
|
||||
| s:"super" LPAREN a2:argList RPAREN SEMI
|
||||
{#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL,
|
||||
"SUPER_CTOR_CALL"],
|
||||
#s, #a2);}
|
||||
;
|
||||
|
||||
// quick-n-dirty hack to the get the advanced class name. we should
|
||||
// really be getting it from the AST and not forking this rule from
|
||||
// the java.g copy at all. Since this is a recursive descent parser, we get
|
||||
// the last class name in the file so that we don't end up with the classname
|
||||
// of an inner class. If there is more than one "outer" class in a file,
|
||||
// this heuristic will fail.
|
||||
//
|
||||
classDefinition![AST modifiers]
|
||||
: "class" i:IDENT
|
||||
// it _might_ have a superclass...
|
||||
sc:superClassClause
|
||||
// it might implement some interfaces...
|
||||
ic:implementsClause
|
||||
// now parse the body of the class
|
||||
cb:classBlock
|
||||
{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
|
||||
modifiers,i,sc,ic,cb);
|
||||
PdePreprocessor.advClassName = i.getText();}
|
||||
;
|
||||
|
||||
possiblyEmptyField
|
||||
: field
|
||||
| s:SEMI {#s.setType(EMPTY_FIELD);}
|
||||
;
|
||||
|
||||
class PdeLexer extends JavaLexer;
|
||||
|
||||
options {
|
||||
importVocab=PdePartial;
|
||||
exportVocab=Pde;
|
||||
}
|
||||
|
||||
// We need to preserve whitespace and commentary instead of ignoring
|
||||
// like the supergrammar does. Otherwise Jikes won't be able to give
|
||||
// us error messages that point to the equivalent PDE code.
|
||||
|
||||
// WS, SL_COMMENT, ML_COMMENT are copies of the original productions,
|
||||
// but with the SKIP assigment removed.
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\f'
|
||||
// handle newlines
|
||||
| ( options {generateAmbigWarnings=false;}
|
||||
: "\r\n" // Evil DOS
|
||||
| '\r' // Macintosh
|
||||
| '\n' // Unix (the right way)
|
||||
)
|
||||
{ newline(); }
|
||||
)+
|
||||
;
|
||||
|
||||
// Single-line comments
|
||||
SL_COMMENT
|
||||
: "//"
|
||||
(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
|
||||
{newline();}
|
||||
;
|
||||
|
||||
// multiple-line comments
|
||||
ML_COMMENT
|
||||
: "/*"
|
||||
( /* '\r' '\n' can be matched in one alternative or by matching
|
||||
'\r' in one iteration and '\n' in another. I am trying to
|
||||
handle any flavor of newline that comes in, but the language
|
||||
that allows both "\r\n" and "\r" and "\n" to all be valid
|
||||
newline is ambiguous. Consequently, the resulting grammar
|
||||
must be ambiguous. I'm shutting this warning off.
|
||||
*/
|
||||
options {
|
||||
generateAmbigWarnings=false;
|
||||
}
|
||||
:
|
||||
{ LA(2)!='/' }? '*'
|
||||
| '\r' '\n' {newline();}
|
||||
| '\r' {newline();}
|
||||
| '\n' {newline();}
|
||||
| ~('*'|'\n'|'\r')
|
||||
)*
|
||||
"*/"
|
||||
;
|
||||
|
||||
WEBCOLOR_LITERAL
|
||||
: '#'! (HEX_DIGIT)+
|
||||
;
|
150
app/preproc/whitespace_test.pde
Executable file
150
app/preproc/whitespace_test.pde
Executable file
@ -0,0 +1,150 @@
|
||||
// this is a whitespace and other invisible token torture test for the ANTLR-based
|
||||
// preprocessor. edit pde.properties and set "editor.save_build_files" to true.
|
||||
// then, build this in processing. next, use
|
||||
//
|
||||
// diff -u --strip-trailing-cr \
|
||||
// work/sketchbook/default/whitespace_test/whitespace_test.pde \
|
||||
// work/lib/build/MyDemo.java
|
||||
//
|
||||
// to compare the files before and after preprocessing. There should not be
|
||||
// any differences.
|
||||
|
||||
import // comment test
|
||||
java.io.*;
|
||||
|
||||
// comment 1
|
||||
public class // post-class comment
|
||||
|
||||
// comment2
|
||||
|
||||
MyDemo extends BApplet implements // foo
|
||||
java.lang. // bar
|
||||
Cloneable {
|
||||
|
||||
//argh
|
||||
|
||||
public // foo
|
||||
String // bar
|
||||
fff = /*rheet */ "stuff";
|
||||
|
||||
static /*a*/ {
|
||||
/*foo*/
|
||||
/*bar*/
|
||||
six = 6;
|
||||
} /* b*/
|
||||
|
||||
static /*a*/ final /*b*/ int six;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(200, 200);
|
||||
background(255);
|
||||
|
||||
this . fff = /* ook */ (String)/*foo*/"yo";
|
||||
rectMode(CENTER_DIAMETER); // comment 1a
|
||||
noStroke();
|
||||
fill(255, 204, 0);
|
||||
|
||||
int q = /*a*/ - /*b*/ 1;
|
||||
|
||||
boolean c = /*a*/ ! /*b*/ true;
|
||||
}
|
||||
|
||||
int foo() /*a*/ throws /*b*/ java.lang.Exception /*c*/
|
||||
{
|
||||
int b = 7;
|
||||
switch /*a*/ ( /*b*/ b /*c*/ ) {
|
||||
case /*d*/ 1 /*e*/: /*f*/
|
||||
int c=9;
|
||||
/*g*/
|
||||
break; /*h*/
|
||||
default /*i*/ :
|
||||
int d=9;
|
||||
break;
|
||||
}
|
||||
|
||||
try { /* qq */
|
||||
loop(); /* rr */
|
||||
} catch /*ss*/ (java.lang.Exception ex) /*tt*/ {
|
||||
b = 8; /*tut*/
|
||||
throw /*utu*/ ex;
|
||||
} /*uu*/ finally /*vv*/ {
|
||||
b = 9;
|
||||
} /*ww*/
|
||||
|
||||
b /*aaa*/ = /*bbb*/ true /*ccc*/ ? /*ddd*/ 0 /*eee*/
|
||||
: /* fff*/ 1 /*ggg*/;
|
||||
return /*a*/ 5 /*b*/;
|
||||
}
|
||||
|
||||
// comment 2
|
||||
void loop()
|
||||
{
|
||||
|
||||
int arr1 /* VVV */ [ /* XXX */] /*YYY*/ ;
|
||||
int[] arr2 = { /*a*/ 2, 3 /*b*/ } /*c*/ ;
|
||||
|
||||
for /*a*/ (/*b*/ int j=0 /*c*/; /*d*/ j<2/*e*/ ; /*f*/ j++ /*g*/)
|
||||
/*h*/
|
||||
arr2[1] = 6;
|
||||
|
||||
/*foo*/
|
||||
;
|
||||
/*bar*/
|
||||
rect(width-mouseX, height-mouseY, 50, 50);
|
||||
rect(mouseX, mouseY, 50, 50);
|
||||
|
||||
if (/*a*/ arr2[1] == 6/*b*/) {
|
||||
/*c*/
|
||||
int d=7;
|
||||
} /*d*/else /*e*/{
|
||||
int e=8;
|
||||
/*f*/
|
||||
}
|
||||
|
||||
int f;
|
||||
if (/*aa*/ arr2[1] ==6 /*bb*/ )
|
||||
/*cc*/
|
||||
f=8; /*dd*/
|
||||
else /*ee*/
|
||||
f=10; /*ff*/
|
||||
|
||||
while ( /*aaa*/ f < 15) /*bbb*/ {
|
||||
f ++;
|
||||
} /*ggg*/
|
||||
|
||||
do /* aaaa */ {
|
||||
f++;
|
||||
} /*bbbb*/ while /*cccc*/ ( /*a*/ - /*b*/ 20 > f) /*dddd*/;
|
||||
|
||||
f = 2 * 3 + 4;
|
||||
|
||||
f = ( 2 * 3 ) + 4 + /*aa*/ -/*bb*/1;
|
||||
|
||||
f = 2 * ( 3 + 4 ) ;
|
||||
|
||||
fff = /*a*/ new /*b*/ String(/*c*/"foo"/*d*/) /*e*/;
|
||||
|
||||
int arr3[] = /*a*/ new /*b*/ int/*c*/[/*d*/] /*e*/ {1/*f*/,2};
|
||||
int arr4[][] = new /*a*/int/*b*/[1][2]/*c*/;
|
||||
|
||||
}
|
||||
|
||||
class Shoe
|
||||
{
|
||||
Shoe(String brand)
|
||||
{
|
||||
println(brand);
|
||||
}
|
||||
}
|
||||
|
||||
class NikeAir extends Shoe
|
||||
{
|
||||
NikeAir()
|
||||
{
|
||||
/*a*/ super /*b*/ ( /*c*/ "Nike" /*d*/ ) /*e*/ ;
|
||||
|
||||
/*aa*/ ( /*bb*/ new /*cc*/ MyDemo /*dd*/ (/*ee*/)/*ff*/)/*gg*/./*hh*/super/*ii*/(/*jj*/5/*kk*/);
|
||||
}
|
||||
}
|
||||
}
|
274
app/syntax/CTokenMarker.java
Normal file
274
app/syntax/CTokenMarker.java
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* CTokenMarker.java - C token marker
|
||||
* Copyright (C) 1998, 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* C token marker.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
* @version $Id: CTokenMarker.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class CTokenMarker extends TokenMarker
|
||||
{
|
||||
public CTokenMarker()
|
||||
{
|
||||
this(true,getKeywords());
|
||||
}
|
||||
|
||||
public CTokenMarker(boolean cpp, KeywordMap keywords)
|
||||
{
|
||||
this.cpp = cpp;
|
||||
this.keywords = keywords;
|
||||
}
|
||||
|
||||
public byte markTokensImpl(byte token, Segment line, int lineIndex)
|
||||
{
|
||||
char[] array = line.array;
|
||||
int offset = line.offset;
|
||||
lastOffset = offset;
|
||||
lastKeyword = offset;
|
||||
int mlength = line.count + offset;
|
||||
boolean backslash = false;
|
||||
|
||||
loop: for(int i = offset; i < mlength; i++)
|
||||
{
|
||||
int i1 = (i+1);
|
||||
|
||||
char c = array[i];
|
||||
if(c == '\\')
|
||||
{
|
||||
backslash = !backslash;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case Token.NULL:
|
||||
switch(c)
|
||||
{
|
||||
case '#':
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(cpp)
|
||||
{
|
||||
if(doKeyword(line,i,c))
|
||||
break;
|
||||
addToken(i - lastOffset,token);
|
||||
addToken(mlength - i,Token.KEYWORD2);
|
||||
lastOffset = lastKeyword = mlength;
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
doKeyword(line,i,c);
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else
|
||||
{
|
||||
addToken(i - lastOffset,token);
|
||||
token = Token.LITERAL1;
|
||||
lastOffset = lastKeyword = i;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
doKeyword(line,i,c);
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else
|
||||
{
|
||||
addToken(i - lastOffset,token);
|
||||
token = Token.LITERAL2;
|
||||
lastOffset = lastKeyword = i;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
if(lastKeyword == offset)
|
||||
{
|
||||
if(doKeyword(line,i,c))
|
||||
break;
|
||||
backslash = false;
|
||||
addToken(i1 - lastOffset,Token.LABEL);
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
else if(doKeyword(line,i,c))
|
||||
break;
|
||||
break;
|
||||
case '/':
|
||||
backslash = false;
|
||||
doKeyword(line,i,c);
|
||||
if(mlength - i > 1)
|
||||
{
|
||||
switch(array[i1])
|
||||
{
|
||||
case '*':
|
||||
addToken(i - lastOffset,token);
|
||||
lastOffset = lastKeyword = i;
|
||||
if(mlength - i > 2 && array[i+2] == '*')
|
||||
token = Token.COMMENT2;
|
||||
else
|
||||
token = Token.COMMENT1;
|
||||
break;
|
||||
case '/':
|
||||
addToken(i - lastOffset,token);
|
||||
addToken(mlength - i,Token.COMMENT1);
|
||||
lastOffset = lastKeyword = mlength;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
backslash = false;
|
||||
if(!Character.isLetterOrDigit(c)
|
||||
&& c != '_')
|
||||
doKeyword(line,i,c);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Token.COMMENT1:
|
||||
case Token.COMMENT2:
|
||||
backslash = false;
|
||||
if(c == '*' && mlength - i > 1)
|
||||
{
|
||||
if(array[i1] == '/')
|
||||
{
|
||||
i++;
|
||||
addToken((i+1) - lastOffset,token);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Token.LITERAL1:
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(c == '"')
|
||||
{
|
||||
addToken(i1 - lastOffset,token);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
break;
|
||||
case Token.LITERAL2:
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(c == '\'')
|
||||
{
|
||||
addToken(i1 - lastOffset,Token.LITERAL1);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Invalid state: "
|
||||
+ token);
|
||||
}
|
||||
}
|
||||
|
||||
if(token == Token.NULL)
|
||||
doKeyword(line,mlength,'\0');
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case Token.LITERAL1:
|
||||
case Token.LITERAL2:
|
||||
addToken(mlength - lastOffset,Token.INVALID);
|
||||
token = Token.NULL;
|
||||
break;
|
||||
case Token.KEYWORD2:
|
||||
addToken(mlength - lastOffset,token);
|
||||
if (!backslash) token = Token.NULL;
|
||||
addToken(mlength - lastOffset,token);
|
||||
break;
|
||||
default:
|
||||
addToken(mlength - lastOffset,token);
|
||||
break;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public static KeywordMap getKeywords()
|
||||
{
|
||||
if(cKeywords == null)
|
||||
{
|
||||
cKeywords = new KeywordMap(false);
|
||||
cKeywords.add("char",Token.KEYWORD3);
|
||||
cKeywords.add("double",Token.KEYWORD3);
|
||||
cKeywords.add("enum",Token.KEYWORD3);
|
||||
cKeywords.add("float",Token.KEYWORD3);
|
||||
cKeywords.add("int",Token.KEYWORD3);
|
||||
cKeywords.add("long",Token.KEYWORD3);
|
||||
cKeywords.add("short",Token.KEYWORD3);
|
||||
cKeywords.add("signed",Token.KEYWORD3);
|
||||
cKeywords.add("struct",Token.KEYWORD3);
|
||||
cKeywords.add("typedef",Token.KEYWORD3);
|
||||
cKeywords.add("union",Token.KEYWORD3);
|
||||
cKeywords.add("unsigned",Token.KEYWORD3);
|
||||
cKeywords.add("void",Token.KEYWORD3);
|
||||
cKeywords.add("auto",Token.KEYWORD1);
|
||||
cKeywords.add("const",Token.KEYWORD1);
|
||||
cKeywords.add("extern",Token.KEYWORD1);
|
||||
cKeywords.add("register",Token.KEYWORD1);
|
||||
cKeywords.add("static",Token.KEYWORD1);
|
||||
cKeywords.add("volatile",Token.KEYWORD1);
|
||||
cKeywords.add("break",Token.KEYWORD1);
|
||||
cKeywords.add("case",Token.KEYWORD1);
|
||||
cKeywords.add("continue",Token.KEYWORD1);
|
||||
cKeywords.add("default",Token.KEYWORD1);
|
||||
cKeywords.add("do",Token.KEYWORD1);
|
||||
cKeywords.add("else",Token.KEYWORD1);
|
||||
cKeywords.add("for",Token.KEYWORD1);
|
||||
cKeywords.add("goto",Token.KEYWORD1);
|
||||
cKeywords.add("if",Token.KEYWORD1);
|
||||
cKeywords.add("return",Token.KEYWORD1);
|
||||
cKeywords.add("sizeof",Token.KEYWORD1);
|
||||
cKeywords.add("switch",Token.KEYWORD1);
|
||||
cKeywords.add("while",Token.KEYWORD1);
|
||||
cKeywords.add("asm",Token.KEYWORD2);
|
||||
cKeywords.add("asmlinkage",Token.KEYWORD2);
|
||||
cKeywords.add("far",Token.KEYWORD2);
|
||||
cKeywords.add("huge",Token.KEYWORD2);
|
||||
cKeywords.add("inline",Token.KEYWORD2);
|
||||
cKeywords.add("near",Token.KEYWORD2);
|
||||
cKeywords.add("pascal",Token.KEYWORD2);
|
||||
cKeywords.add("true",Token.LITERAL2);
|
||||
cKeywords.add("false",Token.LITERAL2);
|
||||
cKeywords.add("NULL",Token.LITERAL2);
|
||||
}
|
||||
return cKeywords;
|
||||
}
|
||||
|
||||
// private members
|
||||
private static KeywordMap cKeywords;
|
||||
|
||||
private boolean cpp;
|
||||
private KeywordMap keywords;
|
||||
private int lastOffset;
|
||||
private int lastKeyword;
|
||||
|
||||
private boolean doKeyword(Segment line, int i, char c)
|
||||
{
|
||||
int i1 = i+1;
|
||||
|
||||
int len = i - lastKeyword;
|
||||
byte id = keywords.lookup(line,lastKeyword,len);
|
||||
if(id != Token.NULL)
|
||||
{
|
||||
if(lastKeyword != lastOffset)
|
||||
addToken(lastKeyword - lastOffset,Token.NULL);
|
||||
addToken(len,id);
|
||||
lastOffset = i;
|
||||
}
|
||||
lastKeyword = i1;
|
||||
return false;
|
||||
}
|
||||
}
|
374
app/syntax/DefaultInputHandler.java
Normal file
374
app/syntax/DefaultInputHandler.java
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* DefaultInputHandler.java - Default implementation of an input handler
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
import java.awt.event.*;
|
||||
import java.awt.Toolkit;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* The default input handler. It maps sequences of keystrokes into actions
|
||||
* and inserts key typed events into the text area.
|
||||
* @author Slava Pestov
|
||||
* @version $Id: DefaultInputHandler.java,v 1.2 2005/05/11 08:34:16 benfry Exp $
|
||||
*/
|
||||
public class DefaultInputHandler extends InputHandler
|
||||
{
|
||||
/**
|
||||
* Creates a new input handler with no key bindings defined.
|
||||
*/
|
||||
public DefaultInputHandler()
|
||||
{
|
||||
bindings = currentBindings = new Hashtable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the default key bindings.
|
||||
*/
|
||||
public void addDefaultKeyBindings()
|
||||
{
|
||||
addKeyBinding("BACK_SPACE",BACKSPACE);
|
||||
addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
|
||||
addKeyBinding("DELETE",DELETE);
|
||||
addKeyBinding("C+DELETE",DELETE_WORD);
|
||||
|
||||
addKeyBinding("ENTER",INSERT_BREAK);
|
||||
addKeyBinding("TAB",INSERT_TAB);
|
||||
|
||||
addKeyBinding("INSERT",OVERWRITE);
|
||||
addKeyBinding("C+\\",TOGGLE_RECT);
|
||||
|
||||
addKeyBinding("HOME",HOME);
|
||||
addKeyBinding("END",END);
|
||||
addKeyBinding("S+HOME",SELECT_HOME);
|
||||
addKeyBinding("S+END",SELECT_END);
|
||||
addKeyBinding("C+HOME",DOCUMENT_HOME);
|
||||
addKeyBinding("C+END",DOCUMENT_END);
|
||||
addKeyBinding("CS+HOME",SELECT_DOC_HOME);
|
||||
addKeyBinding("CS+END",SELECT_DOC_END);
|
||||
|
||||
addKeyBinding("PAGE_UP",PREV_PAGE);
|
||||
addKeyBinding("PAGE_DOWN",NEXT_PAGE);
|
||||
addKeyBinding("S+PAGE_UP",SELECT_PREV_PAGE);
|
||||
addKeyBinding("S+PAGE_DOWN",SELECT_NEXT_PAGE);
|
||||
|
||||
addKeyBinding("LEFT",PREV_CHAR);
|
||||
addKeyBinding("S+LEFT",SELECT_PREV_CHAR);
|
||||
addKeyBinding("C+LEFT",PREV_WORD);
|
||||
addKeyBinding("CS+LEFT",SELECT_PREV_WORD);
|
||||
addKeyBinding("RIGHT",NEXT_CHAR);
|
||||
addKeyBinding("S+RIGHT",SELECT_NEXT_CHAR);
|
||||
addKeyBinding("C+RIGHT",NEXT_WORD);
|
||||
addKeyBinding("CS+RIGHT",SELECT_NEXT_WORD);
|
||||
addKeyBinding("UP",PREV_LINE);
|
||||
addKeyBinding("S+UP",SELECT_PREV_LINE);
|
||||
addKeyBinding("DOWN",NEXT_LINE);
|
||||
addKeyBinding("S+DOWN",SELECT_NEXT_LINE);
|
||||
|
||||
addKeyBinding("C+ENTER",REPEAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key binding to this input handler. The key binding is
|
||||
* a list of white space separated key strokes of the form
|
||||
* <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
|
||||
* or S for Shift, and key is either a character (a-z) or a field
|
||||
* name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
|
||||
* @param keyBinding The key binding
|
||||
* @param action The action
|
||||
*/
|
||||
public void addKeyBinding(String keyBinding, ActionListener action)
|
||||
{
|
||||
Hashtable current = bindings;
|
||||
|
||||
StringTokenizer st = new StringTokenizer(keyBinding);
|
||||
while(st.hasMoreTokens())
|
||||
{
|
||||
KeyStroke keyStroke = parseKeyStroke(st.nextToken());
|
||||
if(keyStroke == null)
|
||||
return;
|
||||
|
||||
if(st.hasMoreTokens())
|
||||
{
|
||||
Object o = current.get(keyStroke);
|
||||
if(o instanceof Hashtable)
|
||||
current = (Hashtable)o;
|
||||
else
|
||||
{
|
||||
o = new Hashtable();
|
||||
current.put(keyStroke,o);
|
||||
current = (Hashtable)o;
|
||||
}
|
||||
}
|
||||
else
|
||||
current.put(keyStroke,action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a key binding from this input handler. This is not yet
|
||||
* implemented.
|
||||
* @param keyBinding The key binding
|
||||
*/
|
||||
public void removeKeyBinding(String keyBinding)
|
||||
{
|
||||
throw new InternalError("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all key bindings from this input handler.
|
||||
*/
|
||||
public void removeAllKeyBindings()
|
||||
{
|
||||
bindings.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this input handler that shares the same
|
||||
* key bindings. Setting key bindings in the copy will also
|
||||
* set them in the original.
|
||||
*/
|
||||
public InputHandler copy()
|
||||
{
|
||||
return new DefaultInputHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a key pressed event. This will look up the binding for
|
||||
* the key stroke and execute it.
|
||||
*/
|
||||
public void keyPressed(KeyEvent evt)
|
||||
{
|
||||
int keyCode = evt.getKeyCode();
|
||||
int modifiers = evt.getModifiers();
|
||||
|
||||
// moved this earlier so it doesn't get random meta clicks
|
||||
if (keyCode == KeyEvent.VK_CONTROL ||
|
||||
keyCode == KeyEvent.VK_SHIFT ||
|
||||
keyCode == KeyEvent.VK_ALT ||
|
||||
keyCode == KeyEvent.VK_META) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't get command-s or other menu key equivs on mac
|
||||
// unless it's something that's specifically bound (cmd-left or right)
|
||||
//if ((modifiers & KeyEvent.META_MASK) != 0) return;
|
||||
if ((modifiers & KeyEvent.META_MASK) != 0) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers);
|
||||
if (currentBindings.get(keyStroke) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char keyChar = evt.getKeyChar();
|
||||
System.out.println("code=" + keyCode + " char=" + keyChar +
|
||||
" charint=" + ((int)keyChar));
|
||||
System.out.println("other codes " + KeyEvent.VK_ALT + " " +
|
||||
KeyEvent.VK_META);
|
||||
*/
|
||||
|
||||
if((modifiers & ~KeyEvent.SHIFT_MASK) != 0
|
||||
|| evt.isActionKey()
|
||||
|| keyCode == KeyEvent.VK_BACK_SPACE
|
||||
|| keyCode == KeyEvent.VK_DELETE
|
||||
|| keyCode == KeyEvent.VK_ENTER
|
||||
|| keyCode == KeyEvent.VK_TAB
|
||||
|| keyCode == KeyEvent.VK_ESCAPE)
|
||||
{
|
||||
if(grabAction != null)
|
||||
{
|
||||
handleGrabAction(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
|
||||
modifiers);
|
||||
Object o = currentBindings.get(keyStroke);
|
||||
if(o == null)
|
||||
{
|
||||
// Don't beep if the user presses some
|
||||
// key we don't know about unless a
|
||||
// prefix is active. Otherwise it will
|
||||
// beep when caps lock is pressed, etc.
|
||||
if(currentBindings != bindings)
|
||||
{
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
// F10 should be passed on, but C+e F10
|
||||
// shouldn't
|
||||
repeatCount = 0;
|
||||
repeat = false;
|
||||
evt.consume();
|
||||
}
|
||||
currentBindings = bindings;
|
||||
return;
|
||||
}
|
||||
else if(o instanceof ActionListener)
|
||||
{
|
||||
currentBindings = bindings;
|
||||
|
||||
executeAction(((ActionListener)o),
|
||||
evt.getSource(),null);
|
||||
|
||||
evt.consume();
|
||||
return;
|
||||
}
|
||||
else if(o instanceof Hashtable)
|
||||
{
|
||||
currentBindings = (Hashtable)o;
|
||||
evt.consume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a key typed event. This inserts the key into the text area.
|
||||
*/
|
||||
public void keyTyped(KeyEvent evt)
|
||||
{
|
||||
int modifiers = evt.getModifiers();
|
||||
char c = evt.getKeyChar();
|
||||
|
||||
// this is the apple/cmd key on macosx.. so menu commands
|
||||
// were being passed through as legit keys.. added this line
|
||||
// in an attempt to prevent.
|
||||
if ((modifiers & KeyEvent.META_MASK) != 0) return;
|
||||
|
||||
if (c != KeyEvent.CHAR_UNDEFINED) // &&
|
||||
// (modifiers & KeyEvent.ALT_MASK) == 0)
|
||||
{
|
||||
if(c >= 0x20 && c != 0x7f)
|
||||
{
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(
|
||||
Character.toUpperCase(c));
|
||||
Object o = currentBindings.get(keyStroke);
|
||||
|
||||
if(o instanceof Hashtable)
|
||||
{
|
||||
currentBindings = (Hashtable)o;
|
||||
return;
|
||||
}
|
||||
else if(o instanceof ActionListener)
|
||||
{
|
||||
currentBindings = bindings;
|
||||
executeAction((ActionListener)o,
|
||||
evt.getSource(),
|
||||
String.valueOf(c));
|
||||
return;
|
||||
}
|
||||
|
||||
currentBindings = bindings;
|
||||
|
||||
if(grabAction != null)
|
||||
{
|
||||
handleGrabAction(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
// 0-9 adds another 'digit' to the repeat number
|
||||
if(repeat && Character.isDigit(c))
|
||||
{
|
||||
repeatCount *= 10;
|
||||
repeatCount += (c - '0');
|
||||
return;
|
||||
}
|
||||
|
||||
executeAction(INSERT_CHAR,evt.getSource(),
|
||||
String.valueOf(evt.getKeyChar()));
|
||||
|
||||
repeatCount = 0;
|
||||
repeat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a keystroke. The string should be of the
|
||||
* form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
|
||||
* is any combination of A for Alt, C for Control, S for Shift
|
||||
* or M for Meta, and <i>shortcut</i> is either a single character,
|
||||
* or a keycode name from the <code>KeyEvent</code> class, without
|
||||
* the <code>VK_</code> prefix.
|
||||
* @param keyStroke A string description of the key stroke
|
||||
*/
|
||||
public static KeyStroke parseKeyStroke(String keyStroke)
|
||||
{
|
||||
if(keyStroke == null)
|
||||
return null;
|
||||
int modifiers = 0;
|
||||
int index = keyStroke.indexOf('+');
|
||||
if(index != -1)
|
||||
{
|
||||
for(int i = 0; i < index; i++)
|
||||
{
|
||||
switch(Character.toUpperCase(keyStroke
|
||||
.charAt(i)))
|
||||
{
|
||||
case 'A':
|
||||
modifiers |= InputEvent.ALT_MASK;
|
||||
break;
|
||||
case 'C':
|
||||
modifiers |= InputEvent.CTRL_MASK;
|
||||
break;
|
||||
case 'M':
|
||||
modifiers |= InputEvent.META_MASK;
|
||||
break;
|
||||
case 'S':
|
||||
modifiers |= InputEvent.SHIFT_MASK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String key = keyStroke.substring(index + 1);
|
||||
if(key.length() == 1)
|
||||
{
|
||||
char ch = Character.toUpperCase(key.charAt(0));
|
||||
if(modifiers == 0)
|
||||
return KeyStroke.getKeyStroke(ch);
|
||||
else
|
||||
return KeyStroke.getKeyStroke(ch,modifiers);
|
||||
}
|
||||
else if(key.length() == 0)
|
||||
{
|
||||
System.err.println("Invalid key stroke: " + keyStroke);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int ch;
|
||||
|
||||
try
|
||||
{
|
||||
ch = KeyEvent.class.getField("VK_".concat(key))
|
||||
.getInt(null);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
System.err.println("Invalid key stroke: "
|
||||
+ keyStroke);
|
||||
return null;
|
||||
}
|
||||
|
||||
return KeyStroke.getKeyStroke(ch,modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
// private members
|
||||
private Hashtable bindings;
|
||||
private Hashtable currentBindings;
|
||||
|
||||
private DefaultInputHandler(DefaultInputHandler copy)
|
||||
{
|
||||
bindings = currentBindings = copy.bindings;
|
||||
}
|
||||
}
|
1071
app/syntax/InputHandler.java
Normal file
1071
app/syntax/InputHandler.java
Normal file
File diff suppressed because it is too large
Load Diff
2264
app/syntax/JEditTextArea.java
Normal file
2264
app/syntax/JEditTextArea.java
Normal file
File diff suppressed because it is too large
Load Diff
140
app/syntax/KeywordMap.java
Normal file
140
app/syntax/KeywordMap.java
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* KeywordMap.java - Fast keyword->id map
|
||||
* Copyright (C) 1998, 1999 Slava Pestov
|
||||
* Copyright (C) 1999 Mike Dillon
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
|
||||
* to values. However, the `keys' are Swing segments. This allows lookups of
|
||||
* text substrings without the overhead of creating a new string object.
|
||||
* <p>
|
||||
* This class is used by <code>CTokenMarker</code> to map keywords to ids.
|
||||
*
|
||||
* @author Slava Pestov, Mike Dillon
|
||||
* @version $Id: KeywordMap.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class KeywordMap
|
||||
{
|
||||
/**
|
||||
* Creates a new <code>KeywordMap</code>.
|
||||
* @param ignoreCase True if keys are case insensitive
|
||||
*/
|
||||
public KeywordMap(boolean ignoreCase)
|
||||
{
|
||||
this(ignoreCase, 52);
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>KeywordMap</code>.
|
||||
* @param ignoreCase True if the keys are case insensitive
|
||||
* @param mapLength The number of `buckets' to create.
|
||||
* A value of 52 will give good performance for most maps.
|
||||
*/
|
||||
public KeywordMap(boolean ignoreCase, int mapLength)
|
||||
{
|
||||
this.mapLength = mapLength;
|
||||
this.ignoreCase = ignoreCase;
|
||||
map = new Keyword[mapLength];
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a key.
|
||||
* @param text The text segment
|
||||
* @param offset The offset of the substring within the text segment
|
||||
* @param length The length of the substring
|
||||
*/
|
||||
public byte lookup(Segment text, int offset, int length)
|
||||
{
|
||||
if(length == 0)
|
||||
return Token.NULL;
|
||||
Keyword k = map[getSegmentMapKey(text, offset, length)];
|
||||
while(k != null)
|
||||
{
|
||||
if(length != k.keyword.length)
|
||||
{
|
||||
k = k.next;
|
||||
continue;
|
||||
}
|
||||
if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
|
||||
k.keyword))
|
||||
return k.id;
|
||||
k = k.next;
|
||||
}
|
||||
return Token.NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key-value mapping.
|
||||
* @param keyword The key
|
||||
* @Param id The value
|
||||
*/
|
||||
public void add(String keyword, byte id)
|
||||
{
|
||||
int key = getStringMapKey(keyword);
|
||||
map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the keyword map is set to be case insensitive,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean getIgnoreCase()
|
||||
{
|
||||
return ignoreCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the keyword map should be case insensitive.
|
||||
* @param ignoreCase True if the keyword map should be case
|
||||
* insensitive, false otherwise
|
||||
*/
|
||||
public void setIgnoreCase(boolean ignoreCase)
|
||||
{
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
// protected members
|
||||
protected int mapLength;
|
||||
|
||||
protected int getStringMapKey(String s)
|
||||
{
|
||||
return (Character.toUpperCase(s.charAt(0)) +
|
||||
Character.toUpperCase(s.charAt(s.length()-1)))
|
||||
% mapLength;
|
||||
}
|
||||
|
||||
protected int getSegmentMapKey(Segment s, int off, int len)
|
||||
{
|
||||
return (Character.toUpperCase(s.array[off]) +
|
||||
Character.toUpperCase(s.array[off + len - 1]))
|
||||
% mapLength;
|
||||
}
|
||||
|
||||
// private members
|
||||
class Keyword
|
||||
{
|
||||
public Keyword(char[] keyword, byte id, Keyword next)
|
||||
{
|
||||
this.keyword = keyword;
|
||||
this.id = id;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public char[] keyword;
|
||||
public byte id;
|
||||
public Keyword next;
|
||||
}
|
||||
|
||||
private Keyword[] map;
|
||||
private boolean ignoreCase;
|
||||
}
|
122
app/syntax/PdeKeywords.java
Normal file
122
app/syntax/PdeKeywords.java
Normal file
@ -0,0 +1,122 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PdeKeywords - handles text coloring and links to html reference
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class PdeKeywords extends CTokenMarker {
|
||||
|
||||
// lookup table for the TokenMarker subclass, handles coloring
|
||||
static KeywordMap keywordColoring;
|
||||
|
||||
// lookup table that maps keywords to their html reference pages
|
||||
static Hashtable keywordToReference;
|
||||
|
||||
|
||||
public PdeKeywords() {
|
||||
super(false, getKeywords());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles loading of keywords file.
|
||||
* <P>
|
||||
* Uses getKeywords() method because that's part of the
|
||||
* TokenMarker classes.
|
||||
* <P>
|
||||
* It is recommended that a # sign be used for comments
|
||||
* inside keywords.txt.
|
||||
*/
|
||||
static public KeywordMap getKeywords() {
|
||||
if (keywordColoring == null) {
|
||||
try {
|
||||
keywordColoring = new KeywordMap(false);
|
||||
keywordToReference = new Hashtable();
|
||||
|
||||
InputStream input = Base.getStream("keywords.txt");
|
||||
InputStreamReader isr = new InputStreamReader(input);
|
||||
BufferedReader reader = new BufferedReader(isr);
|
||||
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//System.out.println("line is " + line);
|
||||
// in case there's any garbage on the line
|
||||
//if (line.trim().length() == 0) continue;
|
||||
|
||||
String pieces[] = Base.split(line, '\t');
|
||||
if (pieces.length >= 2) {
|
||||
//int tab = line.indexOf('\t');
|
||||
// any line with no tab is ignored
|
||||
// meaning that a comment is any line without a tab
|
||||
//if (tab == -1) continue;
|
||||
|
||||
String keyword = pieces[0].trim();
|
||||
//String keyword = line.substring(0, tab).trim();
|
||||
//String second = line.substring(tab + 1);
|
||||
//tab = second.indexOf('\t');
|
||||
//String coloring = second.substring(0, tab).trim();
|
||||
//String htmlFilename = second.substring(tab + 1).trim();
|
||||
String coloring = pieces[1].trim();
|
||||
|
||||
if (coloring.length() > 0) {
|
||||
// text will be KEYWORD or LITERAL
|
||||
boolean isKey = (coloring.charAt(0) == 'K');
|
||||
// KEYWORD1 -> 0, KEYWORD2 -> 1, etc
|
||||
int num = coloring.charAt(coloring.length() - 1) - '1';
|
||||
byte id = (byte)
|
||||
((isKey ? Token.KEYWORD1 : Token.LITERAL1) + num);
|
||||
//System.out.println("got " + (isKey ? "keyword" : "literal") +
|
||||
// (num+1) + " for " + keyword);
|
||||
keywordColoring.add(keyword, id);
|
||||
}
|
||||
if (pieces.length >= 3) {
|
||||
String htmlFilename = pieces[2].trim();
|
||||
if (htmlFilename.length() > 0) {
|
||||
keywordToReference.put(keyword, htmlFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
Base.showError("Problem loading keywords",
|
||||
"Could not load keywords.txt,\n" +
|
||||
"please re-install Arduino.", e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return keywordColoring;
|
||||
}
|
||||
|
||||
|
||||
static public String getReference(String keyword) {
|
||||
return (String) keywordToReference.get(keyword);
|
||||
}
|
||||
}
|
162
app/syntax/PdeTextAreaDefaults.java
Normal file
162
app/syntax/PdeTextAreaDefaults.java
Normal file
@ -0,0 +1,162 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PdeTextAreaDefaults - grabs font/color settings for the editor
|
||||
Part of the Processing project - http://Proce55ing.net
|
||||
|
||||
Except where noted, code is written by Ben Fry
|
||||
Copyright (c) 2001-03 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
|
||||
public class PdeTextAreaDefaults extends TextAreaDefaults {
|
||||
|
||||
public PdeTextAreaDefaults() {
|
||||
|
||||
inputHandler = new DefaultInputHandler();
|
||||
inputHandler.addDefaultKeyBindings();
|
||||
|
||||
// use option on mac for things that are ctrl on windows/linux
|
||||
String mod = Base.isMacOS() ? "A" : "C";
|
||||
|
||||
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
|
||||
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
|
||||
|
||||
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
|
||||
inputHandler.addKeyBinding("C+BACK_SPACE", InputHandler.BACKSPACE_WORD);
|
||||
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
|
||||
inputHandler.addKeyBinding("C+DELETE", InputHandler.DELETE_WORD);
|
||||
|
||||
inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
|
||||
inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
|
||||
|
||||
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
|
||||
inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
|
||||
|
||||
// beginning and ending of the current line
|
||||
inputHandler.addKeyBinding("HOME", InputHandler.HOME);
|
||||
inputHandler.addKeyBinding("END", InputHandler.END);
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
|
||||
inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
|
||||
}
|
||||
|
||||
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
|
||||
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
|
||||
inputHandler.addKeyBinding(mod + "+HOME", InputHandler.DOCUMENT_HOME);
|
||||
inputHandler.addKeyBinding(mod + "+END", InputHandler.DOCUMENT_END);
|
||||
inputHandler.addKeyBinding(mod + "S+HOME", InputHandler.SELECT_DOC_HOME);
|
||||
inputHandler.addKeyBinding(mod + "S+END", InputHandler.SELECT_DOC_END);
|
||||
|
||||
inputHandler.addKeyBinding("PAGE_UP", InputHandler.PREV_PAGE);
|
||||
inputHandler.addKeyBinding("PAGE_DOWN", InputHandler.NEXT_PAGE);
|
||||
inputHandler.addKeyBinding("S+PAGE_UP", InputHandler.SELECT_PREV_PAGE);
|
||||
inputHandler.addKeyBinding("S+PAGE_DOWN", InputHandler.SELECT_NEXT_PAGE);
|
||||
|
||||
inputHandler.addKeyBinding("LEFT", InputHandler.PREV_CHAR);
|
||||
inputHandler.addKeyBinding("S+LEFT", InputHandler.SELECT_PREV_CHAR);
|
||||
inputHandler.addKeyBinding(mod + "+LEFT", InputHandler.PREV_WORD);
|
||||
inputHandler.addKeyBinding(mod + "S+LEFT", InputHandler.SELECT_PREV_WORD);
|
||||
inputHandler.addKeyBinding("RIGHT", InputHandler.NEXT_CHAR);
|
||||
inputHandler.addKeyBinding("S+RIGHT", InputHandler.SELECT_NEXT_CHAR);
|
||||
inputHandler.addKeyBinding(mod + "+RIGHT", InputHandler.NEXT_WORD);
|
||||
inputHandler.addKeyBinding(mod + "S+RIGHT", InputHandler.SELECT_NEXT_WORD);
|
||||
inputHandler.addKeyBinding("UP", InputHandler.PREV_LINE);
|
||||
inputHandler.addKeyBinding(mod + "+UP", InputHandler.PREV_LINE); // p5
|
||||
inputHandler.addKeyBinding("S+UP", InputHandler.SELECT_PREV_LINE);
|
||||
inputHandler.addKeyBinding("DOWN", InputHandler.NEXT_LINE);
|
||||
inputHandler.addKeyBinding(mod + "+DOWN", InputHandler.NEXT_LINE); // p5
|
||||
inputHandler.addKeyBinding("S+DOWN", InputHandler.SELECT_NEXT_LINE);
|
||||
|
||||
inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
|
||||
|
||||
document = new SyntaxDocument();
|
||||
editable = true;
|
||||
electricScroll = 3;
|
||||
|
||||
cols = 80;
|
||||
rows = 15;
|
||||
|
||||
|
||||
// moved from SyntaxUtilities
|
||||
//DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
|
||||
|
||||
styles = new SyntaxStyle[Token.ID_COUNT];
|
||||
|
||||
// comments
|
||||
styles[Token.COMMENT1] = Preferences.getStyle("comment1");
|
||||
styles[Token.COMMENT2] = Preferences.getStyle("comment2");
|
||||
|
||||
// abstract, final, private
|
||||
styles[Token.KEYWORD1] = Preferences.getStyle("keyword1");
|
||||
|
||||
// beginShape, point, line
|
||||
styles[Token.KEYWORD2] = Preferences.getStyle("keyword2");
|
||||
|
||||
// byte, char, short, color
|
||||
styles[Token.KEYWORD3] = Preferences.getStyle("keyword3");
|
||||
|
||||
// constants: null, true, this, RGB, TWO_PI
|
||||
styles[Token.LITERAL1] = Preferences.getStyle("literal1");
|
||||
|
||||
// p5 built in variables: mouseX, width, pixels
|
||||
styles[Token.LITERAL2] = Preferences.getStyle("literal2");
|
||||
|
||||
// ??
|
||||
styles[Token.LABEL] = Preferences.getStyle("label");
|
||||
|
||||
// + - = /
|
||||
styles[Token.OPERATOR] = Preferences.getStyle("operator");
|
||||
|
||||
// area that's not in use by the text (replaced with tildes)
|
||||
styles[Token.INVALID] = Preferences.getStyle("invalid");
|
||||
|
||||
|
||||
// moved from TextAreaPainter
|
||||
|
||||
font = Preferences.getFont("editor.font");
|
||||
|
||||
fgcolor = Preferences.getColor("editor.fgcolor");
|
||||
bgcolor = Preferences.getColor("editor.bgcolor");
|
||||
|
||||
caretVisible = true;
|
||||
caretBlinks = Preferences.getBoolean("editor.caret.blink");
|
||||
caretColor = Preferences.getColor("editor.caret.color");
|
||||
|
||||
selectionColor = Preferences.getColor("editor.selection.color");
|
||||
|
||||
lineHighlight =
|
||||
Preferences.getBoolean("editor.linehighlight");
|
||||
lineHighlightColor =
|
||||
Preferences.getColor("editor.linehighlight.color");
|
||||
|
||||
bracketHighlight =
|
||||
Preferences.getBoolean("editor.brackethighlight");
|
||||
bracketHighlightColor =
|
||||
Preferences.getColor("editor.brackethighlight.color");
|
||||
|
||||
eolMarkers = Preferences.getBoolean("editor.eolmarkers");
|
||||
eolMarkerColor = Preferences.getColor("editor.eolmarkers.color");
|
||||
|
||||
paintInvalid = Preferences.getBoolean("editor.invalid");
|
||||
}
|
||||
}
|
166
app/syntax/SyntaxDocument.java
Normal file
166
app/syntax/SyntaxDocument.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* SyntaxDocument.java - Document that can be tokenized
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.UndoableEdit;
|
||||
|
||||
/**
|
||||
* A document implementation that can be tokenized by the syntax highlighting
|
||||
* system.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
* @version $Id: SyntaxDocument.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class SyntaxDocument extends PlainDocument
|
||||
{
|
||||
/**
|
||||
* Returns the token marker that is to be used to split lines
|
||||
* of this document up into tokens. May return null if this
|
||||
* document is not to be colorized.
|
||||
*/
|
||||
public TokenMarker getTokenMarker()
|
||||
{
|
||||
return tokenMarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token marker that is to be used to split lines of
|
||||
* this document up into tokens. May throw an exception if
|
||||
* this is not supported for this type of document.
|
||||
* @param tm The new token marker
|
||||
*/
|
||||
public void setTokenMarker(TokenMarker tm)
|
||||
{
|
||||
tokenMarker = tm;
|
||||
if(tm == null)
|
||||
return;
|
||||
tokenMarker.insertLines(0,getDefaultRootElement()
|
||||
.getElementCount());
|
||||
tokenizeLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparses the document, by passing all lines to the token
|
||||
* marker. This should be called after the document is first
|
||||
* loaded.
|
||||
*/
|
||||
public void tokenizeLines()
|
||||
{
|
||||
tokenizeLines(0,getDefaultRootElement().getElementCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparses the document, by passing the specified lines to the
|
||||
* token marker. This should be called after a large quantity of
|
||||
* text is first inserted.
|
||||
* @param start The first line to parse
|
||||
* @param len The number of lines, after the first one to parse
|
||||
*/
|
||||
public void tokenizeLines(int start, int len)
|
||||
{
|
||||
if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
|
||||
return;
|
||||
|
||||
Segment lineSegment = new Segment();
|
||||
Element map = getDefaultRootElement();
|
||||
|
||||
len += start;
|
||||
|
||||
try
|
||||
{
|
||||
for(int i = start; i < len; i++)
|
||||
{
|
||||
Element lineElement = map.getElement(i);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
getText(lineStart,lineElement.getEndOffset()
|
||||
- lineStart - 1,lineSegment);
|
||||
tokenMarker.markTokens(lineSegment,i);
|
||||
}
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a compound edit that can be undone in one operation.
|
||||
* Subclasses that implement undo should override this method;
|
||||
* this class has no undo functionality so this method is
|
||||
* empty.
|
||||
*/
|
||||
public void beginCompoundEdit() {}
|
||||
|
||||
/**
|
||||
* Ends a compound edit that can be undone in one operation.
|
||||
* Subclasses that implement undo should override this method;
|
||||
* this class has no undo functionality so this method is
|
||||
* empty.
|
||||
*/
|
||||
public void endCompoundEdit() {}
|
||||
|
||||
/**
|
||||
* Adds an undoable edit to this document's undo list. The edit
|
||||
* should be ignored if something is currently being undone.
|
||||
* @param edit The undoable edit
|
||||
*
|
||||
* @since jEdit 2.2pre1
|
||||
*/
|
||||
public void addUndoableEdit(UndoableEdit edit) {}
|
||||
|
||||
// protected members
|
||||
protected TokenMarker tokenMarker;
|
||||
|
||||
/**
|
||||
* We overwrite this method to update the token marker
|
||||
* state immediately so that any event listeners get a
|
||||
* consistent token marker.
|
||||
*/
|
||||
protected void fireInsertUpdate(DocumentEvent evt)
|
||||
{
|
||||
if(tokenMarker != null)
|
||||
{
|
||||
DocumentEvent.ElementChange ch = evt.getChange(
|
||||
getDefaultRootElement());
|
||||
if(ch != null)
|
||||
{
|
||||
tokenMarker.insertLines(ch.getIndex() + 1,
|
||||
ch.getChildrenAdded().length -
|
||||
ch.getChildrenRemoved().length);
|
||||
}
|
||||
}
|
||||
|
||||
super.fireInsertUpdate(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* We overwrite this method to update the token marker
|
||||
* state immediately so that any event listeners get a
|
||||
* consistent token marker.
|
||||
*/
|
||||
protected void fireRemoveUpdate(DocumentEvent evt)
|
||||
{
|
||||
if(tokenMarker != null)
|
||||
{
|
||||
DocumentEvent.ElementChange ch = evt.getChange(
|
||||
getDefaultRootElement());
|
||||
if(ch != null)
|
||||
{
|
||||
tokenMarker.deleteLines(ch.getIndex() + 1,
|
||||
ch.getChildrenRemoved().length -
|
||||
ch.getChildrenAdded().length);
|
||||
}
|
||||
}
|
||||
|
||||
super.fireRemoveUpdate(evt);
|
||||
}
|
||||
}
|
137
app/syntax/SyntaxStyle.java
Normal file
137
app/syntax/SyntaxStyle.java
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* SyntaxStyle.java - A simple text style class
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* A simple text style class. It can specify the color, italic flag,
|
||||
* and bold flag of a run of text.
|
||||
* @author Slava Pestov
|
||||
* @version $Id: SyntaxStyle.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class SyntaxStyle
|
||||
{
|
||||
/**
|
||||
* Creates a new SyntaxStyle.
|
||||
* @param color The text color
|
||||
* @param italic True if the text should be italics
|
||||
* @param bold True if the text should be bold
|
||||
*/
|
||||
public SyntaxStyle(Color color, boolean italic, boolean bold)
|
||||
{
|
||||
this.color = color;
|
||||
this.italic = italic;
|
||||
this.bold = bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color specified in this style.
|
||||
*/
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if no font styles are enabled.
|
||||
*/
|
||||
public boolean isPlain()
|
||||
{
|
||||
return !(bold || italic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if italics is enabled for this style.
|
||||
*/
|
||||
public boolean isItalic()
|
||||
{
|
||||
return italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if boldface is enabled for this style.
|
||||
*/
|
||||
public boolean isBold()
|
||||
{
|
||||
return bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified font, but with the style's bold and
|
||||
* italic flags applied.
|
||||
*/
|
||||
public Font getStyledFont(Font font)
|
||||
{
|
||||
if(font == null)
|
||||
throw new NullPointerException("font param must not"
|
||||
+ " be null");
|
||||
if(font.equals(lastFont))
|
||||
return lastStyledFont;
|
||||
lastFont = font;
|
||||
lastStyledFont = new Font(font.getFamily(),
|
||||
(bold ? Font.BOLD : 0)
|
||||
| (italic ? Font.ITALIC : 0),
|
||||
font.getSize());
|
||||
return lastStyledFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font metrics for the styled font.
|
||||
*/
|
||||
public FontMetrics getFontMetrics(Font font)
|
||||
{
|
||||
if(font == null)
|
||||
throw new NullPointerException("font param must not"
|
||||
+ " be null");
|
||||
if(font.equals(lastFont) && fontMetrics != null)
|
||||
return fontMetrics;
|
||||
lastFont = font;
|
||||
lastStyledFont = new Font(font.getFamily(),
|
||||
(bold ? Font.BOLD : 0)
|
||||
| (italic ? Font.ITALIC : 0),
|
||||
font.getSize());
|
||||
fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(
|
||||
lastStyledFont);
|
||||
return fontMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the foreground color and font of the specified graphics
|
||||
* context to that specified in this style.
|
||||
* @param gfx The graphics context
|
||||
* @param font The font to add the styles to
|
||||
*/
|
||||
public void setGraphicsFlags(Graphics gfx, Font font)
|
||||
{
|
||||
Font _font = getStyledFont(font);
|
||||
gfx.setFont(_font);
|
||||
gfx.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this object.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getName() + "[color=" + color +
|
||||
(italic ? ",italic" : "") +
|
||||
(bold ? ",bold" : "") + "]";
|
||||
}
|
||||
|
||||
// private members
|
||||
private Color color;
|
||||
private boolean italic;
|
||||
private boolean bold;
|
||||
private Font lastFont;
|
||||
private Font lastStyledFont;
|
||||
private FontMetrics fontMetrics;
|
||||
}
|
163
app/syntax/SyntaxUtilities.java
Normal file
163
app/syntax/SyntaxUtilities.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* SyntaxUtilities.java - Utility functions used by syntax colorizing
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.awt.*;
|
||||
|
||||
|
||||
/**
|
||||
* Class with several utility functions used by jEdit's syntax colorizing
|
||||
* subsystem.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
* @version $Id: SyntaxUtilities.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class SyntaxUtilities
|
||||
{
|
||||
/**
|
||||
* Checks if a subregion of a <code>Segment</code> is equal to a
|
||||
* string.
|
||||
* @param ignoreCase True if case should be ignored, false otherwise
|
||||
* @param text The segment
|
||||
* @param offset The offset into the segment
|
||||
* @param match The string to match
|
||||
*/
|
||||
public static boolean regionMatches(boolean ignoreCase, Segment text,
|
||||
int offset, String match)
|
||||
{
|
||||
int length = offset + match.length();
|
||||
char[] textArray = text.array;
|
||||
if(length > text.offset + text.count)
|
||||
return false;
|
||||
for(int i = offset, j = 0; i < length; i++, j++)
|
||||
{
|
||||
char c1 = textArray[i];
|
||||
char c2 = match.charAt(j);
|
||||
if(ignoreCase)
|
||||
{
|
||||
c1 = Character.toUpperCase(c1);
|
||||
c2 = Character.toUpperCase(c2);
|
||||
}
|
||||
if(c1 != c2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a subregion of a <code>Segment</code> is equal to a
|
||||
* character array.
|
||||
* @param ignoreCase True if case should be ignored, false otherwise
|
||||
* @param text The segment
|
||||
* @param offset The offset into the segment
|
||||
* @param match The character array to match
|
||||
*/
|
||||
public static boolean regionMatches(boolean ignoreCase, Segment text,
|
||||
int offset, char[] match)
|
||||
{
|
||||
int length = offset + match.length;
|
||||
char[] textArray = text.array;
|
||||
if(length > text.offset + text.count)
|
||||
return false;
|
||||
for(int i = offset, j = 0; i < length; i++, j++)
|
||||
{
|
||||
char c1 = textArray[i];
|
||||
char c2 = match[j];
|
||||
if(ignoreCase)
|
||||
{
|
||||
c1 = Character.toUpperCase(c1);
|
||||
c2 = Character.toUpperCase(c2);
|
||||
}
|
||||
if(c1 != c2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default style table. This can be passed to the
|
||||
* <code>setStyles()</code> method of <code>SyntaxDocument</code>
|
||||
* to use the default syntax styles.
|
||||
*/
|
||||
public static SyntaxStyle[] getDefaultSyntaxStyles()
|
||||
{
|
||||
SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
|
||||
|
||||
styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false);
|
||||
styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false);
|
||||
styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
|
||||
styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false);
|
||||
styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
|
||||
styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
|
||||
styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
|
||||
styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
|
||||
styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
|
||||
styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Paints the specified line onto the graphics context. Note that this
|
||||
* method munges the offset and count values of the segment.
|
||||
* @param line The line segment
|
||||
* @param tokens The token list for the line
|
||||
* @param styles The syntax style list
|
||||
* @param expander The tab expander used to determine tab stops. May
|
||||
* be null
|
||||
* @param gfx The graphics context
|
||||
* @param x The x co-ordinate
|
||||
* @param y The y co-ordinate
|
||||
* @return The x co-ordinate, plus the width of the painted string
|
||||
*/
|
||||
public static int paintSyntaxLine(Segment line, Token tokens,
|
||||
SyntaxStyle[] styles,
|
||||
TabExpander expander, Graphics gfx,
|
||||
int x, int y)
|
||||
{
|
||||
Font defaultFont = gfx.getFont();
|
||||
Color defaultColor = gfx.getColor();
|
||||
|
||||
int offset = 0;
|
||||
for(;;)
|
||||
{
|
||||
byte id = tokens.id;
|
||||
if(id == Token.END)
|
||||
break;
|
||||
|
||||
int length = tokens.length;
|
||||
if(id == Token.NULL)
|
||||
{
|
||||
if(!defaultColor.equals(gfx.getColor()))
|
||||
gfx.setColor(defaultColor);
|
||||
if(!defaultFont.equals(gfx.getFont()))
|
||||
gfx.setFont(defaultFont);
|
||||
}
|
||||
else
|
||||
styles[id].setGraphicsFlags(gfx,defaultFont);
|
||||
|
||||
line.count = length;
|
||||
x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
|
||||
line.offset += length;
|
||||
offset += length;
|
||||
|
||||
tokens = tokens.next;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// private members
|
||||
private SyntaxUtilities() {}
|
||||
}
|
90
app/syntax/TextAreaDefaults.java
Normal file
90
app/syntax/TextAreaDefaults.java
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* TextAreaDefaults.java - Encapsulates default values for various settings
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import java.awt.*;
|
||||
//import javax.swing.JPopupMenu;
|
||||
|
||||
/**
|
||||
* Encapsulates default settings for a text area. This can be passed
|
||||
* to the constructor once the necessary fields have been filled out.
|
||||
* The advantage of doing this over calling lots of set() methods after
|
||||
* creating the text area is that this method is faster.
|
||||
*/
|
||||
public class TextAreaDefaults
|
||||
{
|
||||
private static TextAreaDefaults DEFAULTS;
|
||||
|
||||
public InputHandler inputHandler;
|
||||
public SyntaxDocument document;
|
||||
public boolean editable;
|
||||
|
||||
public boolean caretVisible;
|
||||
public boolean caretBlinks;
|
||||
public boolean blockCaret;
|
||||
public int electricScroll;
|
||||
|
||||
public int cols;
|
||||
public int rows;
|
||||
public SyntaxStyle[] styles;
|
||||
public Color caretColor;
|
||||
public Color selectionColor;
|
||||
public Color lineHighlightColor;
|
||||
public boolean lineHighlight;
|
||||
public Color bracketHighlightColor;
|
||||
public boolean bracketHighlight;
|
||||
public Color eolMarkerColor;
|
||||
public boolean eolMarkers;
|
||||
public boolean paintInvalid;
|
||||
|
||||
|
||||
// moved from TextAreaPainter [fry]
|
||||
public Font font;
|
||||
public Color fgcolor;
|
||||
public Color bgcolor;
|
||||
|
||||
//public JPopupMenu popup;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new TextAreaDefaults object with the default values filled
|
||||
* in.
|
||||
*/
|
||||
public static TextAreaDefaults getDefaults()
|
||||
{
|
||||
if (DEFAULTS == null) {
|
||||
DEFAULTS = new TextAreaDefaults();
|
||||
|
||||
DEFAULTS.inputHandler = new DefaultInputHandler();
|
||||
DEFAULTS.inputHandler.addDefaultKeyBindings();
|
||||
DEFAULTS.document = new SyntaxDocument();
|
||||
DEFAULTS.editable = true;
|
||||
|
||||
DEFAULTS.caretVisible = true;
|
||||
DEFAULTS.caretBlinks = true;
|
||||
DEFAULTS.electricScroll = 3;
|
||||
|
||||
DEFAULTS.cols = 80;
|
||||
DEFAULTS.rows = 25;
|
||||
DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
|
||||
DEFAULTS.caretColor = Color.red;
|
||||
DEFAULTS.selectionColor = new Color(0xccccff);
|
||||
DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
|
||||
DEFAULTS.lineHighlight = true;
|
||||
DEFAULTS.bracketHighlightColor = Color.black;
|
||||
DEFAULTS.bracketHighlight = true;
|
||||
DEFAULTS.eolMarkerColor = new Color(0x009999);
|
||||
DEFAULTS.eolMarkers = true;
|
||||
DEFAULTS.paintInvalid = true;
|
||||
}
|
||||
|
||||
return DEFAULTS;
|
||||
}
|
||||
}
|
688
app/syntax/TextAreaPainter.java
Normal file
688
app/syntax/TextAreaPainter.java
Normal file
@ -0,0 +1,688 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
* TextAreaPainter.java - Paints the text area
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.JComponent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* The text area repaint manager. It performs double buffering and paints
|
||||
* lines of text.
|
||||
* @author Slava Pestov
|
||||
* @version $Id: TextAreaPainter.java,v 1.3 2005/05/10 01:17:21 benfry Exp $
|
||||
*/
|
||||
public class TextAreaPainter extends JComponent implements TabExpander
|
||||
{
|
||||
/**
|
||||
* Creates a new repaint manager. This should be not be called
|
||||
* directly.
|
||||
*/
|
||||
public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
|
||||
setAutoscrolls(true);
|
||||
setDoubleBuffered(true);
|
||||
setOpaque(true);
|
||||
|
||||
ToolTipManager.sharedInstance().registerComponent(this);
|
||||
|
||||
currentLine = new Segment();
|
||||
currentLineIndex = -1;
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
|
||||
|
||||
setFont(defaults.font);
|
||||
setForeground(defaults.fgcolor);
|
||||
setBackground(defaults.bgcolor);
|
||||
|
||||
blockCaret = defaults.blockCaret;
|
||||
styles = defaults.styles;
|
||||
cols = defaults.cols;
|
||||
rows = defaults.rows;
|
||||
caretColor = defaults.caretColor;
|
||||
selectionColor = defaults.selectionColor;
|
||||
lineHighlightColor = defaults.lineHighlightColor;
|
||||
lineHighlight = defaults.lineHighlight;
|
||||
bracketHighlightColor = defaults.bracketHighlightColor;
|
||||
bracketHighlight = defaults.bracketHighlight;
|
||||
paintInvalid = defaults.paintInvalid;
|
||||
eolMarkerColor = defaults.eolMarkerColor;
|
||||
eolMarkers = defaults.eolMarkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this component can be traversed by pressing the
|
||||
* Tab key. This returns false.
|
||||
*/
|
||||
public final boolean isManagingFocus()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the syntax styles used to paint colorized text. Entry <i>n</i>
|
||||
* will be used to paint tokens with id = <i>n</i>.
|
||||
* @see org.gjt.sp.jedit.syntax.Token
|
||||
*/
|
||||
public final SyntaxStyle[] getStyles()
|
||||
{
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the syntax styles used to paint colorized text. Entry <i>n</i>
|
||||
* will be used to paint tokens with id = <i>n</i>.
|
||||
* @param styles The syntax styles
|
||||
* @see org.gjt.sp.jedit.syntax.Token
|
||||
*/
|
||||
public final void setStyles(SyntaxStyle[] styles)
|
||||
{
|
||||
this.styles = styles;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caret color.
|
||||
*/
|
||||
public final Color getCaretColor()
|
||||
{
|
||||
return caretColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the caret color.
|
||||
* @param caretColor The caret color
|
||||
*/
|
||||
public final void setCaretColor(Color caretColor)
|
||||
{
|
||||
this.caretColor = caretColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection color.
|
||||
*/
|
||||
public final Color getSelectionColor()
|
||||
{
|
||||
return selectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection color.
|
||||
* @param selectionColor The selection color
|
||||
*/
|
||||
public final void setSelectionColor(Color selectionColor)
|
||||
{
|
||||
this.selectionColor = selectionColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line highlight color.
|
||||
*/
|
||||
public final Color getLineHighlightColor()
|
||||
{
|
||||
return lineHighlightColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line highlight color.
|
||||
* @param lineHighlightColor The line highlight color
|
||||
*/
|
||||
public final void setLineHighlightColor(Color lineHighlightColor)
|
||||
{
|
||||
this.lineHighlightColor = lineHighlightColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if line highlight is enabled, false otherwise.
|
||||
*/
|
||||
public final boolean isLineHighlightEnabled()
|
||||
{
|
||||
return lineHighlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables current line highlighting.
|
||||
* @param lineHighlight True if current line highlight
|
||||
* should be enabled, false otherwise
|
||||
*/
|
||||
public final void setLineHighlightEnabled(boolean lineHighlight)
|
||||
{
|
||||
this.lineHighlight = lineHighlight;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bracket highlight color.
|
||||
*/
|
||||
public final Color getBracketHighlightColor()
|
||||
{
|
||||
return bracketHighlightColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bracket highlight color.
|
||||
* @param bracketHighlightColor The bracket highlight color
|
||||
*/
|
||||
public final void setBracketHighlightColor(Color bracketHighlightColor)
|
||||
{
|
||||
this.bracketHighlightColor = bracketHighlightColor;
|
||||
invalidateLine(textArea.getBracketLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if bracket highlighting is enabled, false otherwise.
|
||||
* When bracket highlighting is enabled, the bracket matching the
|
||||
* one before the caret (if any) is highlighted.
|
||||
*/
|
||||
public final boolean isBracketHighlightEnabled()
|
||||
{
|
||||
return bracketHighlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables bracket highlighting.
|
||||
* When bracket highlighting is enabled, the bracket matching the
|
||||
* one before the caret (if any) is highlighted.
|
||||
* @param bracketHighlight True if bracket highlighting should be
|
||||
* enabled, false otherwise
|
||||
*/
|
||||
public final void setBracketHighlightEnabled(boolean bracketHighlight)
|
||||
{
|
||||
this.bracketHighlight = bracketHighlight;
|
||||
invalidateLine(textArea.getBracketLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caret should be drawn as a block, false otherwise.
|
||||
*/
|
||||
public final boolean isBlockCaretEnabled()
|
||||
{
|
||||
return blockCaret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the caret should be drawn as a block, false otherwise.
|
||||
* @param blockCaret True if the caret should be drawn as a block,
|
||||
* false otherwise.
|
||||
*/
|
||||
public final void setBlockCaretEnabled(boolean blockCaret)
|
||||
{
|
||||
this.blockCaret = blockCaret;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EOL marker color.
|
||||
*/
|
||||
public final Color getEOLMarkerColor()
|
||||
{
|
||||
return eolMarkerColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the EOL marker color.
|
||||
* @param eolMarkerColor The EOL marker color
|
||||
*/
|
||||
public final void setEOLMarkerColor(Color eolMarkerColor)
|
||||
{
|
||||
this.eolMarkerColor = eolMarkerColor;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if EOL markers are drawn, false otherwise.
|
||||
*/
|
||||
public final boolean getEOLMarkersPainted()
|
||||
{
|
||||
return eolMarkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if EOL markers are to be drawn.
|
||||
* @param eolMarkers True if EOL markers should be drawn, false otherwise
|
||||
*/
|
||||
public final void setEOLMarkersPainted(boolean eolMarkers)
|
||||
{
|
||||
this.eolMarkers = eolMarkers;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if invalid lines are painted as red tildes (~),
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean getInvalidLinesPainted()
|
||||
{
|
||||
return paintInvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if invalid lines are to be painted as red tildes.
|
||||
* @param paintInvalid True if invalid lines should be drawn, false otherwise
|
||||
*/
|
||||
public void setInvalidLinesPainted(boolean paintInvalid)
|
||||
{
|
||||
this.paintInvalid = paintInvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom highlight painter.
|
||||
* @param highlight The highlight
|
||||
*/
|
||||
public void addCustomHighlight(Highlight highlight)
|
||||
{
|
||||
highlight.init(textArea,highlights);
|
||||
highlights = highlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight interface.
|
||||
*/
|
||||
public interface Highlight
|
||||
{
|
||||
/**
|
||||
* Called after the highlight painter has been added.
|
||||
* @param textArea The text area
|
||||
* @param next The painter this one should delegate to
|
||||
*/
|
||||
void init(JEditTextArea textArea, Highlight next);
|
||||
|
||||
/**
|
||||
* This should paint the highlight and delgate to the
|
||||
* next highlight painter.
|
||||
* @param gfx The graphics context
|
||||
* @param line The line number
|
||||
* @param y The y co-ordinate of the line
|
||||
*/
|
||||
void paintHighlight(Graphics gfx, int line, int y);
|
||||
|
||||
/**
|
||||
* Returns the tool tip to display at the specified
|
||||
* location. If this highlighter doesn't know what to
|
||||
* display, it should delegate to the next highlight
|
||||
* painter.
|
||||
* @param evt The mouse event
|
||||
*/
|
||||
String getToolTipText(MouseEvent evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tool tip to display at the specified location.
|
||||
* @param evt The mouse event
|
||||
*/
|
||||
public String getToolTipText(MouseEvent evt)
|
||||
{
|
||||
if(highlights != null)
|
||||
return highlights.getToolTipText(evt);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font metrics used by this component.
|
||||
*/
|
||||
public FontMetrics getFontMetrics()
|
||||
{
|
||||
return fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font for this component. This is overridden to update the
|
||||
* cached font metrics and to recalculate which lines are visible.
|
||||
* @param font The font
|
||||
*/
|
||||
public void setFont(Font font)
|
||||
{
|
||||
super.setFont(font);
|
||||
fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
|
||||
textArea.recalculateVisibleLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the text.
|
||||
* @param g The graphics context
|
||||
*/
|
||||
public void paint(Graphics gfx)
|
||||
{
|
||||
if (Base.isMacOS()) {
|
||||
Graphics2D g2 = (Graphics2D) gfx;
|
||||
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
}
|
||||
|
||||
tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
|
||||
|
||||
Rectangle clipRect = gfx.getClipBounds();
|
||||
|
||||
gfx.setColor(getBackground());
|
||||
gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
|
||||
|
||||
// We don't use yToLine() here because that method doesn't
|
||||
// return lines past the end of the document
|
||||
int height = fm.getHeight();
|
||||
int firstLine = textArea.getFirstLine();
|
||||
int firstInvalid = firstLine + clipRect.y / height;
|
||||
// Because the clipRect's height is usually an even multiple
|
||||
// of the font height, we subtract 1 from it, otherwise one
|
||||
// too many lines will always be painted.
|
||||
int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
|
||||
|
||||
try {
|
||||
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
|
||||
int x = textArea.getHorizontalOffset();
|
||||
|
||||
for (int line = firstInvalid; line <= lastInvalid; line++) {
|
||||
paintLine(gfx,tokenMarker,line,x);
|
||||
}
|
||||
|
||||
if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
|
||||
int h = clipRect.y + clipRect.height;
|
||||
repaint(0,h,getWidth(),getHeight() - h);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error repainting line"
|
||||
+ " range {" + firstInvalid + ","
|
||||
+ lastInvalid + "}:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a line as needing a repaint.
|
||||
* @param line The line to invalidate
|
||||
*/
|
||||
public final void invalidateLine(int line)
|
||||
{
|
||||
repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
|
||||
getWidth(),fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a range of lines as needing a repaint.
|
||||
* @param firstLine The first line to invalidate
|
||||
* @param lastLine The last line to invalidate
|
||||
*/
|
||||
public final void invalidateLineRange(int firstLine, int lastLine)
|
||||
{
|
||||
repaint(0,textArea.lineToY(firstLine) +
|
||||
fm.getMaxDescent() + fm.getLeading(),
|
||||
getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the lines containing the selection.
|
||||
*/
|
||||
public final void invalidateSelectedLines()
|
||||
{
|
||||
invalidateLineRange(textArea.getSelectionStartLine(),
|
||||
textArea.getSelectionEndLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of TabExpander interface. Returns next tab stop after
|
||||
* a specified point.
|
||||
* @param x The x co-ordinate
|
||||
* @param tabOffset Ignored
|
||||
* @return The next tab stop after <i>x</i>
|
||||
*/
|
||||
public float nextTabStop(float x, int tabOffset)
|
||||
{
|
||||
int offset = textArea.getHorizontalOffset();
|
||||
int ntabs = ((int)x - offset) / tabSize;
|
||||
return (ntabs + 1) * tabSize + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the painter's preferred size.
|
||||
*/
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
Dimension dim = new Dimension();
|
||||
dim.width = fm.charWidth('w') * cols;
|
||||
dim.height = fm.getHeight() * rows;
|
||||
return dim;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the painter's minimum size.
|
||||
*/
|
||||
public Dimension getMinimumSize()
|
||||
{
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
// package-private members
|
||||
int currentLineIndex;
|
||||
Token currentLineTokens;
|
||||
Segment currentLine;
|
||||
|
||||
// protected members
|
||||
protected JEditTextArea textArea;
|
||||
|
||||
protected SyntaxStyle[] styles;
|
||||
protected Color caretColor;
|
||||
protected Color selectionColor;
|
||||
protected Color lineHighlightColor;
|
||||
protected Color bracketHighlightColor;
|
||||
protected Color eolMarkerColor;
|
||||
|
||||
protected boolean blockCaret;
|
||||
protected boolean lineHighlight;
|
||||
protected boolean bracketHighlight;
|
||||
protected boolean paintInvalid;
|
||||
protected boolean eolMarkers;
|
||||
protected int cols;
|
||||
protected int rows;
|
||||
|
||||
protected int tabSize;
|
||||
protected FontMetrics fm;
|
||||
|
||||
protected Highlight highlights;
|
||||
|
||||
protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
|
||||
int line, int x)
|
||||
{
|
||||
Font defaultFont = getFont();
|
||||
Color defaultColor = getForeground();
|
||||
|
||||
currentLineIndex = line;
|
||||
int y = textArea.lineToY(line);
|
||||
|
||||
if (line < 0 || line >= textArea.getLineCount()) {
|
||||
if (paintInvalid) {
|
||||
paintHighlight(gfx,line,y);
|
||||
styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
|
||||
gfx.drawString("~",0,y + fm.getHeight());
|
||||
}
|
||||
} else if(tokenMarker == null) {
|
||||
paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
|
||||
} else {
|
||||
paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
|
||||
defaultColor,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
|
||||
Color defaultColor, int x, int y)
|
||||
{
|
||||
paintHighlight(gfx,line,y);
|
||||
textArea.getLineText(line,currentLine);
|
||||
|
||||
gfx.setFont(defaultFont);
|
||||
gfx.setColor(defaultColor);
|
||||
|
||||
y += fm.getHeight();
|
||||
x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
|
||||
|
||||
if (eolMarkers) {
|
||||
gfx.setColor(eolMarkerColor);
|
||||
gfx.drawString(".",x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
|
||||
int line, Font defaultFont,
|
||||
Color defaultColor, int x, int y)
|
||||
{
|
||||
textArea.getLineText(currentLineIndex,currentLine);
|
||||
currentLineTokens = tokenMarker.markTokens(currentLine,
|
||||
currentLineIndex);
|
||||
|
||||
paintHighlight(gfx,line,y);
|
||||
|
||||
gfx.setFont(defaultFont);
|
||||
gfx.setColor(defaultColor);
|
||||
y += fm.getHeight();
|
||||
x = SyntaxUtilities.paintSyntaxLine(currentLine,
|
||||
currentLineTokens,
|
||||
styles, this, gfx, x, y);
|
||||
|
||||
if (eolMarkers) {
|
||||
gfx.setColor(eolMarkerColor);
|
||||
gfx.drawString(".",x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
if (line >= textArea.getSelectionStartLine()
|
||||
&& line <= textArea.getSelectionEndLine())
|
||||
paintLineHighlight(gfx,line,y);
|
||||
|
||||
if (highlights != null)
|
||||
highlights.paintHighlight(gfx,line,y);
|
||||
|
||||
if (bracketHighlight && line == textArea.getBracketLine())
|
||||
paintBracketHighlight(gfx,line,y);
|
||||
|
||||
if (line == textArea.getCaretLine())
|
||||
paintCaret(gfx,line,y);
|
||||
}
|
||||
|
||||
protected void paintLineHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
int height = fm.getHeight();
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
|
||||
int selectionStart = textArea.getSelectionStart();
|
||||
int selectionEnd = textArea.getSelectionEnd();
|
||||
|
||||
if (selectionStart == selectionEnd) {
|
||||
if (lineHighlight) {
|
||||
gfx.setColor(lineHighlightColor);
|
||||
gfx.fillRect(0,y,getWidth(),height);
|
||||
}
|
||||
} else {
|
||||
gfx.setColor(selectionColor);
|
||||
|
||||
int selectionStartLine = textArea.getSelectionStartLine();
|
||||
int selectionEndLine = textArea.getSelectionEndLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
|
||||
int x1, x2;
|
||||
if (textArea.isSelectionRectangular()) {
|
||||
int lineLen = textArea.getLineLength(line);
|
||||
x1 = textArea._offsetToX(line,Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
|
||||
x2 = textArea._offsetToX(line,Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
|
||||
if (x1 == x2)
|
||||
x2++;
|
||||
} else if(selectionStartLine == selectionEndLine) {
|
||||
x1 = textArea._offsetToX(line, selectionStart - lineStart);
|
||||
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
|
||||
} else if(line == selectionStartLine) {
|
||||
x1 = textArea._offsetToX(line, selectionStart - lineStart);
|
||||
x2 = getWidth();
|
||||
} else if(line == selectionEndLine) {
|
||||
//x1 = 0;
|
||||
// hack from stendahl to avoid doing weird side selection thing
|
||||
x1 = textArea._offsetToX(line, 0);
|
||||
// attempt at getting the gutter too, but doesn't seem to work
|
||||
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
|
||||
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
|
||||
} else {
|
||||
//x1 = 0;
|
||||
// hack from stendahl to avoid doing weird side selection thing
|
||||
x1 = textArea._offsetToX(line, 0);
|
||||
// attempt at getting the gutter too, but doesn't seem to work
|
||||
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
|
||||
x2 = getWidth();
|
||||
}
|
||||
|
||||
// "inlined" min/max()
|
||||
gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
|
||||
(x1 - x2) : (x2 - x1),height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void paintBracketHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
int position = textArea.getBracketPosition();
|
||||
if(position == -1)
|
||||
return;
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int x = textArea._offsetToX(line,position);
|
||||
gfx.setColor(bracketHighlightColor);
|
||||
// Hack!!! Since there is no fast way to get the character
|
||||
// from the bracket matching routine, we use ( since all
|
||||
// brackets probably have the same width anyway
|
||||
gfx.drawRect(x,y,fm.charWidth('(') - 1,
|
||||
fm.getHeight() - 1);
|
||||
}
|
||||
|
||||
protected void paintCaret(Graphics gfx, int line, int y)
|
||||
{
|
||||
//System.out.println("painting caret " + line + " " + y);
|
||||
if (textArea.isCaretVisible()) {
|
||||
//System.out.println("caret is visible");
|
||||
int offset =
|
||||
textArea.getCaretPosition() - textArea.getLineStartOffset(line);
|
||||
int caretX = textArea._offsetToX(line, offset);
|
||||
int caretWidth = ((blockCaret ||
|
||||
textArea.isOverwriteEnabled()) ?
|
||||
fm.charWidth('w') : 1);
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int height = fm.getHeight();
|
||||
|
||||
//System.out.println("caretX, width = " + caretX + " " + caretWidth);
|
||||
|
||||
gfx.setColor(caretColor);
|
||||
|
||||
if (textArea.isOverwriteEnabled()) {
|
||||
gfx.fillRect(caretX,y + height - 1, caretWidth,1);
|
||||
|
||||
} else {
|
||||
// some machines don't like the drawRect for the single
|
||||
// pixel caret.. this caused a lot of hell because on that
|
||||
// minority of machines, the caret wouldn't show up past
|
||||
// the first column. the fix is to use drawLine() in
|
||||
// those cases, as a workaround.
|
||||
if (caretWidth == 1) {
|
||||
gfx.drawLine(caretX, y, caretX, y + height - 1);
|
||||
} else {
|
||||
gfx.drawRect(caretX, y, caretWidth - 1, height - 1);
|
||||
}
|
||||
//gfx.drawRect(caretX, y, caretWidth, height - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
184
app/syntax/TextUtilities.java
Normal file
184
app/syntax/TextUtilities.java
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* TextUtilities.java - Utility functions used by the text area classes
|
||||
* Copyright (C) 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Class with several utility functions used by the text area component.
|
||||
* @author Slava Pestov
|
||||
* @version $Id: TextUtilities.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class TextUtilities
|
||||
{
|
||||
/**
|
||||
* Returns the offset of the bracket matching the one at the
|
||||
* specified offset of the document, or -1 if the bracket is
|
||||
* unmatched (or if the character is not a bracket).
|
||||
* @param doc The document
|
||||
* @param offset The offset
|
||||
* @exception BadLocationException If an out-of-bounds access
|
||||
* was attempted on the document text
|
||||
*/
|
||||
public static int findMatchingBracket(Document doc, int offset)
|
||||
throws BadLocationException
|
||||
{
|
||||
if(doc.getLength() == 0)
|
||||
return -1;
|
||||
char c = doc.getText(offset,1).charAt(0);
|
||||
char cprime; // c` - corresponding character
|
||||
boolean direction; // true = back, false = forward
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '(': cprime = ')'; direction = false; break;
|
||||
case ')': cprime = '('; direction = true; break;
|
||||
case '[': cprime = ']'; direction = false; break;
|
||||
case ']': cprime = '['; direction = true; break;
|
||||
case '{': cprime = '}'; direction = false; break;
|
||||
case '}': cprime = '{'; direction = true; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
int count;
|
||||
|
||||
// How to merge these two cases is left as an exercise
|
||||
// for the reader.
|
||||
|
||||
// Go back or forward
|
||||
if(direction)
|
||||
{
|
||||
// Count is 1 initially because we have already
|
||||
// `found' one closing bracket
|
||||
count = 1;
|
||||
|
||||
// Get text[0,offset-1];
|
||||
String text = doc.getText(0,offset);
|
||||
|
||||
// Scan backwards
|
||||
for(int i = offset - 1; i >= 0; i--)
|
||||
{
|
||||
// If text[i] == c, we have found another
|
||||
// closing bracket, therefore we will need
|
||||
// two opening brackets to complete the
|
||||
// match.
|
||||
char x = text.charAt(i);
|
||||
if(x == c)
|
||||
count++;
|
||||
|
||||
// If text[i] == cprime, we have found a
|
||||
// opening bracket, so we return i if
|
||||
// --count == 0
|
||||
else if(x == cprime)
|
||||
{
|
||||
if(--count == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count is 1 initially because we have already
|
||||
// `found' one opening bracket
|
||||
count = 1;
|
||||
|
||||
// So we don't have to + 1 in every loop
|
||||
offset++;
|
||||
|
||||
// Number of characters to check
|
||||
int len = doc.getLength() - offset;
|
||||
|
||||
// Get text[offset+1,len];
|
||||
String text = doc.getText(offset,len);
|
||||
|
||||
// Scan forwards
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
// If text[i] == c, we have found another
|
||||
// opening bracket, therefore we will need
|
||||
// two closing brackets to complete the
|
||||
// match.
|
||||
char x = text.charAt(i);
|
||||
|
||||
if(x == c)
|
||||
count++;
|
||||
|
||||
// If text[i] == cprime, we have found an
|
||||
// closing bracket, so we return i if
|
||||
// --count == 0
|
||||
else if(x == cprime)
|
||||
{
|
||||
if(--count == 0)
|
||||
return i + offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the start of the word at the specified position.
|
||||
* @param line The text
|
||||
* @param pos The position
|
||||
*/
|
||||
public static int findWordStart(String line, int pos, String noWordSep)
|
||||
{
|
||||
char ch = line.charAt(pos - 1);
|
||||
|
||||
if(noWordSep == null)
|
||||
noWordSep = "";
|
||||
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
|
||||
&& noWordSep.indexOf(ch) == -1);
|
||||
|
||||
int wordStart = 0;
|
||||
for(int i = pos - 1; i >= 0; i--)
|
||||
{
|
||||
ch = line.charAt(i);
|
||||
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
|
||||
noWordSep.indexOf(ch) == -1))
|
||||
{
|
||||
wordStart = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wordStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the end of the word at the specified position.
|
||||
* @param line The text
|
||||
* @param pos The position
|
||||
*/
|
||||
public static int findWordEnd(String line, int pos, String noWordSep)
|
||||
{
|
||||
char ch = line.charAt(pos);
|
||||
|
||||
if(noWordSep == null)
|
||||
noWordSep = "";
|
||||
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
|
||||
&& noWordSep.indexOf(ch) == -1);
|
||||
|
||||
int wordEnd = line.length();
|
||||
for(int i = pos; i < line.length(); i++)
|
||||
{
|
||||
ch = line.charAt(i);
|
||||
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
|
||||
noWordSep.indexOf(ch) == -1))
|
||||
{
|
||||
wordEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return wordEnd;
|
||||
}
|
||||
}
|
149
app/syntax/Token.java
Normal file
149
app/syntax/Token.java
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Token.java - Generic token
|
||||
* Copyright (C) 1998, 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
/**
|
||||
* A linked list of tokens. Each token has three fields - a token
|
||||
* identifier, which is a byte value that can be looked up in the
|
||||
* array returned by <code>SyntaxDocument.getColors()</code>
|
||||
* to get a color value, a length value which is the length of the
|
||||
* token in the text, and a pointer to the next token in the list.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
* @version $Id: Token.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*/
|
||||
public class Token
|
||||
{
|
||||
/**
|
||||
* Normal text token id. This should be used to mark
|
||||
* normal text.
|
||||
*/
|
||||
public static final byte NULL = 0;
|
||||
|
||||
/**
|
||||
* Comment 1 token id. This can be used to mark a comment.
|
||||
*/
|
||||
public static final byte COMMENT1 = 1;
|
||||
|
||||
/**
|
||||
* Comment 2 token id. This can be used to mark a comment.
|
||||
*/
|
||||
public static final byte COMMENT2 = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Literal 1 token id. This can be used to mark a string
|
||||
* literal (eg, C mode uses this to mark "..." literals)
|
||||
*/
|
||||
public static final byte LITERAL1 = 3;
|
||||
|
||||
/**
|
||||
* Literal 2 token id. This can be used to mark an object
|
||||
* literal (eg, Java mode uses this to mark true, false, etc)
|
||||
*/
|
||||
public static final byte LITERAL2 = 4;
|
||||
|
||||
/**
|
||||
* Label token id. This can be used to mark labels
|
||||
* (eg, C mode uses this to mark ...: sequences)
|
||||
*/
|
||||
public static final byte LABEL = 5;
|
||||
|
||||
/**
|
||||
* Keyword 1 token id. This can be used to mark a
|
||||
* keyword. This should be used for general language
|
||||
* constructs.
|
||||
*/
|
||||
public static final byte KEYWORD1 = 6;
|
||||
|
||||
/**
|
||||
* Keyword 2 token id. This can be used to mark a
|
||||
* keyword. This should be used for preprocessor
|
||||
* commands, or variables.
|
||||
*/
|
||||
public static final byte KEYWORD2 = 7;
|
||||
|
||||
/**
|
||||
* Keyword 3 token id. This can be used to mark a
|
||||
* keyword. This should be used for data types.
|
||||
*/
|
||||
public static final byte KEYWORD3 = 8;
|
||||
|
||||
/**
|
||||
* Operator token id. This can be used to mark an
|
||||
* operator. (eg, SQL mode marks +, -, etc with this
|
||||
* token type)
|
||||
*/
|
||||
public static final byte OPERATOR = 9;
|
||||
|
||||
/**
|
||||
* Invalid token id. This can be used to mark invalid
|
||||
* or incomplete tokens, so the user can easily spot
|
||||
* syntax errors.
|
||||
*/
|
||||
public static final byte INVALID = 10;
|
||||
|
||||
/**
|
||||
* The total number of defined token ids.
|
||||
*/
|
||||
public static final byte ID_COUNT = 11;
|
||||
|
||||
/**
|
||||
* The first id that can be used for internal state
|
||||
* in a token marker.
|
||||
*/
|
||||
public static final byte INTERNAL_FIRST = 100;
|
||||
|
||||
/**
|
||||
* The last id that can be used for internal state
|
||||
* in a token marker.
|
||||
*/
|
||||
public static final byte INTERNAL_LAST = 126;
|
||||
|
||||
/**
|
||||
* The token type, that along with a length of 0
|
||||
* marks the end of the token list.
|
||||
*/
|
||||
public static final byte END = 127;
|
||||
|
||||
/**
|
||||
* The length of this token.
|
||||
*/
|
||||
public int length;
|
||||
|
||||
/**
|
||||
* The id of this token.
|
||||
*/
|
||||
public byte id;
|
||||
|
||||
/**
|
||||
* The next token in the linked list.
|
||||
*/
|
||||
public Token next;
|
||||
|
||||
/**
|
||||
* Creates a new token.
|
||||
* @param length The length of the token
|
||||
* @param id The id of the token
|
||||
*/
|
||||
public Token(int length, byte id)
|
||||
{
|
||||
this.length = length;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this token.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "[id=" + id + ",length=" + length + "]";
|
||||
}
|
||||
}
|
345
app/syntax/TokenMarker.java
Normal file
345
app/syntax/TokenMarker.java
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* TokenMarker.java - Generic token marker
|
||||
* Copyright (C) 1998, 1999 Slava Pestov
|
||||
*
|
||||
* You may use and modify this package for any purpose. Redistribution is
|
||||
* permitted, in both source and binary form, provided that this notice
|
||||
* remains intact in all source distributions of this package.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A token marker that splits lines of text into tokens. Each token carries
|
||||
* a length field and an indentification tag that can be mapped to a color
|
||||
* for painting that token.<p>
|
||||
*
|
||||
* For performance reasons, the linked list of tokens is reused after each
|
||||
* line is tokenized. Therefore, the return value of <code>markTokens</code>
|
||||
* should only be used for immediate painting. Notably, it cannot be
|
||||
* cached.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
* @version $Id: TokenMarker.java,v 1.1 2005/04/09 02:30:37 benfry Exp $
|
||||
*
|
||||
* @see org.gjt.sp.jedit.syntax.Token
|
||||
*/
|
||||
public abstract class TokenMarker
|
||||
{
|
||||
/**
|
||||
* A wrapper for the lower-level <code>markTokensImpl</code> method
|
||||
* that is called to split a line up into tokens.
|
||||
* @param line The line
|
||||
* @param lineIndex The line number
|
||||
*/
|
||||
public Token markTokens(Segment line, int lineIndex)
|
||||
{
|
||||
if(lineIndex >= length)
|
||||
{
|
||||
throw new IllegalArgumentException("Tokenizing invalid line: "
|
||||
+ lineIndex);
|
||||
}
|
||||
|
||||
lastToken = null;
|
||||
|
||||
LineInfo info = lineInfo[lineIndex];
|
||||
LineInfo prev;
|
||||
if(lineIndex == 0)
|
||||
prev = null;
|
||||
else
|
||||
prev = lineInfo[lineIndex - 1];
|
||||
|
||||
byte oldToken = info.token;
|
||||
byte token = markTokensImpl(prev == null ?
|
||||
Token.NULL : prev.token,line,lineIndex);
|
||||
|
||||
info.token = token;
|
||||
|
||||
/*
|
||||
* This is a foul hack. It stops nextLineRequested
|
||||
* from being cleared if the same line is marked twice.
|
||||
*
|
||||
* Why is this necessary? It's all JEditTextArea's fault.
|
||||
* When something is inserted into the text, firing a
|
||||
* document event, the insertUpdate() method shifts the
|
||||
* caret (if necessary) by the amount inserted.
|
||||
*
|
||||
* All caret movement is handled by the select() method,
|
||||
* which eventually pipes the new position to scrollTo()
|
||||
* and calls repaint().
|
||||
*
|
||||
* Note that at this point in time, the new line hasn't
|
||||
* yet been painted; the caret is moved first.
|
||||
*
|
||||
* scrollTo() calls offsetToX(), which tokenizes the line
|
||||
* unless it is being called on the last line painted
|
||||
* (in which case it uses the text area's painter cached
|
||||
* token list). What scrollTo() does next is irrelevant.
|
||||
*
|
||||
* After scrollTo() has done it's job, repaint() is
|
||||
* called, and eventually we end up in paintLine(), whose
|
||||
* job is to paint the changed line. It, too, calls
|
||||
* markTokens().
|
||||
*
|
||||
* The problem was that if the line started a multiline
|
||||
* token, the first markTokens() (done in offsetToX())
|
||||
* would set nextLineRequested (because the line end
|
||||
* token had changed) but the second would clear it
|
||||
* (because the line was the same that time) and therefore
|
||||
* paintLine() would never know that it needed to repaint
|
||||
* subsequent lines.
|
||||
*
|
||||
* This bug took me ages to track down, that's why I wrote
|
||||
* all the relevant info down so that others wouldn't
|
||||
* duplicate it.
|
||||
*/
|
||||
if(!(lastLine == lineIndex && nextLineRequested))
|
||||
nextLineRequested = (oldToken != token);
|
||||
|
||||
lastLine = lineIndex;
|
||||
|
||||
addToken(0,Token.END);
|
||||
|
||||
return firstToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract method that splits a line up into tokens. It
|
||||
* should parse the line, and call <code>addToken()</code> to
|
||||
* add syntax tokens to the token list. Then, it should return
|
||||
* the initial token type for the next line.<p>
|
||||
*
|
||||
* For example if the current line contains the start of a
|
||||
* multiline comment that doesn't end on that line, this method
|
||||
* should return the comment token type so that it continues on
|
||||
* the next line.
|
||||
*
|
||||
* @param token The initial token type for this line
|
||||
* @param line The line to be tokenized
|
||||
* @param lineIndex The index of the line in the document,
|
||||
* starting at 0
|
||||
* @return The initial token type for the next line
|
||||
*/
|
||||
protected abstract byte markTokensImpl(byte token, Segment line,
|
||||
int lineIndex);
|
||||
|
||||
/**
|
||||
* Returns if the token marker supports tokens that span multiple
|
||||
* lines. If this is true, the object using this token marker is
|
||||
* required to pass all lines in the document to the
|
||||
* <code>markTokens()</code> method (in turn).<p>
|
||||
*
|
||||
* The default implementation returns true; it should be overridden
|
||||
* to return false on simpler token markers for increased speed.
|
||||
*/
|
||||
public boolean supportsMultilineTokens()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the token marker that lines have been inserted into
|
||||
* the document. This inserts a gap in the <code>lineInfo</code>
|
||||
* array.
|
||||
* @param index The first line number
|
||||
* @param lines The number of lines
|
||||
*/
|
||||
public void insertLines(int index, int lines)
|
||||
{
|
||||
if(lines <= 0)
|
||||
return;
|
||||
length += lines;
|
||||
ensureCapacity(length);
|
||||
int len = index + lines;
|
||||
System.arraycopy(lineInfo,index,lineInfo,len,
|
||||
lineInfo.length - len);
|
||||
|
||||
for(int i = index + lines - 1; i >= index; i--)
|
||||
{
|
||||
lineInfo[i] = new LineInfo();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the token marker that line have been deleted from
|
||||
* the document. This removes the lines in question from the
|
||||
* <code>lineInfo</code> array.
|
||||
* @param index The first line number
|
||||
* @param lines The number of lines
|
||||
*/
|
||||
public void deleteLines(int index, int lines)
|
||||
{
|
||||
if (lines <= 0)
|
||||
return;
|
||||
int len = index + lines;
|
||||
length -= lines;
|
||||
System.arraycopy(lineInfo,len,lineInfo,
|
||||
index,lineInfo.length - len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines in this token marker.
|
||||
*/
|
||||
public int getLineCount()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the next line should be repainted. This
|
||||
* will return true after a line has been tokenized that starts
|
||||
* a multiline token that continues onto the next line.
|
||||
*/
|
||||
public boolean isNextLineRequested()
|
||||
{
|
||||
return nextLineRequested;
|
||||
}
|
||||
|
||||
// protected members
|
||||
|
||||
/**
|
||||
* The first token in the list. This should be used as the return
|
||||
* value from <code>markTokens()</code>.
|
||||
*/
|
||||
protected Token firstToken;
|
||||
|
||||
/**
|
||||
* The last token in the list. New tokens are added here.
|
||||
* This should be set to null before a new line is to be tokenized.
|
||||
*/
|
||||
protected Token lastToken;
|
||||
|
||||
/**
|
||||
* An array for storing information about lines. It is enlarged and
|
||||
* shrunk automatically by the <code>insertLines()</code> and
|
||||
* <code>deleteLines()</code> methods.
|
||||
*/
|
||||
protected LineInfo[] lineInfo;
|
||||
|
||||
/**
|
||||
* The number of lines in the model being tokenized. This can be
|
||||
* less than the length of the <code>lineInfo</code> array.
|
||||
*/
|
||||
protected int length;
|
||||
|
||||
/**
|
||||
* The last tokenized line.
|
||||
*/
|
||||
protected int lastLine;
|
||||
|
||||
/**
|
||||
* True if the next line should be painted.
|
||||
*/
|
||||
protected boolean nextLineRequested;
|
||||
|
||||
/**
|
||||
* Creates a new <code>TokenMarker</code>. This DOES NOT create
|
||||
* a lineInfo array; an initial call to <code>insertLines()</code>
|
||||
* does that.
|
||||
*/
|
||||
protected TokenMarker()
|
||||
{
|
||||
lastLine = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the <code>lineInfo</code> array can contain the
|
||||
* specified index. This enlarges it if necessary. No action is
|
||||
* taken if the array is large enough already.<p>
|
||||
*
|
||||
* It should be unnecessary to call this under normal
|
||||
* circumstances; <code>insertLine()</code> should take care of
|
||||
* enlarging the line info array automatically.
|
||||
*
|
||||
* @param index The array index
|
||||
*/
|
||||
protected void ensureCapacity(int index)
|
||||
{
|
||||
if(lineInfo == null)
|
||||
lineInfo = new LineInfo[index + 1];
|
||||
else if(lineInfo.length <= index)
|
||||
{
|
||||
LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
|
||||
System.arraycopy(lineInfo,0,lineInfoN,0,
|
||||
lineInfo.length);
|
||||
lineInfo = lineInfoN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a token to the token list.
|
||||
* @param length The length of the token
|
||||
* @param id The id of the token
|
||||
*/
|
||||
protected void addToken(int length, byte id)
|
||||
{
|
||||
if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
|
||||
throw new InternalError("Invalid id: " + id);
|
||||
|
||||
if(length == 0 && id != Token.END)
|
||||
return;
|
||||
|
||||
if(firstToken == null)
|
||||
{
|
||||
firstToken = new Token(length,id);
|
||||
lastToken = firstToken;
|
||||
}
|
||||
else if(lastToken == null)
|
||||
{
|
||||
lastToken = firstToken;
|
||||
firstToken.length = length;
|
||||
firstToken.id = id;
|
||||
}
|
||||
else if(lastToken.next == null)
|
||||
{
|
||||
lastToken.next = new Token(length,id);
|
||||
lastToken = lastToken.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastToken = lastToken.next;
|
||||
lastToken.length = length;
|
||||
lastToken.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class for storing information about tokenized lines.
|
||||
*/
|
||||
public class LineInfo
|
||||
{
|
||||
/**
|
||||
* Creates a new LineInfo object with token = Token.NULL
|
||||
* and obj = null.
|
||||
*/
|
||||
public LineInfo()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LineInfo object with the specified
|
||||
* parameters.
|
||||
*/
|
||||
public LineInfo(byte token, Object obj)
|
||||
{
|
||||
this.token = token;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id of the last token of the line.
|
||||
*/
|
||||
public byte token;
|
||||
|
||||
/**
|
||||
* This is for use by the token marker implementations
|
||||
* themselves. It can be used to store anything that
|
||||
* is an object and that needs to exist on a per-line
|
||||
* basis.
|
||||
*/
|
||||
public Object obj;
|
||||
}
|
||||
}
|
46
app/syntax/readme.txt
Normal file
46
app/syntax/readme.txt
Normal file
@ -0,0 +1,46 @@
|
||||
OLDSYNTAX PACKAGE README
|
||||
|
||||
I am placing the jEdit 2.2.1 syntax highlighting package in the public
|
||||
domain. This means it can be integrated into commercial programs, etc.
|
||||
|
||||
This package requires at least Java 1.1 and Swing 1.1. Syntax
|
||||
highlighting for the following file types is supported:
|
||||
|
||||
- C++, C
|
||||
- CORBA IDL
|
||||
- Eiffel
|
||||
- HTML
|
||||
- Java
|
||||
- Java properties
|
||||
- JavaScript
|
||||
- MS-DOS INI
|
||||
- MS-DOS batch files
|
||||
- Makefile
|
||||
- PHP
|
||||
- Perl
|
||||
- Python
|
||||
- TeX
|
||||
- Transact-SQL
|
||||
- Unix patch/diff
|
||||
- Unix shell script
|
||||
- XML
|
||||
|
||||
This package is undocumented; read the source (start by taking a look at
|
||||
JEditTextArea.java) to find out how to use it; it's really simple. Feel
|
||||
free to e-mail questions, queries, etc. to me, but keep in mind that
|
||||
this code is very old and I no longer maintain it. So if you find a bug,
|
||||
don't bother me about it; fix it yourself.
|
||||
|
||||
* Copyright
|
||||
|
||||
The jEdit 2.2.1 syntax highlighting package contains code that is
|
||||
Copyright 1998-1999 Slava Pestov, Artur Biesiadowski, Clancy Malcolm,
|
||||
Jonathan Revusky, Juha Lindfors and Mike Dillon.
|
||||
|
||||
You may use and modify this package for any purpose. Redistribution is
|
||||
permitted, in both source and binary form, provided that this notice
|
||||
remains intact in all source distributions of this package.
|
||||
|
||||
-- Slava Pestov
|
||||
25 September 2000
|
||||
<sp@gjt.org>
|
1011
app/tools/AutoFormat.java
Normal file
1011
app/tools/AutoFormat.java
Normal file
File diff suppressed because it is too large
Load Diff
168
build/howto.txt
Executable file
168
build/howto.txt
Executable file
@ -0,0 +1,168 @@
|
||||
HOW TO BUILD PROCESSING ON YOUR FAVORITE PLATFORM
|
||||
|
||||
With frequently asked questions, scroll to the end of the file.
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// Steps for First Time Setup
|
||||
|
||||
|
||||
1. INSTALL DEVELOPMENT TOOLS
|
||||
|
||||
1a. On Windows, install Cygwin. It's downloadable from
|
||||
www.cygwin.com or specifically: www.cygwin.com/setup.exe
|
||||
|
||||
** of the packages, begin with the defaults, and add:
|
||||
|
||||
+ cvs - used for version control
|
||||
|
||||
+ make, gcc-mingw, and g++ - used to build processing.exe
|
||||
(this will also pull in gcc-core)
|
||||
|
||||
+ perl - use this version, activestate or other distros have trouble
|
||||
|
||||
+ unzip, zip - for dealing with archives
|
||||
|
||||
+ included in the defaults, but make sure:
|
||||
coreutils (or textutils), gzip, tar
|
||||
|
||||
+ not required but useful:
|
||||
openssh - command line ssh client
|
||||
nano - handy/simple text editor
|
||||
|
||||
** and be sure to leave the option selected for 'unix line endings'
|
||||
|
||||
the cygwin installer is sometimes a little flakey, so it may take more
|
||||
than one try to get everything in there. in fact, it's often best to
|
||||
run the installer once, and let it install all its defaults, then run
|
||||
it again, and select the items above. it's also useful to run the
|
||||
installer every few months to keep things fresh.
|
||||
|
||||
|
||||
1b. On Mac OS X, install Apple's Developer Tools. Should work with
|
||||
everything from the December 2002 Tools for Jaguar on OS X 10.2,
|
||||
up through the more recent Xcode stuff.
|
||||
|
||||
|
||||
1c. On Linux, you're pretty much on your own.. You need a pretty
|
||||
standard development setup.
|
||||
|
||||
|
||||
2. GRAB THE CODE FROM SOURCEFORGE
|
||||
|
||||
* this grabs the code as an anonymous user. if you have a sourceforge
|
||||
account, you should know how to grab the code as yourself.
|
||||
|
||||
# first do this
|
||||
cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing login
|
||||
# just hit enter when it asks for a password
|
||||
|
||||
# then do this (may take a while)
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing co processing
|
||||
# (maybe even a long while for you dialup and international folks)
|
||||
|
||||
# gonna do a few things in the p5 folder
|
||||
cd processing
|
||||
|
||||
# a quick cleanup, removes empty (dead/old) folders
|
||||
cvs update -P
|
||||
|
||||
# get back to the processing/ folder
|
||||
cd ..
|
||||
|
||||
|
||||
3. INSTALL QUICKTIME FOR JAVA (windows users only)
|
||||
|
||||
* you'll also need to install quicktime for java. grab a quicktime
|
||||
installer from: http://www.apple.com/quicktime/download/
|
||||
don't try to be sly & use the itunes installer. we all love itunes
|
||||
but it doesn't include quicktime for java by default. or if you were
|
||||
sly, you might need to read the point below about using the updater:
|
||||
|
||||
* if you already have quicktime installed, just make sure that
|
||||
quicktime for java has already been installed, use the quicktime
|
||||
updater (Program Files -> QuickTime -> QuickTime Updater) hit the
|
||||
'Details' button in the updater, and if it lists "Not installed"
|
||||
for "QuickTime for Java", well, take care of that.
|
||||
|
||||
|
||||
4. BUILD IT
|
||||
|
||||
# now to build for the first time:
|
||||
cd /path/to/processing/build/windows
|
||||
|
||||
# or if you're on linux
|
||||
cd /path/to/processing/build/linux
|
||||
|
||||
# for the followers of goatee man
|
||||
cd /path/to/processing/build/macosx
|
||||
|
||||
# and then..
|
||||
./make.sh
|
||||
|
||||
# if everything went well, you'll have no errors. (feel free to make
|
||||
# suggestions for things to include here for common problems)
|
||||
|
||||
# then to run it
|
||||
./run.sh
|
||||
|
||||
# each time you make a change, use make to build the thing
|
||||
# and run to get it up and running.
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// Updating to the Latest Version
|
||||
|
||||
|
||||
5a. Each time you want to update to latest version from cvs:
|
||||
|
||||
cd /path/to/processing
|
||||
cvs -z3 update
|
||||
# -z3 means make it snappy (using compression)
|
||||
|
||||
|
||||
5b. If new folders have been added, or you're gettin odd errors, use:
|
||||
|
||||
# get to the processing folder
|
||||
cd /path/to/processing
|
||||
|
||||
# remove the work directory
|
||||
rm -rf work
|
||||
|
||||
# -d grabs new directories and -P cleans out old (empty) ones
|
||||
# cvs is a little brain dead about this stuff
|
||||
cvs -z3 update -d -P
|
||||
|
||||
Unfortunately there isn't a way to know (?) if new folders have
|
||||
since been added. but if you're getting "class not found" errors
|
||||
while building, then that's a good indicator that something is
|
||||
missing from a subfolder.
|
||||
|
||||
If there have been significant changes, or you get weird build
|
||||
errors, try deleting your 'work' folder. This will create a
|
||||
fresh build. This includes any changes to the reference,
|
||||
the examples, the libraries, jikes, or just about any time you
|
||||
have to use -d -P with the update.
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// Frequently Asked Questions
|
||||
|
||||
- What about eclipse? What about ant? The command line is frightening
|
||||
and gives me nightmares!
|
||||
|
||||
In a basic sense, the command line stuff isn't as scary as it might
|
||||
seem. Hopefully it's just a matter of following the instructions
|
||||
above (and being patient). If not, let us know where you have trouble
|
||||
so we can fix things.
|
||||
|
||||
Conceivably, it wouldn't take much to make Processing build under
|
||||
Eclipse or any other IDE, but we don't do it by default. Same goes for
|
||||
ANT. We don't use it, but if someone were to make build scripts that
|
||||
emulated everything that the current build scripts do (not just build
|
||||
the code, but all the other annoying crap that the build scripts do)
|
||||
then maybe we could switch to it. It's all about reaching some kind
|
||||
of critical mass.
|
5
build/linux/.cvsignore
Normal file
5
build/linux/.cvsignore
Normal file
@ -0,0 +1,5 @@
|
||||
work
|
||||
processing*
|
||||
|
||||
|
||||
|
6
build/linux/CVS/Entries
Normal file
6
build/linux/CVS/Entries
Normal file
@ -0,0 +1,6 @@
|
||||
/.cvsignore/1.3/Mon Jul 29 06:07:10 2002//
|
||||
D/dist////
|
||||
/run.sh/1.1/Wed Aug 6 02:42:46 2003//
|
||||
/dist.sh/1.22/Tue Jun 7 13:00:22 2005//
|
||||
/jre.tgz/1.4/Tue Jun 7 13:05:29 2005/-kb/
|
||||
/make.sh/1.39/Tue Jun 7 13:05:30 2005//
|
1
build/linux/CVS/Repository
Normal file
1
build/linux/CVS/Repository
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/linux
|
1
build/linux/CVS/Root
Normal file
1
build/linux/CVS/Root
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
72
build/linux/dist.sh
Executable file
72
build/linux/dist.sh
Executable file
@ -0,0 +1,72 @@
|
||||
#!/bin/sh
|
||||
|
||||
REVISION=`head -c 4 ../../todo.txt`
|
||||
|
||||
./make.sh
|
||||
|
||||
echo Creating linux distribution for revision $REVISION...
|
||||
|
||||
# remove any old boogers
|
||||
rm -rf processing
|
||||
rm -rf processing-*
|
||||
|
||||
# use 'shared' files as starting point
|
||||
cp -r ../shared processing
|
||||
|
||||
# add the libraries folder with source
|
||||
cp -r ../../net processing/libraries/
|
||||
cp -r ../../opengl processing/libraries/
|
||||
cp -r ../../serial processing/libraries/
|
||||
|
||||
# new style examples thing ala reas
|
||||
cd processing
|
||||
unzip -q examples.zip
|
||||
rm examples.zip
|
||||
cd ..
|
||||
|
||||
cd processing
|
||||
unzip -q reference.zip
|
||||
rm reference.zip
|
||||
cd ..
|
||||
|
||||
# add java (jre) files
|
||||
#tar --extract --verbose --file=jre.tgz --ungzip --directory=processing
|
||||
tar --extract --file=jre.tgz --ungzip --directory=processing
|
||||
|
||||
# directories used by the app
|
||||
#mkdir processing/lib/build
|
||||
|
||||
# grab pde.jar and export from the working dir
|
||||
cp work/lib/pde.jar processing/lib/
|
||||
cp work/lib/core.jar processing/lib/
|
||||
|
||||
# get platform-specific goodies from the dist dir
|
||||
install -m 755 dist/processing processing/processing
|
||||
cp dist/jikes processing/
|
||||
chmod +x processing/jikes
|
||||
|
||||
# make sure notes.txt is unix LFs
|
||||
# the 2> is because the app is a little chatty
|
||||
dos2unix processing/revisions.txt 2> /dev/null
|
||||
dos2unix processing/lib/preferences.txt 2> /dev/null
|
||||
|
||||
# remove boogers
|
||||
find processing -name "*~" -exec rm -f {} ';'
|
||||
find processing -name ".DS_Store" -exec rm -f {} ';'
|
||||
find processing -name "._*" -exec rm -f {} ';'
|
||||
find processing -name "Thumbs.db" -exec rm -f {} ';'
|
||||
|
||||
# clean out the cvs entries
|
||||
find processing -name "CVS" -exec rm -rf {} ';' 2> /dev/null
|
||||
#find processing -name "CVS" -exec echo {} ';'
|
||||
|
||||
# zip it all up for release
|
||||
echo Creating tarball and finishing...
|
||||
P5=processing-$REVISION
|
||||
mv processing $P5
|
||||
|
||||
tar cfz $P5.tgz $P5
|
||||
# nah, keep the new directory around
|
||||
#rm -rf $P5
|
||||
|
||||
#echo Done.
|
0
build/linux/dist/.cvsignore
vendored
Normal file
0
build/linux/dist/.cvsignore
vendored
Normal file
4
build/linux/dist/CVS/Entries
vendored
Normal file
4
build/linux/dist/CVS/Entries
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/.cvsignore/1.1/Thu Jul 25 19:51:59 2002//
|
||||
D/lib////
|
||||
/jikes/1.6/Tue Jun 7 13:05:39 2005/-kb/
|
||||
/processing/1.7/Tue Jun 7 13:05:39 2005//
|
1
build/linux/dist/CVS/Repository
vendored
Normal file
1
build/linux/dist/CVS/Repository
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/linux/dist
|
1
build/linux/dist/CVS/Root
vendored
Normal file
1
build/linux/dist/CVS/Root
vendored
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
BIN
build/linux/dist/jikes
vendored
Executable file
BIN
build/linux/dist/jikes
vendored
Executable file
Binary file not shown.
1
build/linux/dist/lib/CVS/Entries
vendored
Normal file
1
build/linux/dist/lib/CVS/Entries
vendored
Normal file
@ -0,0 +1 @@
|
||||
D
|
1
build/linux/dist/lib/CVS/Repository
vendored
Normal file
1
build/linux/dist/lib/CVS/Repository
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/linux/dist/lib
|
1
build/linux/dist/lib/CVS/Root
vendored
Normal file
1
build/linux/dist/lib/CVS/Root
vendored
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
47
build/linux/dist/processing
vendored
Executable file
47
build/linux/dist/processing
vendored
Executable file
@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
|
||||
CLASSPATH=java/lib/rt.jar:lib:lib/build:lib/pde.jar:lib/core.jar:lib/antlr.jar:lib/oro.jar:lib/registry.jar:lib/mrj.jar
|
||||
export CLASSPATH
|
||||
|
||||
# put the directory where this file lives in the front of the path, because
|
||||
# that directory also contains jikes, which we will need at runtime.
|
||||
#
|
||||
PATH=`pwd`/`dirname $0`:`pwd`/java/bin:${PATH}
|
||||
export PATH
|
||||
|
||||
# test to see if jikes is operable. i'm a crappy bash scripter
|
||||
# so if someone knows a more elegant way to do this, let me know.
|
||||
#
|
||||
jikes -version 1> /dev/null 2> /dev/null
|
||||
if [ $? == 0 ]
|
||||
then
|
||||
java processing.app.Base
|
||||
else
|
||||
echo
|
||||
echo It appears that the version of Jikes distributed with Processing
|
||||
echo cannot properly run on this system.
|
||||
echo
|
||||
echo Possible solutions:
|
||||
echo
|
||||
echo + If you already have Jikes installed on your system, you may
|
||||
echo just need to remove the version that is included with Processing.
|
||||
echo
|
||||
echo + You probably just need to track down a version of Jikes that will
|
||||
echo work with your distribution.
|
||||
echo
|
||||
echo + You may need to install the rpm/package for compat-libstdc++
|
||||
echo This is what it takes to get things running on most versions
|
||||
echo of RedHat Linux or Fedora Core.
|
||||
echo
|
||||
echo + If all else fails, or if you just like building stuff yourself,
|
||||
echo you can download the source for Jikes from SourceForge:
|
||||
echo http://sourceforge.net/project/showfiles.php?group_id=128803
|
||||
echo And it just takes a simple ./configure and make, followed by
|
||||
echo copying src/jikes to the processing-XXXX folder and you should
|
||||
echo be all set.
|
||||
echo
|
||||
echo If you get stuck, ask questions online from the helpful folks via
|
||||
echo the Processing discussion board: http://processing.org/discourse/
|
||||
echo
|
||||
echo Good luck!
|
||||
fi
|
159
build/linux/make.sh
Executable file
159
build/linux/make.sh
Executable file
@ -0,0 +1,159 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
### -- SETUP WORK DIR -------------------------------------------
|
||||
|
||||
if test -d work
|
||||
then
|
||||
BUILD_PREPROC=false
|
||||
else
|
||||
echo Setting up directories to build for linux...
|
||||
BUILD_PREPROC=true
|
||||
cp -r ../shared work
|
||||
|
||||
# needs to make the dir because of packaging goofiness
|
||||
mkdir -p work/classes/processing/app/preproc
|
||||
mkdir -p work/classes/processing/app/syntax
|
||||
mkdir -p work/classes/processing/app/tools
|
||||
|
||||
#cp -r ../../lib work/libraries
|
||||
cp -r ../../net work/libraries/
|
||||
cp -r ../../opengl work/libraries/
|
||||
cp -r ../../serial work/libraries/
|
||||
cp -r ../../video work/libraries/
|
||||
|
||||
cd work
|
||||
unzip -q examples.zip
|
||||
rm examples.zip
|
||||
cd ..
|
||||
|
||||
cd work
|
||||
unzip -q reference.zip
|
||||
rm reference.zip
|
||||
cd ..
|
||||
|
||||
tar --extract --file=jre.tgz --ungzip --directory=work
|
||||
|
||||
#mkdir work/lib/export
|
||||
mkdir work/lib/build
|
||||
#mkdir work/classes
|
||||
|
||||
# get the serial stuff
|
||||
#echo Copying serial support from bagel dir
|
||||
#cp ../../bagel/serial/RXTXcomm.jar work/lib/
|
||||
#mkdir work/lib/i386
|
||||
#cp ../../bagel/serial/librxtxSerial.so work/lib/i386/libSerial.so
|
||||
#chmod +x work/librxtxSerial.so
|
||||
|
||||
# get jikes and depedencies
|
||||
cp dist/jikes work/
|
||||
chmod +x work/jikes
|
||||
|
||||
install -m 755 dist/processing work/processing
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
|
||||
|
||||
### -- BUILD CORE ----------------------------------------------
|
||||
|
||||
|
||||
echo Building processing.core
|
||||
|
||||
# move to bagel inside base 'processing' directory
|
||||
cd core
|
||||
|
||||
# new regular version
|
||||
CLASSPATH="../build/linux/work/java/lib/rt.jar"
|
||||
export CLASSPATH
|
||||
|
||||
perl preproc.pl
|
||||
../build/linux/work/jikes -d . +D -target 1.1 *.java
|
||||
zip -rq ../build/linux/work/lib/core.jar processing
|
||||
rm -rf processing
|
||||
|
||||
|
||||
# back to base processing dir
|
||||
cd ..
|
||||
|
||||
|
||||
### -- BUILD PREPROC ------------------------------------------------
|
||||
|
||||
echo Building PDE for JDK 1.3
|
||||
|
||||
cd app/preproc
|
||||
|
||||
# first build the default java goop
|
||||
# long path is to avoid requiring java to be in your PATH
|
||||
|
||||
../../build/linux/work/java/bin/java \
|
||||
-cp ../../build/linux/work/lib/antlr.jar antlr.Tool java.g
|
||||
|
||||
# now build the pde stuff that extends the java classes
|
||||
../../build/linux/work/java/bin/java \
|
||||
-cp ../../build/linux/work/lib/antlr.jar antlr.Tool -glib java.g pde.g
|
||||
|
||||
cd ../..
|
||||
|
||||
|
||||
### -- BUILD PDE ------------------------------------------------
|
||||
|
||||
cd app
|
||||
|
||||
CLASSPATH="../build/linux/work/lib/core.jar:../build/linux/work/lib/mrj.jar:../build/linux/work/lib/antlr.jar:../build/linux/work/lib/oro.jar:../build/linux/work/lib/registry.jar:../build/linux/work/java/lib/rt.jar"
|
||||
|
||||
../build/linux/work/jikes -target 1.3 +D -classpath $CLASSPATH:../build/linux/work/classes -d ../build/linux/work/classes *.java preproc/*.java syntax/*.java tools/*.java
|
||||
|
||||
cd ../build/linux/work/classes
|
||||
rm -f ../lib/pde.jar
|
||||
zip -0rq ../lib/pde.jar .
|
||||
cd ../../../..
|
||||
|
||||
|
||||
### -- BUILD LIBRARIES ------------------------------------------------
|
||||
|
||||
cd build/linux
|
||||
|
||||
PLATFORM=linux
|
||||
|
||||
#CLASSPATH="../../build/linux/work/lib/core.jar:../../build/linux/work/java/lib/rt.jar"
|
||||
CLASSPATH=../build/$PLATFORM/work/lib/core.jar:$CLASSPATH
|
||||
JIKES=../build/$PLATFORM/work/jikes
|
||||
CORE=../build/$PLATFORM/work/lib/core.jar
|
||||
LIBRARIES=../build/$PLATFORM/work/libraries
|
||||
|
||||
# move to processing/build
|
||||
cd ..
|
||||
|
||||
|
||||
# SERIAL LIBRARY
|
||||
echo Building serial library...
|
||||
cd ../serial
|
||||
$JIKES -target 1.1 +D -classpath "code/RXTXcomm.jar:$CORE:$CLASSPATH" -d . *.java
|
||||
rm -f library/serial.jar
|
||||
zip -r0q library/serial.jar processing
|
||||
rm -rf processing
|
||||
mkdir -p $LIBRARIES/serial/library/
|
||||
cp library/serial.jar $LIBRARIES/serial/library/
|
||||
|
||||
|
||||
# NET LIBRARY
|
||||
echo Building net library...
|
||||
cd ../net
|
||||
$JIKES -target 1.1 +D -d . *.java
|
||||
rm -f library/net.jar
|
||||
zip -r0q library/net.jar processing
|
||||
rm -rf processing
|
||||
mkdir -p $LIBRARIES/net/library/
|
||||
cp library/net.jar $LIBRARIES/net/library/
|
||||
|
||||
|
||||
# OPENGL LIBRARY
|
||||
echo Building OpenGL library...
|
||||
cd ../opengl
|
||||
$JIKES -target 1.1 +D -classpath "library/jogl.jar:$CLASSPATH" -d . *.java
|
||||
rm -f library/opengl.jar
|
||||
zip -r0q library/opengl.jar processing
|
||||
rm -rf processing
|
||||
mkdir -p $LIBRARIES/opengl/library/
|
||||
cp library/opengl.jar $LIBRARIES/opengl/library/
|
3
build/linux/run.sh
Executable file
3
build/linux/run.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd work && ./processing && cd ..
|
2
build/macosx/.cvsignore
Normal file
2
build/macosx/.cvsignore
Normal file
@ -0,0 +1,2 @@
|
||||
work*
|
||||
processing-0000-macosx
|
132
build/macosx/dist.sh
Executable file
132
build/macosx/dist.sh
Executable file
@ -0,0 +1,132 @@
|
||||
#!/bin/sh
|
||||
|
||||
# part of the arduino project http://arduino.berlios.de
|
||||
# take from processing http://www.processing.org
|
||||
# by Ben Fry, Casey Reas et al
|
||||
#
|
||||
# the power of open source
|
||||
|
||||
|
||||
# prefers that fink is intalled, but not required
|
||||
if test -f /sw/bin/head
|
||||
then
|
||||
# old 4 char version.. osx only uses the two chars
|
||||
#REVISION=`head -c 4 ../../todo.txt`
|
||||
# a more useful version of head than what's included with osx
|
||||
SHORT_REVISION=`/sw/bin/head -c 4 ../../todo.txt | tail -c 2`
|
||||
REVISION=`/sw/bin/head -c 4 ../../todo.txt`
|
||||
|
||||
VERSIONED=`cat ../../app/Base.java | grep $REVISION`
|
||||
if [ -z "$VERSIONED" ]
|
||||
then
|
||||
echo Fix the revision number in Base.java
|
||||
exit
|
||||
fi
|
||||
|
||||
else
|
||||
# can't get four bytes of head (osx doesn't support -c)
|
||||
SHORT_REVISION=00
|
||||
REVISION=0000
|
||||
fi
|
||||
|
||||
|
||||
./make.sh
|
||||
|
||||
echo Creating Arduino distribution for revision $REVISION...
|
||||
|
||||
# remove any old boogers
|
||||
rm -rf arduino
|
||||
rm -rf Arduino*
|
||||
rm -rf arduino-*
|
||||
|
||||
mkdir arduino
|
||||
|
||||
|
||||
# use 'shared' files as starting point
|
||||
cp -r ../shared arduino
|
||||
|
||||
# add the libraries folder with source
|
||||
#cp -r ../../lib arduino/libraries
|
||||
|
||||
|
||||
# new style examples thing ala reas
|
||||
# not there yet in arduino
|
||||
# cd arduino
|
||||
# unzip -q examples.zip
|
||||
# rm examples.zip
|
||||
# cd ..
|
||||
|
||||
# new style reference
|
||||
# not there yet in arduino
|
||||
# cd arduino
|
||||
# unzip -q reference.zip
|
||||
# rm reference.zip
|
||||
# cd ..
|
||||
|
||||
# get ds_store file (!)
|
||||
cp dist/DS_Store arduino/.DS_Store
|
||||
|
||||
# get package from the dist dir
|
||||
cp -R dist/Arduino.app arduino/
|
||||
chmod +x arduino/Arduino.app/Contents/MacOS/JavaApplicationStub
|
||||
|
||||
# put jar files into the resource dir, leave the rest in lib
|
||||
RES=arduino/Arduino.app/Contents/Resources/Java
|
||||
mkdir -p $RES
|
||||
mv work/lib/*.jar $RES/
|
||||
|
||||
# directories used by the app
|
||||
#mkdir arduino/lib/build
|
||||
|
||||
# grab pde.jar and export from the working dir
|
||||
cp work/Arduino.app/Contents/Resources/Java/pde.jar $RES/
|
||||
|
||||
# removed dependecies from the processing core
|
||||
#cp work/lib/core.jar arduino/lib/
|
||||
|
||||
# get platform-specific goodies from the dist dir
|
||||
#cp `which jikes` arduino
|
||||
#gunzip < dist/jikes.gz > arduino/jikes
|
||||
|
||||
# not needed in arduino
|
||||
# cp dist/jikes arduino/
|
||||
# chmod a+x arduino /jikes
|
||||
|
||||
chmod a+x arduino/Arduino.app/Contents/MacOS/JavaApplicationStub
|
||||
|
||||
#cd ../..
|
||||
#javadoc -public -d doc app/*.java app/preproc/*.java app/syntax/*.java core/*.java opengl/*.java net/*.java video/*.java serial/*.java
|
||||
#cd build/macosx
|
||||
|
||||
# remove boogers
|
||||
find arduino -name "*~" -exec rm -f {} ';'
|
||||
# need to leave ds store stuff cuz one of those is important
|
||||
#find arduino -name ".DS_Store" -exec rm -f {} ';'
|
||||
find arduino -name "._*" -exec rm -f {} ';'
|
||||
find arduino -name "Thumbs.db" -exec rm -f {} ';'
|
||||
|
||||
# clean out the cvs entries
|
||||
find arduino -name "CVS" -exec rm -rf {} ';' 2> /dev/null
|
||||
find arduino -name ".cvsignore" -exec rm -rf {} ';'
|
||||
|
||||
mv arduino/Arduino.app "arduino/Arduino $SHORT_REVISION.app"
|
||||
mv arduino arduino-$REVISION
|
||||
|
||||
# don't have deluxe on my laptop right now
|
||||
#stuff -f sitx arduino-$REVISION
|
||||
|
||||
# zip it all up for release
|
||||
#NICE_FOLDER="Arduino $SHORT_REVISION"
|
||||
#DMG_NAME="arduino-$REVISION"
|
||||
#mv arduino "$NICE_FOLDER"
|
||||
#chmod +x mkdmg
|
||||
#./mkdmg "$NICE_FOLDER" "Arduino"
|
||||
#mv "$NICE_FOLDER.dmg" "$DMG_NAME.dmg"
|
||||
|
||||
# actually, could probably use:
|
||||
# open arduino-uncomp.dmg
|
||||
# rm -rf /Volumes/Arduino/Arduino*
|
||||
# mv "Arduino $REVISION" /Volumes/Arduino
|
||||
# umount /Volumes/Arduino
|
||||
|
||||
echo Done.
|
1
build/macosx/dist/Arduino.app/CVS/Entries
vendored
Normal file
1
build/macosx/dist/Arduino.app/CVS/Entries
vendored
Normal file
@ -0,0 +1 @@
|
||||
D/Contents////
|
1
build/macosx/dist/Arduino.app/CVS/Repository
vendored
Normal file
1
build/macosx/dist/Arduino.app/CVS/Repository
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/macosx/dist/Processing.app
|
1
build/macosx/dist/Arduino.app/CVS/Root
vendored
Normal file
1
build/macosx/dist/Arduino.app/CVS/Root
vendored
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
77
build/macosx/dist/Arduino.app/Contents/Info.plist
vendored
Executable file
77
build/macosx/dist/Arduino.app/Contents/Info.plist
vendored
Executable file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<string>true</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>arduino</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>arduino.icns</string>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>text/plain</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Arduino Source File</string>
|
||||
<key>CFBundleTypeOSTypes</key>
|
||||
<array>
|
||||
<string>TEXT</string>
|
||||
</array>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>JavaApplicationStub</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>arduino.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>de.berlios.arduino</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Arduino</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>Pde1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.3</string>
|
||||
<key>Java</key>
|
||||
<dict>
|
||||
<key>ClassPath</key>
|
||||
<string>$JAVAROOT/pde.jar:lib/core.jar:$JAVAROOT/antlr.jar:$JAVAROOT/oro.jar:$JAVAROOT/registry.jar:lib/build:$JAVAROOT/RXTXcomm.jar</string>
|
||||
<key>JVMVersion</key>
|
||||
<string>1.4+</string>
|
||||
<key>MainClass</key>
|
||||
<string>processing.app.Base</string>
|
||||
<key>Properties</key>
|
||||
<dict>
|
||||
<key>apple.awt.Antialiasing</key>
|
||||
<string>true</string>
|
||||
<key>apple.awt.TextAntialiasing</key>
|
||||
<string>true</string>
|
||||
<key>apple.awt.showGrowBox</key>
|
||||
<string>true</string>
|
||||
<key>apple.awt.use-file-dialog-packages</key>
|
||||
<string>false</string>
|
||||
<key>apple.laf.useScreenMenuBar</key>
|
||||
<string>true</string>
|
||||
<key>com.apple.hwaccel</key>
|
||||
<string>true</string>
|
||||
<key>com.apple.smallTabs</key>
|
||||
<string>true</string>
|
||||
</dict>
|
||||
<key>VMOptions</key>
|
||||
<string>-Xms128M -Xmx256M</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
BIN
build/macosx/dist/Arduino.app/Contents/MacOS/JavaApplicationStub
vendored
Executable file
BIN
build/macosx/dist/Arduino.app/Contents/MacOS/JavaApplicationStub
vendored
Executable file
Binary file not shown.
1
build/macosx/dist/Arduino.app/Contents/PkgInfo
vendored
Executable file
1
build/macosx/dist/Arduino.app/Contents/PkgInfo
vendored
Executable file
@ -0,0 +1 @@
|
||||
APPLsnip
|
3
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Entries
vendored
Normal file
3
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Entries
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
D/Java////
|
||||
/processing.icns/1.2/Sun Dec 5 00:45:14 2004/-kb/
|
||||
/pde.icns/1.1/Sun Jan 30 03:41:54 2005/-kb/
|
1
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Repository
vendored
Normal file
1
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Repository
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/macosx/dist/Processing.app/Contents/Resources
|
1
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Root
vendored
Normal file
1
build/macosx/dist/Arduino.app/Contents/Resources/CVS/Root
vendored
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Entries
vendored
Normal file
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Entries
vendored
Normal file
@ -0,0 +1 @@
|
||||
D
|
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Repository
vendored
Normal file
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Repository
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cvsroot/processing/processing/build/macosx/dist/Processing.app/Contents/Resources/Java
|
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Root
vendored
Normal file
1
build/macosx/dist/Arduino.app/Contents/Resources/Java/CVS/Root
vendored
Normal file
@ -0,0 +1 @@
|
||||
:pserver:anonymous@cvs.sourceforge.net:/cvsroot/processing
|
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/antlr.jar
vendored
Normal file
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/antlr.jar
vendored
Normal file
Binary file not shown.
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/core.jar
vendored
Normal file
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/core.jar
vendored
Normal file
Binary file not shown.
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/mrj.jar
vendored
Executable file
BIN
build/macosx/dist/Arduino.app/Contents/Resources/Java/mrj.jar
vendored
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user