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