1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-30 16:24:09 +03:00

Initial sync with Processing 6406. Compiles and runs (on Mac OS X) but probably very buggy.

This commit is contained in:
David A. Mellis
2010-04-21 01:58:57 +00:00
parent d36fbfe1cf
commit 34579ae440
57 changed files with 22913 additions and 2218 deletions

View File

@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-09 Ben Fry and Casey Reas
Copyright (c) 2004-10 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
@ -42,7 +42,10 @@ import processing.core.*;
*/
public class Base {
public static final int REVISION = 18;
/** This might be replaced by main() if there's a lib/version.txt file. */
static String VERSION_NAME = "0018";
/** Set true if this a proper release rather than a numbered revision. */
static public boolean RELEASE = false;
static HashMap<Integer, String> platformNames = new HashMap<Integer, String>();
static {
@ -101,31 +104,16 @@ public class Base {
// ArrayList editors = Collections.synchronizedList(new ArrayList<Editor>());
Editor activeEditor;
// int nextEditorX;
// int nextEditorY;
// import com.sun.jna.Library;
// import com.sun.jna.Native;
// public interface CLibrary extends Library {
// CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
// int setenv(String name, String value, int overwrite);
// String getenv(String name);
// int unsetenv(String name);
// int putenv(String string);
// }
static public void main(String args[]) {
// /Users/fry/coconut/sketchbook/libraries/gsvideo/library
// CLibrary clib = CLibrary.INSTANCE;
// clib.setenv("DYLD_LIBRARY_PATH", "/Users/fry/coconut/sketchbook/libraries/gsvideo/library", 1);
// System.out.println("env is now " + clib.getenv("DYLD_LIBRARY_PATH"));
try {
File versionFile = getContentFile("lib/version.txt");
if (versionFile.exists()) {
VERSION_NAME = PApplet.loadStrings(versionFile)[0];
String version = PApplet.loadStrings(versionFile)[0];
if (!version.equals(VERSION_NAME)) {
VERSION_NAME = version;
RELEASE = true;
}
}
} catch (Exception e) {
e.printStackTrace();
@ -187,10 +175,12 @@ public class Base {
try {
platform.setLookAndFeel();
} catch (Exception e) {
System.err.println("Non-fatal error while setting the Look & Feel.");
System.err.println("The error message follows, however Arduino should run fine.");
System.err.println(e.getMessage());
//e.printStackTrace();
String mess = e.getMessage();
if (mess.indexOf("ch.randelshofer.quaqua.QuaquaLookAndFeel") == -1) {
System.err.println("Non-fatal error while setting the Look & Feel.");
System.err.println("The error message follows, however Arduino should run fine.");
System.err.println(mess);
}
}
// Create a location for untitled sketches
@ -213,7 +203,7 @@ public class Base {
static protected void initPlatform() {
try {
Class platformClass = Class.forName("processing.app.Platform");
Class<?> platformClass = Class.forName("processing.app.Platform");
if (Base.isMacOS()) {
platformClass = Class.forName("processing.app.macosx.Platform");
} else if (Base.isWindows()) {
@ -270,7 +260,7 @@ public class Base {
}
}
// If not path is set, get the default sketchbook folder for this platform
// If no path is set, get the default sketchbook folder for this platform
if (sketchbookPath == null) {
File defaultFolder = getDefaultSketchbookFolder();
Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath());
@ -456,8 +446,8 @@ public class Base {
protected int[] nextEditorLocation() {
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int defaultWidth = Preferences.getInteger("default.window.width");
int defaultHeight = Preferences.getInteger("default.window.height");
int defaultWidth = Preferences.getInteger("editor.window.width.default");
int defaultHeight = Preferences.getInteger("editor.window.height.default");
if (activeEditor == null) {
// If no current active editor, use default placement
@ -584,7 +574,7 @@ public class Base {
* Replace the sketch in the current window with a new untitled document.
*/
public void handleNewReplace() {
if (!activeEditor.checkModified(true)) {
if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled
}
// Close the running window, avoid window boogers with multiple sketches
@ -616,7 +606,7 @@ public class Base {
* @param path Location of the primary pde file for the sketch.
*/
public void handleOpenReplace(String path) {
if (!activeEditor.checkModified(true)) {
if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled
}
// Close the running window, avoid window boogers with multiple sketches
@ -758,8 +748,8 @@ public class Base {
*/
public boolean handleClose(Editor editor) {
// Check if modified
boolean immediate = editors.size() == 1;
if (!editor.checkModified(immediate)) {
// boolean immediate = editors.size() == 1;
if (!editor.checkModified()) {
return false;
}
@ -862,7 +852,7 @@ public class Base {
protected boolean handleQuitEach() {
int index = 0;
for (Editor editor : editors) {
if (editor.checkModified(true)) {
if (editor.checkModified()) {
// Update to the new/final sketch path for this fella
storeSketchPath(editor, index);
index++;
@ -914,7 +904,8 @@ public class Base {
// Add a list of all sketches and subfolders
try {
boolean sketches = addSketches(menu, getSketchbookFolder(), true);
//boolean sketches = addSketches(menu, getSketchbookFolder(), true);
boolean sketches = addSketches(menu, getSketchbookFolder());
if (sketches) menu.addSeparator();
} catch (IOException e) {
e.printStackTrace();
@ -923,11 +914,11 @@ public class Base {
//System.out.println("rebuilding examples menu");
// Add each of the subfolders of examples directly to the menu
try {
boolean found = addSketches(menu, examplesFolder, true);
boolean found = addSketches(menu, examplesFolder);
if (found) menu.addSeparator();
found = addSketches(menu, getSketchbookLibrariesFolder(), true);
found = addSketches(menu, getSketchbookLibrariesFolder());
if (found) menu.addSeparator();
addSketches(menu, librariesFolder, true);
addSketches(menu, librariesFolder);
} catch (IOException e) {
e.printStackTrace();
}
@ -939,7 +930,8 @@ public class Base {
//new Exception().printStackTrace();
try {
menu.removeAll();
addSketches(menu, getSketchbookFolder(), false);
//addSketches(menu, getSketchbookFolder(), false);
addSketches(menu, getSketchbookFolder());
} catch (IOException e) {
e.printStackTrace();
}
@ -983,11 +975,11 @@ public class Base {
//System.out.println("rebuilding examples menu");
try {
menu.removeAll();
boolean found = addSketches(menu, examplesFolder, false);
boolean found = addSketches(menu, examplesFolder);
if (found) menu.addSeparator();
found = addSketches(menu, getSketchbookLibrariesFolder(), false);
found = addSketches(menu, getSketchbookLibrariesFolder());
if (found) menu.addSeparator();
addSketches(menu, librariesFolder, false);
addSketches(menu, librariesFolder);
} catch (IOException e) {
e.printStackTrace();
}
@ -1050,8 +1042,7 @@ public class Base {
* should replace the sketch in the current window, or false when the
* sketch should open in a new window.
*/
protected boolean addSketches(JMenu menu, File folder,
final boolean openReplaces) throws IOException {
protected boolean addSketches(JMenu menu, File folder) throws IOException {
// skip .DS_Store files, etc (this shouldn't actually be necessary)
if (!folder.isDirectory()) return false;
@ -1068,7 +1059,8 @@ public class Base {
public void actionPerformed(ActionEvent e) {
String path = e.getActionCommand();
if (new File(path).exists()) {
if (openReplaces) {
// if (openReplaces) {
if ((e.getModifiers() & ActionEvent.SHIFT_MASK) == 0) {
handleOpenReplace(path);
} else {
handleOpen(path);
@ -1121,14 +1113,15 @@ public class Base {
} else {
// don't create an extra menu level for a folder named "examples"
if (subfolder.getName().equals("examples")) {
boolean found = addSketches(menu, subfolder, openReplaces); //, false);
boolean found = addSketches(menu, subfolder);
if (found) ifound = true;
} else {
// not a sketch folder, but maybe a subfolder containing sketches
JMenu submenu = new JMenu(list[i]);
// needs to be separate var
// otherwise would set ifound to false
boolean found = addSketches(submenu, subfolder, openReplaces); //, false);
//boolean found = addSketches(submenu, subfolder, openReplaces); //, false);
boolean found = addSketches(submenu, subfolder); //, false);
if (found) {
menu.add(submenu);
ifound = true;
@ -1319,6 +1312,11 @@ public class Base {
// }
static public Platform getPlatform() {
return platform;
}
static public String getPlatformName() {
String osname = System.getProperty("os.name");
@ -1714,12 +1712,11 @@ public class Base {
}
*/
/**
* Registers key events for a Ctrl-W and ESC with an ActionListener
* that will take care of disposing the window.
*/
static public void registerWindowCloseKeys(JRootPane root, //Window window,
static public void registerWindowCloseKeys(JRootPane root,
ActionListener disposer) {
KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
root.registerKeyboardAction(disposer, stroke,
@ -1836,6 +1833,129 @@ public class Base {
// ...................................................................
// incomplete
static public int showYesNoCancelQuestion(Editor editor, String title,
String primary, String secondary) {
if (!Base.isMacOS()) {
int result =
JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
return result;
// if (result == JOptionPane.YES_OPTION) {
//
// } else if (result == JOptionPane.NO_OPTION) {
// return true; // ok to continue
//
// } else if (result == JOptionPane.CANCEL_OPTION) {
// return false;
//
// } else {
// throw new IllegalStateException();
// }
} else {
// Pane formatting adapted from the Quaqua guide
// http://www.randelshofer.ch/quaqua/guide/joptionpane.html
JOptionPane pane =
new JOptionPane("<html> " +
"<head> <style type=\"text/css\">"+
"b { font: 13pt \"Lucida Grande\" }"+
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
"</style> </head>" +
"<b>Do you want to save changes to this sketch<BR>" +
" before closing?</b>" +
"<p>If you don't save, your changes will be lost.",
JOptionPane.QUESTION_MESSAGE);
String[] options = new String[] {
"Save", "Cancel", "Don't Save"
};
pane.setOptions(options);
// highlight the safest option ala apple hig
pane.setInitialValue(options[0]);
// on macosx, setting the destructive property places this option
// away from the others at the lefthand side
pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
new Integer(2));
JDialog dialog = pane.createDialog(editor, null);
dialog.setVisible(true);
Object result = pane.getValue();
if (result == options[0]) {
return JOptionPane.YES_OPTION;
} else if (result == options[1]) {
return JOptionPane.CANCEL_OPTION;
} else if (result == options[2]) {
return JOptionPane.NO_OPTION;
} else {
return JOptionPane.CLOSED_OPTION;
}
}
}
//if (result == JOptionPane.YES_OPTION) {
//
// } else if (result == JOptionPane.NO_OPTION) {
// return true; // ok to continue
//
// } else if (result == JOptionPane.CANCEL_OPTION) {
// return false;
//
// } else {
// throw new IllegalStateException();
// }
static public int showYesNoQuestion(Frame editor, String title,
String primary, String secondary) {
if (!Base.isMacOS()) {
return JOptionPane.showConfirmDialog(editor,
"<html><body>" +
"<b>" + primary + "</b>" +
"<br>" + secondary, title,
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
} else {
// Pane formatting adapted from the Quaqua guide
// http://www.randelshofer.ch/quaqua/guide/joptionpane.html
JOptionPane pane =
new JOptionPane("<html> " +
"<head> <style type=\"text/css\">"+
"b { font: 13pt \"Lucida Grande\" }"+
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
"</style> </head>" +
"<b>" + primary + "</b>" +
"<p>" + secondary + "</p>",
JOptionPane.QUESTION_MESSAGE);
String[] options = new String[] {
"Yes", "No"
};
pane.setOptions(options);
// highlight the safest option ala apple hig
pane.setInitialValue(options[0]);
JDialog dialog = pane.createDialog(editor, null);
dialog.setVisible(true);
Object result = pane.getValue();
if (result == options[0]) {
return JOptionPane.YES_OPTION;
} else if (result == options[1]) {
return JOptionPane.NO_OPTION;
} else {
return JOptionPane.CLOSED_OPTION;
}
}
}
/**
* Retrieve a path to something in the Processing folder. Eventually this
* may refer to the Contents subfolder of Processing.app, if we bundle things
@ -1959,6 +2079,36 @@ public class Base {
}
/**
* Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #.
*/
static public HashMap<String,String> readSettings(File inputFile) {
HashMap<String,String> outgoing = new HashMap<String,String>();
if (!inputFile.exists()) return outgoing; // return empty hash
String lines[] = PApplet.loadStrings(inputFile);
for (int i = 0; i < lines.length; i++) {
int hash = lines[i].indexOf('#');
String line = (hash == -1) ?
lines[i].trim() : lines[i].substring(0, hash).trim();
if (line.length() == 0) continue;
int equals = line.indexOf('=');
if (equals == -1) {
System.err.println("ignoring illegal line in " + inputFile);
System.err.println(" " + line);
continue;
}
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
outgoing.put(attr, valu);
}
return outgoing;
}
static public void copyFile(File sourceFile,
File targetFile) throws IOException {
InputStream from =
@ -2116,7 +2266,7 @@ public class Base {
static public String[] listFiles(File folder, boolean relative) {
String path = folder.getAbsolutePath();
Vector vector = new Vector();
Vector<String> vector = new Vector<String>();
listFiles(relative ? (path + File.separator) : "", path, vector);
String outgoing[] = new String[vector.size()];
vector.copyInto(outgoing);
@ -2125,7 +2275,7 @@ public class Base {
static protected void listFiles(String basePath,
String path, Vector vector) {
String path, Vector<String> vector) {
File folder = new File(path);
String list[] = folder.list();
if (list == null) return;

View File

@ -43,7 +43,6 @@ import javax.swing.undo.*;
import gnu.io.*;
/**
* Main editor panel for the Processing Development Environment.
*/
@ -114,7 +113,6 @@ public class Editor extends JFrame implements RunnerListener {
EditorLineStatus lineStatus;
boolean newEditor = true;
JEditorPane editorPane;
JEditTextArea textarea;
@ -122,14 +120,14 @@ public class Editor extends JFrame implements RunnerListener {
// runtime information and window placement
Point sketchWindowLocation;
Runner runtime;
//Runner runtime;
JMenuItem exportAppItem;
JMenuItem saveMenuItem;
JMenuItem saveAsMenuItem;
boolean running;
boolean presenting;
//boolean presenting;
boolean uploading;
// undo fellers
@ -142,6 +140,12 @@ public class Editor extends JFrame implements RunnerListener {
FindReplace find;
Runnable runHandler;
Runnable presentHandler;
Runnable stopHandler;
Runnable exportHandler;
Runnable exportAppHandler;
public Editor(Base ibase, String path, int[] location) {
super("Arduino");
@ -149,6 +153,9 @@ public class Editor extends JFrame implements RunnerListener {
//Base.setIcon(this);
// Install default actions for Run, Present, etc.
resetHandlers();
// add listener to handle window close box hit event
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
@ -232,22 +239,7 @@ public class Editor extends JFrame implements RunnerListener {
lineStatus = new EditorLineStatus(textarea);
consolePanel.add(lineStatus, BorderLayout.SOUTH);
// if (newEditor) {
// try {
// setupEditorPane();
// upper.add(editorPane);
// } catch (Exception e1) {
// PrintWriter w = PApplet.createWriter(new File("/Users/fry/Desktop/blah.txt"));
// w.println(e1.getMessage());
// e1.printStackTrace(w);
// w.flush();
// w.close();
//// e1.printStackTrace());
//// e1.printStackTrace(System.out);
// }
// } else {
upper.add(textarea);
// }
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
upper, consolePanel);
@ -276,64 +268,10 @@ public class Editor extends JFrame implements RunnerListener {
listener = new EditorListener(this, textarea);
pain.add(box);
pain.setTransferHandler(new TransferHandler() {
// get shift down/up events so we can show the alt version of toolbar buttons
textarea.addKeyListener(toolbar);
public boolean canImport(JComponent dest, DataFlavor[] flavors) {
return true;
}
public boolean importData(JComponent src, Transferable transferable) {
int successful = 0;
try {
DataFlavor uriListFlavor =
new DataFlavor("text/uri-list;class=java.lang.String");
if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
java.util.List list = (java.util.List)
transferable.getTransferData(DataFlavor.javaFileListFlavor);
for (int i = 0; i < list.size(); i++) {
File file = (File) list.get(i);
if (sketch.addFile(file)) {
successful++;
}
}
} else if (transferable.isDataFlavorSupported(uriListFlavor)) {
//System.out.println("uri list");
String data = (String)transferable.getTransferData(uriListFlavor);
String[] pieces = PApplet.splitTokens(data, "\r\n");
//PApplet.println(pieces);
for (int i = 0; i < pieces.length; i++) {
if (pieces[i].startsWith("#")) continue;
String path = null;
if (pieces[i].startsWith("file:///")) {
path = pieces[i].substring(7);
} else if (pieces[i].startsWith("file:/")) {
path = pieces[i].substring(5);
}
if (sketch.addFile(new File(path))) {
successful++;
}
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
if (successful == 0) {
statusError("No files were added to the sketch.");
} else if (successful == 1) {
statusNotice("One file added to the sketch.");
} else {
statusNotice(successful + " files added to the sketch.");
}
return true;
}
});
pain.setTransferHandler(new FileDropHandler());
// System.out.println("t1");
@ -345,6 +283,20 @@ public class Editor extends JFrame implements RunnerListener {
// Set the window bounds and the divider location before setting it visible
setPlacement(location);
// If the window is resized too small this will resize it again to the
// minimums. Adapted by Chris Lonnen from comments here:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4320050
// as a fix for http://dev.processing.org/bugs/show_bug.cgi?id=25
final int minW = Preferences.getInteger("editor.window.width.min");
final int minH = Preferences.getInteger("editor.window.height.min");
addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentResized(ComponentEvent event) {
setSize((getWidth() < minW) ? minW : getWidth(),
(getHeight() < minH) ? minH : getHeight());
}
});
// System.out.println("t3");
// Bring back the general options for the editor
@ -363,46 +315,71 @@ public class Editor extends JFrame implements RunnerListener {
}
/*
// http://wiki.netbeans.org/DevFaqEditorCodeCompletionAnyJEditorPane
void setupEditorPane() throws IOException {
editorPane = new JEditorPane();
/**
* Handles files dragged & dropped from the desktop and into the editor
* window. Dragging files into the editor window is the same as using
* "Sketch &rarr; Add File" for each file.
*/
class FileDropHandler extends TransferHandler {
public boolean canImport(JComponent dest, DataFlavor[] flavors) {
return true;
}
// This will find the Java editor kit and associate it with
// our editor pane. But that does not give us code completion
// just yet because we have no Java context (i.e. no class path, etc.).
// However, this does give us syntax coloring.
EditorKit kit = CloneableEditorSupport.getEditorKit("text/x-java");
editorPane.setEditorKit(kit);
// You can specify any ".java" file.
// If the file does not exist, it will be created.
// The contents of the file does not matter.
// The extension must be ".java", however.
// String newSourcePath = "/Users/fry/Desktop/tmp.java";
@SuppressWarnings("unchecked")
public boolean importData(JComponent src, Transferable transferable) {
int successful = 0;
// File tmpFile = new File(newSourcePath);
// System.out.println(tmpFile.getParent() + " " + tmpFile.getName());
// FileObject fob = FileUtil.createData(tmpFile);
File tmpFile = File.createTempFile("temp", ".java");
FileObject fob = FileUtil.toFileObject(FileUtil.normalizeFile(tmpFile));
try {
DataFlavor uriListFlavor =
new DataFlavor("text/uri-list;class=java.lang.String");
DataObject dob = DataObject.find(fob);
editorPane.getDocument().putProperty(Document.StreamDescriptionProperty, dob);
if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
java.util.List list = (java.util.List)
transferable.getTransferData(DataFlavor.javaFileListFlavor);
for (int i = 0; i < list.size(); i++) {
File file = (File) list.get(i);
if (sketch.addFile(file)) {
successful++;
}
}
} else if (transferable.isDataFlavorSupported(uriListFlavor)) {
// Some platforms (Mac OS X and Linux, when this began) preferred
// this method of moving files.
String data = (String)transferable.getTransferData(uriListFlavor);
String[] pieces = PApplet.splitTokens(data, "\r\n");
for (int i = 0; i < pieces.length; i++) {
if (pieces[i].startsWith("#")) continue;
// This sets up a default class path for us so that
// we can find all the JDK classes via code completion.
DialogBinding.bindComponentToFile(fob, 0, 0, editorPane);
String path = null;
if (pieces[i].startsWith("file:///")) {
path = pieces[i].substring(7);
} else if (pieces[i].startsWith("file:/")) {
path = pieces[i].substring(5);
}
if (sketch.addFile(new File(path))) {
successful++;
}
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Last but not least, we need to fill the editor pane with
// some initial dummy code - as it seems somehow required to
// kick-start code completion.
// A simple dummy package declaration will do.
editorPane.setText("package dummy;");
if (successful == 0) {
statusError("No files were added to the sketch.");
} else if (successful == 1) {
statusNotice("One file added to the sketch.");
} else {
statusNotice(successful + " files added to the sketch.");
}
return true;
}
}
*/
protected void setPlacement(int[] location) {
setBounds(location[0], location[1], location[2], location[3]);
if (location[4] != 0) {
@ -434,10 +411,10 @@ public class Editor extends JFrame implements RunnerListener {
* This appears to only be required on OS X 10.2, and is not
* even being called on later versions of OS X or Windows.
*/
public Dimension getMinimumSize() {
//System.out.println("getting minimum size");
return new Dimension(500, 550);
}
// public Dimension getMinimumSize() {
// //System.out.println("getting minimum size");
// return new Dimension(500, 550);
// }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@ -737,7 +714,7 @@ public class Editor extends JFrame implements RunnerListener {
protected void addTools(JMenu menu, File sourceFolder) {
HashMap toolItems = new HashMap();
HashMap<String, JMenuItem> toolItems = new HashMap<String, JMenuItem>();
File[] folders = sourceFolder.listFiles(new FileFilter() {
public boolean accept(File folder) {
@ -807,7 +784,7 @@ public class Editor extends JFrame implements RunnerListener {
// If no class name found, just move on.
if (className == null) continue;
Class toolClass = Class.forName(className, true, loader);
Class<?> toolClass = Class.forName(className, true, loader);
final Tool tool = (Tool) toolClass.newInstance();
tool.init(Editor.this);
@ -817,6 +794,7 @@ public class Editor extends JFrame implements RunnerListener {
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(tool);
//new Thread(tool).start();
}
});
//menu.add(item);
@ -826,7 +804,7 @@ public class Editor extends JFrame implements RunnerListener {
e.printStackTrace();
}
}
ArrayList<String> toolList = new ArrayList(toolItems.keySet());
ArrayList<String> toolList = new ArrayList<String>(toolItems.keySet());
if (toolList.size() == 0) return;
menu.addSeparator();
@ -843,7 +821,7 @@ public class Editor extends JFrame implements RunnerListener {
try {
ZipFile zipFile = new ZipFile(file);
Enumeration entries = zipFile.entries();
Enumeration<?> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
@ -869,7 +847,7 @@ public class Editor extends JFrame implements RunnerListener {
protected JMenuItem createToolMenuItem(String className) {
try {
Class toolClass = Class.forName(className);
Class<?> toolClass = Class.forName(className);
final Tool tool = (Tool) toolClass.newInstance();
JMenuItem item = new JMenuItem(tool.getMenuTitle());
@ -903,12 +881,14 @@ public class Editor extends JFrame implements RunnerListener {
menu.add(createToolMenuItem("processing.app.tools.Archiver"));
menu.add(createToolMenuItem("processing.app.tools.FixEncoding"));
/*
//menu.add(createToolMenuItem("processing.app.tools.android.Build"));
item = createToolMenuItem("processing.app.tools.android.Build");
item.setAccelerator(KeyStroke.getKeyStroke('D', modifiers));
menu.add(item);
*/
// // These are temporary entries while Android mode is being worked out.
// // The mode will not be in the tools menu, and won't involve a cmd-key
// if (!Base.RELEASE) {
// item = createToolMenuItem("processing.app.tools.android.AndroidTool");
// item.setAccelerator(KeyStroke.getKeyStroke('D', modifiers));
// menu.add(item);
// menu.add(createToolMenuItem("processing.app.tools.android.Reset"));
// }
return menu;
}
@ -1363,6 +1343,35 @@ public class Editor extends JFrame implements RunnerListener {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// these will be done in a more generic way soon, more like:
// setHandler("action name", Runnable);
// but for the time being, working out the kinks of how many things to
// abstract from the editor in this fashion.
public void setHandlers(Runnable runHandler, Runnable presentHandler,
Runnable stopHandler,
Runnable exportHandler, Runnable exportAppHandler) {
this.runHandler = runHandler;
this.presentHandler = presentHandler;
this.stopHandler = stopHandler;
this.exportHandler = exportHandler;
this.exportAppHandler = exportAppHandler;
}
public void resetHandlers() {
runHandler = new DefaultRunHandler();
presentHandler = new DefaultPresentHandler();
stopHandler = new DefaultStopHandler();
exportHandler = new DefaultExportHandler();
exportAppHandler = new DefaultExportAppHandler();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Gets the current sketch object.
*/
@ -1799,26 +1808,50 @@ public class Editor extends JFrame implements RunnerListener {
console.clear();
}
//presenting = present;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
sketch.compile(verbose);
statusNotice("Done compiling.");
} catch (RunnerException e) {
//statusError("Error compiling...");
statusError(e);
} catch (Exception e) {
e.printStackTrace();
}
toolbar.deactivate(EditorToolbar.RUN);
}
});
// Cannot use invokeLater() here, otherwise it gets
// placed on the event thread and causes a hang--bad idea all around.
new Thread(verbose ? presentHandler : runHandler).start();
}
// DAM: in Arduino, this is compile
class DefaultRunHandler implements Runnable {
public void run() {
try {
sketch.prepare();
String appletClassName = sketch.build(false);
statusNotice("Done compiling.");
} catch (Exception e) {
statusError(e);
}
toolbar.deactivate(EditorToolbar.RUN);
}
}
// DAM: in Arduino, this is compile (with verbose output)
class DefaultPresentHandler implements Runnable {
public void run() {
try {
sketch.prepare();
String appletClassName = sketch.build(true);
statusNotice("Done compiling.");
} catch (Exception e) {
statusError(e);
}
toolbar.deactivate(EditorToolbar.RUN);
}
}
class DefaultStopHandler implements Runnable {
public void run() {
try {
// DAM: we should try to kill the compilation or upload process here.
} catch (Exception e) {
statusError(e);
}
}
}
/**
* Set the location of the sketch run window. Used by Runner to update the
@ -1855,8 +1888,10 @@ public class Editor extends JFrame implements RunnerListener {
/**
* Called by Runner to notify that the sketch has stopped running.
* Tools should not call this function, use handleStop() instead.
* Deactivate the Run button. This is called by Runner to notify that the
* sketch has stopped running, usually in response to an error (or maybe
* the sketch completing and exiting?) Tools should not call this function.
* To initiate a "stop" action, call handleStop() instead.
*/
public void internalRunnerClosed() {
running = false;
@ -1870,11 +1905,9 @@ public class Editor extends JFrame implements RunnerListener {
public void internalCloseRunner() {
running = false;
if (stopHandler != null)
try {
if (runtime != null) {
runtime.close(); // kills the window
runtime = null; // will this help?
}
stopHandler.run();
} catch (Exception e) { }
sketch.cleanup();
@ -1883,13 +1916,14 @@ public class Editor extends JFrame implements RunnerListener {
/**
* Check if the sketch is modified and ask user to save changes.
* Immediately should be set true when quitting, or when the save should
* not happen asynchronously. Come to think of it, that's always now?
* @return false if canceling the close/quit operation
*/
protected boolean checkModified(boolean immediately) {
protected boolean checkModified() {
if (!sketch.isModified()) return true;
// As of Processing 1.0.10, this always happens immediately.
// http://dev.processing.org/bugs/show_bug.cgi?id=1456
String prompt = "Save changes to " + sketch.getName() + "? ";
if (!Base.isMacOS()) {
@ -1899,13 +1933,14 @@ public class Editor extends JFrame implements RunnerListener {
JOptionPane.QUESTION_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
return handleSave(immediately);
return handleSave(true);
} else if (result == JOptionPane.NO_OPTION) {
return true; // ok to continue
} else if (result == JOptionPane.CANCEL_OPTION) {
return false;
} else {
throw new IllegalStateException();
}
@ -1950,7 +1985,7 @@ public class Editor extends JFrame implements RunnerListener {
Object result = pane.getValue();
if (result == options[0]) { // save (and close/quit)
return handleSave(immediately);
return handleSave(true);
} else if (result == options[2]) { // don't save (still close/quit)
return true;
@ -2203,39 +2238,69 @@ public class Editor extends JFrame implements RunnerListener {
synchronized public void handleExport(final boolean verbose) {
//if (!handleExportCheckModified()) return;
toolbar.activate(EditorToolbar.EXPORT);
console.clear();
statusNotice("Uploading to I/O Board...");
//SwingUtilities.invokeLater(new Runnable() {
Thread t = new Thread(new Runnable() {
public void run() {
try {
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
uploading = true;
boolean success = sketch.exportApplet(verbose);
if (success) {
statusNotice("Done uploading.");
} else {
// error message will already be visible
}
} catch (RunnerException e) {
//statusError("Error during upload.");
//e.printStackTrace();
statusError(e);
} catch (Exception e) {
e.printStackTrace();
}
uploading = false;
//toolbar.clear();
toolbar.deactivate(EditorToolbar.EXPORT);
}});
t.start();
new Thread(verbose ? exportAppHandler : exportHandler).start();
}
// DAM: in Arduino, this is upload
class DefaultExportHandler implements Runnable {
public void run() {
try {
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
uploading = true;
boolean success = sketch.exportApplet(false);
if (success) {
statusNotice("Done uploading.");
} else {
// error message will already be visible
}
} catch (RunnerException e) {
//statusError("Error during upload.");
//e.printStackTrace();
statusError(e);
} catch (Exception e) {
e.printStackTrace();
}
uploading = false;
//toolbar.clear();
toolbar.deactivate(EditorToolbar.EXPORT);
}
}
// DAM: in Arduino, this is upload (with verbose output)
class DefaultExportAppHandler implements Runnable {
public void run() {
try {
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
uploading = true;
boolean success = sketch.exportApplet(true);
if (success) {
statusNotice("Done uploading.");
} else {
// error message will already be visible
}
} catch (RunnerException e) {
//statusError("Error during upload.");
//e.printStackTrace();
statusError(e);
} catch (Exception e) {
e.printStackTrace();
}
uploading = false;
//toolbar.clear();
toolbar.deactivate(EditorToolbar.EXPORT);
}
}
/**
* Checks to see if the sketch has been modified, and if so,
@ -2418,7 +2483,7 @@ public class Editor extends JFrame implements RunnerListener {
}
statusError(mess);
}
e.printStackTrace();
// e.printStackTrace();
}
@ -2563,4 +2628,3 @@ public class Editor extends JFrame implements RunnerListener {
}
}
}

View File

@ -28,6 +28,7 @@ import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import java.util.*;
@ -47,8 +48,6 @@ public class EditorConsole extends JScrollPane {
MutableAttributeSet stdStyle;
MutableAttributeSet errStyle;
boolean cerror;
int maxLineCount;
static File errFile;
@ -221,18 +220,9 @@ public class EditorConsole extends JScrollPane {
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;
}
@ -291,10 +281,10 @@ public class EditorConsole extends JScrollPane {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
class EditorConsoleStream extends OutputStream {
private static class EditorConsoleStream extends OutputStream {
//static EditorConsole current;
boolean err; // whether stderr or stdout
byte single[] = new byte[1];
final boolean err; // whether stderr or stdout
final byte single[] = new byte[1];
public EditorConsoleStream(boolean err) {
this.err = err;
@ -389,7 +379,7 @@ public class EditorConsole extends JScrollPane {
* swing event thread, so they need to be synchronized
*/
class BufferedStyledDocument extends DefaultStyledDocument {
ArrayList elements = new ArrayList();
ArrayList<ElementSpec> elements = new ArrayList<ElementSpec>();
int maxLineLength, maxLineCount;
int currentLineLength = 0;
boolean needLineBreak = false;

View File

@ -103,6 +103,10 @@ public class EditorListener {
char c = event.getKeyChar();
int code = event.getKeyCode();
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(true);
// }
//System.out.println((int)c + " " + code + " " + event);
//System.out.println();
@ -457,6 +461,13 @@ public class EditorListener {
}
// public boolean keyReleased(KeyEvent event) {
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(false);
// }
// }
public boolean keyTyped(KeyEvent event) {
char c = event.getKeyChar();

View File

@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2004-09 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
@ -25,6 +25,7 @@ package processing.app;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
@ -32,12 +33,18 @@ import javax.swing.event.*;
/**
* run/stop/etc buttons for the ide
*/
public class EditorToolbar extends JComponent implements MouseInputListener {
public class EditorToolbar extends JComponent implements MouseInputListener, KeyListener {
/** Rollover titles for each button. */
static final String title[] = {
"Verify", "Stop", "New", "Open", "Save", "Upload", "Serial Monitor"
};
/** Titles for each button when the shift key is pressed. */
static final String titleShift[] = {
"Verify (w/ Verbose Output)", "Stop", "New Editor Window", "Open in Another Window", "Save", "Upload (w/ Verbose Output)", "Serial Monitor"
};
static final int BUTTON_COUNT = title.length;
/** Width of each toolbar button. */
static final int BUTTON_WIDTH = 27;
@ -45,6 +52,9 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
static final int BUTTON_HEIGHT = 32;
/** The amount of space between groups of buttons on the toolbar. */
static final int BUTTON_GAP = 5;
/** Size of the button image being chopped up. */
static final int BUTTON_IMAGE_SIZE = 33;
static final int RUN = 0;
static final int STOP = 1;
@ -61,45 +71,35 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
static final int ACTIVE = 2;
Editor editor;
//boolean disableRun; // this was for library
//Label status;
Image offscreen;
int width, height;
Color bgcolor;
static Image buttons;
static Image inactive[];
static Image rollover[];
static Image active[];
static Image[][] buttonImages;
int currentRollover;
//int currentSelection;
JPopupMenu popup;
JMenu menu;
int buttonCount;
int state[] = new int[BUTTON_COUNT];
Image stateImage[];
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;
boolean shiftPressed;
public EditorToolbar(Editor editor, JMenu menu) {
this.editor = editor;
this.menu = menu;
if (buttons == null) {
buttons = Base.getThemeImage("buttons.gif", this);
}
buttonCount = 0;
which = new int[BUTTON_COUNT];
@ -115,9 +115,6 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
currentRollover = -1;
bgcolor = Theme.getColor("buttons.bgcolor");
status = "";
statusFont = Theme.getFont("buttons.status.font");
statusColor = Theme.getColor("buttons.status.color");
@ -125,30 +122,28 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
addMouseMotionListener(this);
}
public void paintComponent(Graphics screen) {
// this data is shared by all EditorToolbar instances
if (inactive == null) {
inactive = new Image[BUTTON_COUNT];
rollover = new Image[BUTTON_COUNT];
active = new Image[BUTTON_COUNT];
int IMAGE_SIZE = 33;
protected void loadButtons() {
Image allButtons = Base.getThemeImage("buttons.gif", this);
buttonImages = new Image[BUTTON_COUNT][3];
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);
for (int state = 0; state < 3; state++) {
Image image = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
Graphics g = image.getGraphics();
g.drawImage(allButtons,
-(i*BUTTON_IMAGE_SIZE) - 3,
(-2 + state)*BUTTON_IMAGE_SIZE, null);
buttonImages[i][state] = image;
}
}
}
@Override
public void paintComponent(Graphics screen) {
// this data is shared by all EditorToolbar instances
if (buttonImages == null) {
loadButtons();
}
// this happens once per instance of EditorToolbar
if (stateImage == null) {
@ -191,21 +186,34 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
/*
// if i ever find the guy who wrote the java2d api, i will hurt him.
*
* whereas I love the Java2D API. --jdf. lol.
*
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;
if (currentRollover != -1) {
int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
String status = shiftPressed ? titleShift[currentRollover] : title[currentRollover];
g.drawString(status, buttonCount * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY);
}
screen.drawImage(offscreen, 0, 0, null);
if (!isEnabled()) {
screen.setColor(new Color(0,0,0,100));
screen.fillRect(0, 0, getWidth(), getHeight());
}
}
public void mouseMoved(MouseEvent e) {
if (!isEnabled())
return;
// mouse events before paint();
if (state == null) return;
@ -213,16 +221,17 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
// 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());
handleMouse(e);
}
public void mouseDragged(MouseEvent e) { }
public void handleMouse(int x, int y) {
public void handleMouse(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (currentRollover != -1) {
if ((x > x1[currentRollover]) && (y > y1) &&
(x < x2[currentRollover]) && (y < y2)) {
@ -230,7 +239,6 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
} else {
setState(currentRollover, INACTIVE, true);
messageClear(title[currentRollover]);
currentRollover = -1;
}
}
@ -238,10 +246,8 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
if (sel == -1) return;
if (state[sel] != ACTIVE) {
//if (!(disableRun && ((sel == RUN) || (sel == STOP)))) {
setState(sel, ROLLOVER, true);
currentRollover = sel;
//}
}
}
@ -263,32 +269,16 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
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;
}
stateImage[slot] = buttonImages[which[slot]][newState];
if (updateAfter) {
//System.out.println("trying to update " + slot + " " + state[slot]);
//new Exception("setting slot " + slot + " to " + state[slot]).printStackTrace();
repaint(); // changed for swing from update();
//Toolkit.getDefaultToolkit().sync();
repaint();
}
}
public void mouseEntered(MouseEvent e) {
//mouseMove(e);
handleMouse(e.getX(), e.getY());
handleMouse(e);
}
@ -300,14 +290,18 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
if (state[OPEN] != INACTIVE) {
setState(OPEN, INACTIVE, true);
}
status = "";
handleMouse(e.getX(), e.getY());
handleMouse(e);
}
int wasDown = -1;
public void mousePressed(MouseEvent e) {
// jdf
if (!isEnabled())
return;
final int x = e.getX();
final int y = e.getY();
@ -331,8 +325,11 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
break;
case NEW:
//editor.base.handleNew(e.isShiftDown());
if (shiftPressed) {
editor.base.handleNew();
} else {
editor.base.handleNewReplace();
}
break;
case SAVE:
@ -353,84 +350,26 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
public void mouseClicked(MouseEvent e) { }
public void mouseReleased(MouseEvent e) {
/*
switch (currentSelection) {
case OPEN:
setState(OPEN, INACTIVE, true);
break;
}
currentSelection = -1;
*/
}
//public void disableRun(boolean what) {
//disableRun = what;
//}
/*
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 mouseReleased(MouseEvent e) { }
/**
* Set a particular button to be active.
*/
public void activate(int what) {
//System.out.println("activating " + what);
if (inactive == null) return;
if (buttonImages != null) {
setState(what, ACTIVE, true);
}
//public void clearRun() {
//if (inactive == null) return;
//setState(RUN, INACTIVE, true);
//}
}
/**
* Set a particular button to be active.
*/
public void deactivate(int what) {
if (inactive == null) return; // don't draw if not ready
if (buttonImages != null) {
setState(what, INACTIVE, true);
}
/**
* Clear all the state of all buttons.
*/
// public void clear() { // (int button) {
// if (inactive == null) return;
//
// System.out.println("clearing state of buttons");
// // 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 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 = "";
}
@ -447,4 +386,23 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
public Dimension getMaximumSize() {
return new Dimension(3000, BUTTON_HEIGHT);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
shiftPressed = true;
repaint();
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
shiftPressed = false;
repaint();
}
}
public void keyTyped(KeyEvent e) { }
}

View File

@ -26,6 +26,9 @@ import java.io.File;
import javax.swing.UIManager;
import com.sun.jna.Library;
import com.sun.jna.Native;
/**
* Used by Base for platform-specific tweaking, for instance finding the
@ -129,6 +132,36 @@ public class Platform {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
int setenv(String name, String value, int overwrite);
String getenv(String name);
int unsetenv(String name);
int putenv(String string);
}
public void setenv(String variable, String value) {
CLibrary clib = CLibrary.INSTANCE;
clib.setenv(variable, value, 1);
}
public String getenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.getenv(variable);
}
public int unsetenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.unsetenv(variable);
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected void showLauncherWarning() {
Base.showWarning("No launcher available",
"Unspecified platform, no launcher available.\n" +

View File

@ -626,6 +626,11 @@ public class Preferences {
}
static public void unset(String attribute) {
table.remove(attribute);
}
static public boolean getBoolean(String attribute) {
String value = get(attribute); //, null);
return (new Boolean(value)).booleanValue();

View File

@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-09 Ben Fry and Casey Reas
Copyright (c) 2004-10 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
@ -95,6 +95,9 @@ public class Sketch {
* DLLs or JNILIBs.
*/
private String libraryPath;
/**
* List of library folders.
*/
private ArrayList<File> importedLibraries;
/**
@ -1165,11 +1168,14 @@ public class Sketch {
* X. afterwards, some of these steps need a cleanup function
* </PRE>
*/
protected String compile(boolean verbose)
throws RunnerException {
String name;
//protected String compile() throws RunnerException {
/**
* When running from the editor, take care of preparations before running
* the build.
*/
public void prepare() {
// make sure the user didn't hide the sketch folder
ensureExistence();
@ -1199,11 +1205,8 @@ public class Sketch {
// better connected to the dataFolder stuff below.
cleanup();
// handle preprocessing the main file's code
name = build(tempBuildFolder.getAbsolutePath(), verbose);
size(tempBuildFolder.getAbsolutePath(), name);
return name;
// // handle preprocessing the main file's code
// return build(tempBuildFolder.getAbsolutePath());
}
@ -1255,14 +1258,6 @@ public class Sketch {
// 1. concatenate all .pde files to the 'main' pde
// store line number for starting point of each code bit
// Unfortunately, the header has to be written on a single line, because
// there's no way to determine how long it will be until the code has
// already been preprocessed. The header will vary in length based on
// the programming mode (STATIC, ACTIVE, or JAVA), which is determined
// by the preprocessor. So the preprocOffset for the primary class remains
// zero, even though it'd be nice to have a legitimate offset, and be able
// to remove the 'pretty' boolean for preproc.write().
StringBuffer bigCode = new StringBuffer();
int bigCount = 0;
for (SketchCode sc : code) {
@ -1271,29 +1266,9 @@ public class Sketch {
bigCode.append(sc.getProgram());
bigCode.append('\n');
bigCount += sc.getLineCount();
// if (sc != code[0]) {
// sc.setPreprocName(null); // don't compile me
// }
}
}
/*
String program = code[0].getProgram();
StringBuffer bigCode = new StringBuffer(program);
int bigCount = code[0].getLineCount();
bigCode.append('\n');
for (int i = 1; i < codeCount; i++) {
if (code[i].isExtension("pde")) {
code[i].setPreprocOffset(bigCount);
bigCode.append(code[i].getProgram());
bigCode.append('\n');
bigCount += code[i].getLineCount();
code[i].setPreprocName(null); // don't compile me
}
}
*/
// Note that the headerOffset isn't applied until compile and run, because
// it only applies to the code after it's been written to the .java file.
int headerOffset = 0;
@ -1391,6 +1366,134 @@ public class Sketch {
}
public ArrayList<File> getImportedLibraries() {
return importedLibraries;
}
/**
* Map an error from a set of processed .java files back to its location
* in the actual sketch.
* @param message The error message.
* @param filename The .java file where the exception was found.
* @param line Line number of the .java file for the exception (1-indexed)
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
// public RunnerException placeExceptionAlt(String message,
// String filename, int line) {
// String appletJavaFile = appletClassName + ".java";
// SketchCode errorCode = null;
// if (filename.equals(appletJavaFile)) {
// for (SketchCode code : getCode()) {
// if (code.isExtension("pde")) {
// if (line >= code.getPreprocOffset()) {
// errorCode = code;
// }
// }
// }
// } else {
// for (SketchCode code : getCode()) {
// if (code.isExtension("java")) {
// if (filename.equals(code.getFileName())) {
// errorCode = code;
// }
// }
// }
// }
// int codeIndex = getCodeIndex(errorCode);
//
// if (codeIndex != -1) {
// //System.out.println("got line num " + lineNumber);
// // in case this was a tab that got embedded into the main .java
// line -= getCode(codeIndex).getPreprocOffset();
//
// // lineNumber is 1-indexed, but editor wants zero-indexed
// line--;
//
// // getMessage() will be what's shown in the editor
// RunnerException exception =
// new RunnerException(message, codeIndex, line, -1);
// exception.hideStackTrace();
// return exception;
// }
// return null;
// }
/**
* Map an error from a set of processed .java files back to its location
* in the actual sketch.
* @param message The error message.
* @param filename The .java file where the exception was found.
* @param line Line number of the .java file for the exception (0-indexed!)
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
public RunnerException placeException(String message,
String dotJavaFilename,
int dotJavaLine) {
int codeIndex = 0; //-1;
int codeLine = -1;
// System.out.println("placing " + dotJavaFilename + " " + dotJavaLine);
// System.out.println("code count is " + getCodeCount());
// first check to see if it's a .java file
for (int i = 0; i < getCodeCount(); i++) {
SketchCode code = getCode(i);
if (code.isExtension("java")) {
if (dotJavaFilename.equals(code.getFileName())) {
codeIndex = i;
codeLine = dotJavaLine;
return new RunnerException(message, codeIndex, codeLine);
}
}
}
// If not the preprocessed file at this point, then need to get out
if (!dotJavaFilename.equals(name + ".java")) {
return null;
}
// if it's not a .java file, codeIndex will still be 0
// this section searches through the list of .pde files
codeIndex = 0;
for (int i = 0; i < getCodeCount(); i++) {
SketchCode code = getCode(i);
if (code.isExtension("pde")) {
// System.out.println("preproc offset is " + code.getPreprocOffset());
// System.out.println("looking for line " + dotJavaLine);
if (code.getPreprocOffset() <= dotJavaLine) {
codeIndex = i;
// System.out.println("i'm thinkin file " + i);
codeLine = dotJavaLine - code.getPreprocOffset();
}
}
}
// could not find a proper line number, so deal with this differently.
// but if it was in fact the .java file we're looking for, though,
// send the error message through.
// this is necessary because 'import' statements will be at a line
// that has a lower number than the preproc offset, for instance.
// if (codeLine == -1 && !dotJavaFilename.equals(name + ".java")) {
// return null;
// }
return new RunnerException(message, codeIndex, codeLine);
}
/**
* Run the build inside the temporary build folder.
* @return null if compilation failed, main class name if not
* @throws RunnerException
*/
public String build(boolean verbose) throws RunnerException {
return build(tempBuildFolder.getAbsolutePath(), verbose);
}
/**
* Preprocess and compile all the code for this sketch.
*
@ -1410,6 +1513,7 @@ public class Sketch {
// that will bubble up to whomever called build().
Compiler compiler = new Compiler();
if (compiler.compile(this, buildPath, primaryClassName, verbose)) {
size(buildPath, primaryClassName);
return primaryClassName;
}
return null;
@ -1500,7 +1604,7 @@ public class Sketch {
verbose);
return success ? suggestedClassName : null;
}
}
/**
* Replace all commented portions of a given String as spaces.
@ -1538,7 +1642,8 @@ public class Sketch {
break;
} else {
index++;
// continue blanking this area
p[index++] = ' ';
}
}
if (!endOfRainbow) {
@ -1562,8 +1667,8 @@ public class Sketch {
* Export to application via GUI.
*/
protected boolean exportApplication() throws IOException, RunnerException {
return false;
}
return false;
}
/**
@ -1571,8 +1676,8 @@ public class Sketch {
*/
public boolean exportApplication(String destPath,
int exportPlatform) throws IOException, RunnerException {
return false;
}
return false;
}
protected void addManifest(ZipOutputStream zos) throws IOException {
@ -1588,35 +1693,6 @@ public class Sketch {
}
/**
* Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #.
*/
protected HashMap<String,String> readSettings(File inputFile) {
HashMap<String,String> outgoing = new HashMap<String,String>();
if (!inputFile.exists()) return outgoing; // return empty hash
String lines[] = PApplet.loadStrings(inputFile);
for (int i = 0; i < lines.length; i++) {
int hash = lines[i].indexOf('#');
String line = (hash == -1) ?
lines[i].trim() : lines[i].substring(0, hash).trim();
if (line.length() == 0) continue;
int equals = line.indexOf('=');
if (equals == -1) {
System.err.println("ignoring illegal line in " + inputFile);
System.err.println(" " + line);
continue;
}
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
outgoing.put(attr, valu);
}
return outgoing;
}
/**
* Slurps up .class files from a colon (or semicolon on windows)
* separated list of paths and adds them to a ZipOutputStream.
@ -1923,11 +1999,6 @@ public class Sketch {
}
public ArrayList<File> getImportedLibraries() {
return importedLibraries;
}
public String getClassPath() {
return classPath;
}

View File

@ -0,0 +1,95 @@
/*
* @(#)StreamRedirectThread.java 1.4 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/*
* Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
package processing.app;
import java.io.*;
/**
* StreamRedirectThread is a thread which copies it's input to
* it's output and terminates when it completes.
*
* @version @(#) StreamRedirectThread.java 1.4 03/01/23 23:33:38
* @author Robert Field
*/
public class StreamRedirectThread extends Thread {
private final Reader in;
private final Writer out;
private static final int BUFFER_SIZE = 2048;
/**
* Set up for copy.
* @param name Name of the thread
* @param in Stream to copy from
* @param out Stream to copy to
*/
public StreamRedirectThread(String name, InputStream in, OutputStream out) {
super(name);
this.in = new InputStreamReader(in);
this.out = new OutputStreamWriter(out);
setPriority(Thread.MAX_PRIORITY-1);
}
public StreamRedirectThread(String name, Reader in, Writer out) {
super(name);
this.in = in;
this.out = out;
setPriority(Thread.MAX_PRIORITY-1);
}
/**
* Copy.
*/
public void run() {
try {
char[] cbuf = new char[BUFFER_SIZE];
int count;
//System.out.println("opening streamredirectthread");
while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
out.write(cbuf, 0, count);
// had to add the flush() here.. maybe shouldn't be using writer? [fry]
out.flush();
}
//System.out.println("exiting streamredirectthread");
out.flush();
} catch(IOException exc) {
System.err.println("Child I/O Transfer - " + exc);
}
}
}

View File

@ -8,8 +8,12 @@ import java.util.zip.*;
//import javax.swing.SwingUtilities;
/**
* An example of a very simple, multi-threaded HTTP server.
* Taken from <a href="http://java.sun.com/developer/technicalArticles/Networking/Webserver/">this</a> article on java.sun.com.
* This code is placed here in anticipation of running the reference from an
* internal web server that reads the docs from a zip file, instead of using
* thousands of .html files on the disk, which is really inefficient.
* <p/>
* This is a very simple, multi-threaded HTTP server, originally based on
* <a href="http://j.mp/6BQwpI">this</a> article on java.sun.com.
*/
public class WebServer implements HttpConstants {

View File

@ -65,7 +65,8 @@ public class EventThread extends Thread {
// Maps ThreadReference to ThreadTrace instances
private Map traceMap = new HashMap();
EventThread(Runner parent, VirtualMachine vm, String[] excludes, PrintWriter writer) {
public EventThread(Runner parent, VirtualMachine vm, String[] excludes, PrintWriter writer) {
super("event-handler");
this.parent = parent;
this.vm = vm;
@ -103,7 +104,7 @@ public class EventThread extends Thread {
* @param excludes Class patterns for which we don't want events
* @param watchFields Do we want to watch assignments to fields
*/
void setEventRequests(boolean watchFields) {
public void setEventRequests(boolean watchFields) {
EventRequestManager mgr = vm.eventRequestManager();
// VMDeathRequest deathReq = mgr.createVMDeathRequest();

View File

@ -29,7 +29,7 @@ import java.io.*;
/**
* Slurps up messages from compiler.
*/
class MessageSiphon implements Runnable {
public class MessageSiphon implements Runnable {
BufferedReader streamReader;
Thread thread;
MessageConsumer consumer;
@ -84,4 +84,9 @@ class MessageSiphon implements Runnable {
thread = null;
}
}
public Thread getThread() {
return thread;
}
}

View File

@ -24,6 +24,7 @@
package processing.app.debug;
import processing.app.*;
import processing.app.preproc.PdePreprocessor;
import processing.core.*;
import java.awt.Point;
@ -49,60 +50,54 @@ public class Runner implements MessageConsumer {
private boolean presenting;
// Object that listens for error messages or exceptions.
private RunnerListener listener;
protected RunnerListener listener;
// Running remote VM
private VirtualMachine vm;
protected VirtualMachine vm;
// Thread transferring remote error stream to our error stream
private Thread errThread = null;
protected Thread errThread = null;
// Thread transferring remote output stream to our output stream
private Thread outThread = null;
protected Thread outThread = null;
// Mode for tracing the Trace program (default= 0 off)
private int debugTraceMode = 0;
protected int debugTraceMode = 0;
// Do we want to watch assignments to fields
private boolean watchFields = false;
protected boolean watchFields = false;
// Class patterns for which we don't want events
private String[] excludes = {
protected String[] excludes = {
"java.*", "javax.*", "sun.*", "com.sun.*",
"apple.*",
"processing.*"
};
private RunnerException exception;
protected RunnerException exception;
//private PrintStream leechErr;
private Editor editor;
private Sketch sketch;
protected Editor editor;
protected Sketch sketch;
private String appletClassName;
// private boolean newMessage;
// private int messageLineCount;
// private boolean foundMessageSource;
//
// private SystemOutSiphon processInput;
// private OutputStream processOutput;
// private MessageSiphon processError;
public Runner(Sketch sketch, String appletClassName,
boolean presenting, RunnerListener listener) {
this.sketch = sketch;
this.appletClassName = appletClassName;
this.presenting = presenting;
public Runner(RunnerListener listener, Sketch sketch) {
this.listener = listener;
this.sketch = sketch;
if (listener instanceof Editor) {
this.editor = (Editor) listener;
// } else {
// System.out.println("actually it's a " + listener.getClass().getName());
}
}
public void launch() {
public void launch(String appletClassName, boolean presenting) {
this.appletClassName = appletClassName;
this.presenting = presenting;
// TODO entire class is a total mess as of release 0136.
// This will be cleaned up significantly over the next couple months.
@ -132,7 +127,7 @@ public class Runner implements MessageConsumer {
protected String[] getMachineParams() {
ArrayList params = new ArrayList();
ArrayList<String> params = new ArrayList<String>();
//params.add("-Xint"); // interpreted mode
//params.add("-Xprof"); // profiler
@ -203,6 +198,13 @@ public class Runner implements MessageConsumer {
protected String[] getSketchParams() {
ArrayList<String> params = new ArrayList<String>();
// It's dangerous to add your own main() to your code,
// but if you've done it, we'll respect your right to hang yourself.
// http://dev.processing.org/bugs/show_bug.cgi?id=1446
if (PdePreprocessor.foundMain) {
params.add(appletClassName);
} else {
params.add("processing.core.PApplet");
// If there was a saved location (this guy has been run more than once)
@ -242,6 +244,7 @@ public class Runner implements MessageConsumer {
}
params.add(appletClassName);
}
// String outgoing[] = new String[params.size()];
// params.toArray(outgoing);
@ -250,121 +253,11 @@ public class Runner implements MessageConsumer {
}
/*
protected VirtualMachine launchVirtualMachine_sun(String[] vmParams, String[] classParams) {
//vm = launchTarget(sb.toString());
LaunchingConnector connector =
findLaunchingConnector("com.sun.jdi.CommandLineLaunch");
//Map arguments = connectorArguments(connector, mainArgs);
PApplet.println(connector); // gets the defaults
Map arguments = connector.defaultArguments();
//System.out.println(arguments);
// for (Iterator itr = arguments.keySet().iterator(); itr.hasNext(); ) {
// Connector.Argument argument =
// (Connector.Argument) arguments.get(itr.next());
// System.out.println(argument);
// }
//connector.transport().
Connector.Argument mainArg =
(Connector.Argument)arguments.get("main");
if (mainArg == null) {
throw new Error("Bad launching connector");
}
String mainArgs = "";
//mainArgs = addArgument(mainArgs, className);
if (classParams != null) {
for (int i = 0; i < classParams.length; i++) {
mainArgs = addArgument(mainArgs, classParams[i], ' ');
}
}
mainArg.setValue(mainArgs);
//System.out.println("main args are: ");
//System.out.println(mainArgs);
// if (watchFields) {
// // We need a VM that supports watchpoints
// Connector.Argument optionArg =
// (Connector.Argument)arguments.get("options");
// if (optionArg == null) {
// throw new Error("Bad launching connector");
// }
// optionArg.setValue("-classic");
// }
String optionArgs = "";
for (int i = 0; i < vmParams.length; i++) {
optionArgs = addArgument(optionArgs, vmParams[i], ' ');
}
// prevent any incorrect transport address b.s. from being added
// -Xrunjdwp:transport=dt_socket,address=cincinnati118.ipcorporate.com:55422,suspend=y
//optionArgs = addArgument(optionArgs, "-agentlib:jdwp=transport=dt_socket,address=localhost:12345,suspend=y", ' ');
//optionArgs += " -Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y";
//optionArgs = optionArgs + " -agentlib:jdwp=transport=dt_socket";
//optionArgs = addArgument(optionArgs, "-Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y", ' ');
//optionArgs = addArgument(optionArgs, "address=127.0.0.1:54321", ' ');
//optionArgs = addArgument(optionArgs, "localAddress", ' ');
Connector.Argument optionArg =
(Connector.Argument)arguments.get("options");
optionArg.setValue(optionArgs);
// Connector.Argument addressArg =
// (Connector.Argument)arguments.get("address");
//arguments.put("raw.address", new Connector.Argument("blah"));
//PApplet.println("it's gonna be " + addressArg);
//arguments.put("address", "localhost");
// Connector.Argument addressArg =
// (Connector.Argument)arguments.get("address");
// addressArg.setValue("localhost");
// System.out.println("option args are: ");
// System.out.println(arguments.get("options"));
System.out.println("args are " + arguments);
// com.sun.tools.jdi.SunCommandLineLauncher
// http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#sunlaunch
try {
return connector.launch(arguments);
} catch (IOException exc) {
throw new Error("Unable to launch target VM: " + exc);
} catch (IllegalConnectorArgumentsException exc) {
throw new Error("Internal error: " + exc);
} catch (VMStartException exc) {
exc.printStackTrace();
System.err.println();
System.err.println("Could not run the sketch.");
System.err.println("Make sure that you haven't set the maximum available memory too high.");
System.err.println("For more information, read revisions.txt and Help -> Troubleshooting.");
//System.err.println("Target VM failed to initialize:");
//System.err.println("msg is " + exc.getMessage());
//exc.printStackTrace();
//throw new Error("Target VM failed to initialize: " +
//exc.getMessage());
//throw new Error(exc.getMessage());
//throw new RunnerException(exc.getMessage());
//editor.error(exc);
editor.error("Could not run the sketch.");
return null;
}
}
*/
protected VirtualMachine launchVirtualMachine(String[] vmParams,
String[] classParams) {
//vm = launchTarget(sb.toString());
LaunchingConnector connector =
findLaunchingConnector("com.sun.jdi.RawCommandLineLaunch");
LaunchingConnector connector = (LaunchingConnector)
findConnector("com.sun.jdi.RawCommandLineLaunch");
//PApplet.println(connector); // gets the defaults
//Map arguments = connectorArguments(connector, mainArgs);
@ -447,9 +340,10 @@ public class Runner implements MessageConsumer {
}
System.err.println("For more information, read revisions.txt and Help \u2192 Troubleshooting.");
}
if (editor != null) {
// changing this to separate editor and listener [091124]
//if (editor != null) {
listener.statusError("Could not run the sketch.");
}
//}
return null;
}
}
@ -493,7 +387,7 @@ public class Runner implements MessageConsumer {
* start threads to forward remote error and output streams,
* resume the remote VM, wait for the final event, and shutdown.
*/
void generateTrace(PrintWriter writer) {
protected void generateTrace(PrintWriter writer) {
vm.setDebugTraceMode(debugTraceMode);
EventThread eventThread = null;
@ -515,7 +409,7 @@ public class Runner implements MessageConsumer {
// process.getErrorStream(),
// System.err);
MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this);
errThread = ms.thread;
errThread = ms.getThread();
outThread = new StreamRedirectThread("output reader",
process.getInputStream(),
@ -545,7 +439,6 @@ public class Runner implements MessageConsumer {
if (editor != null) {
editor.internalRunnerClosed();
}
} catch (InterruptedException exc) {
// we don't interrupt
}
@ -554,20 +447,10 @@ public class Runner implements MessageConsumer {
}
/**
* Find a com.sun.jdi.CommandLineLaunch connector
*/
LaunchingConnector findLaunchingConnector(String connectorName) {
//VirtualMachineManager mgr = Bootstrap.virtualMachineManager();
// Get the default connector.
// Not useful here since they all need different args.
// System.out.println(Bootstrap.virtualMachineManager().defaultConnector());
// return Bootstrap.virtualMachineManager().defaultConnector();
protected Connector findConnector(String connectorName) {
List connectors = Bootstrap.virtualMachineManager().allConnectors();
// code to list available connectors
// debug: code to list available connectors
// Iterator iter2 = connectors.iterator();
// while (iter2.hasNext()) {
// Connector connector = (Connector)iter2.next();
@ -578,10 +461,10 @@ public class Runner implements MessageConsumer {
while (iter.hasNext()) {
Connector connector = (Connector)iter.next();
if (connector.name().equals(connectorName)) {
return (LaunchingConnector)connector;
return connector;
}
}
throw new Error("No launching connector");
throw new Error("No connector");
}
@ -611,7 +494,17 @@ public class Runner implements MessageConsumer {
// System.out.println(or.referenceType().fields());
// if (name.startsWith("java.lang.")) {
// name = name.substring(10);
if (exceptionName.equals("java.lang.OutOfMemoryError")) {
if (!handleCommonErrors(exceptionName, message, listener)) {
reportException(message, event.thread());
}
if (editor != null) {
editor.internalRunnerClosed();
}
}
public static boolean handleCommonErrors(final String exceptionClass, final String message, final RunnerListener listener)
{
if (exceptionClass.equals("java.lang.OutOfMemoryError")) {
listener.statusError("OutOfMemoryError: You may need to increase the memory setting in Preferences.");
System.err.println("An OutOfMemoryError means that your code is either using up too much memory");
System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally");
@ -619,96 +512,83 @@ public class Runner implements MessageConsumer {
System.err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)");
System.err.println("you can increase the memory available to your sketch using the Preferences window.");
} else if (exceptionName.equals("java.lang.StackOverflowError")) {
} else if (exceptionClass.equals("java.lang.StackOverflowError")) {
listener.statusError("StackOverflowError: This sketch is attempting too much recursion.");
System.err.println("A StackOverflowError means that you have a bug that's causing a function");
System.err.println("to be called recursively (it's calling itself and going in circles),");
System.err.println("or you're intentionally calling a recursive function too much,");
System.err.println("and your code should be rewritten in a more efficient manner.");
} else if (exceptionName.equals("java.lang.UnsupportedClassVersionError")) {
} else if (exceptionClass.equals("java.lang.UnsupportedClassVersionError")) {
listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java.");
System.err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.5.");
System.err.println("A library used by this sketch was compiled for Java 1.6 or later, ");
System.err.println("and needs to be recompiled to be compatible with Java 1.5.");
} else if (exceptionName.equals("java.lang.NoSuchMethodError") || exceptionName.equals("java.lang.NoSuchFieldError")) {
listener.statusError(exceptionName.substring(10) + ": You're probably using a library that's incompatible with this version of Processing.");
} else if (message.equals("ClassNotFoundException: quicktime.std.StdQTException")) {
listener.statusError("Could not find QuickTime, please reinstall QuickTime 7 or later.");
} else if (exceptionClass.equals("java.lang.NoSuchMethodError") || exceptionClass.equals("java.lang.NoSuchFieldError")) {
listener.statusError(exceptionClass.substring(10) + ": You're probably using a library that's incompatible with this version of Processing.");
} else if (message!=null &&
message.equals("ClassNotFoundException: quicktime.std.StdQTException")) {
listener
.statusError("Could not find QuickTime, please reinstall QuickTime 7 or later.");
} else {
reportException(message, event.thread());
return false;
}
editor.internalRunnerClosed();
return true;
}
// This may be called more than one time per error in the VM,
// TODO: This may be called more than one time per error in the VM,
// presumably because exceptions might be wrapped inside others,
// and this will fire for both.
protected void reportException(String message, ThreadReference thread) {
try {
int codeIndex = -1;
int lineNumber = -1;
listener.statusError(findException(message, thread));
}
/**
* Move through a list of stack frames, searching for references to code
* found in the current sketch. Return with a RunnerException that contains
* the location of the error, or if nothing is found, just return with a
* RunnerException that wraps the error message itself.
*/
RunnerException findException(String message, ThreadReference thread) {
try {
// use to dump the stack for debugging
// for (StackFrame frame : thread.frames()) {
// System.out.println("frame: " + frame);
// }
// Any of the thread.blah() methods can throw an AbsentInformationEx
// if that bit of data is missing. If so, just write out the error
// message to the console.
List<StackFrame> frames = thread.frames();
for (StackFrame frame : frames) {
// System.out.println("frame: " + frame);
try {
Location location = frame.location();
String filename = null;
filename = location.sourceName();
lineNumber = location.lineNumber();
String appletJavaFile = appletClassName + ".java";
SketchCode errorCode = null;
if (filename.equals(appletJavaFile)) {
for (SketchCode code : sketch.getCode()) {
if (code.isExtension("pde")) {
if (lineNumber >= code.getPreprocOffset()) {
errorCode = code;
int lineNumber = location.lineNumber() - 1;
RunnerException rex =
sketch.placeException(message, filename, lineNumber);
if (rex != null) {
return rex;
}
}
}
} else {
for (SketchCode code : sketch.getCode()) {
if (code.isExtension("java")) {
if (filename.equals(code.getFileName())) {
errorCode = code;
}
}
}
}
codeIndex = sketch.getCodeIndex(errorCode);
if (codeIndex != -1) {
//System.out.println("got line num " + lineNumber);
// in case this was a tab that got embedded into the main .java
lineNumber -= sketch.getCode(codeIndex).getPreprocOffset();
// lineNumber is 1-indexed, but editor wants zero-indexed
lineNumber--;
// getMessage() will be what's shown in the editor
exception = new RunnerException(message, codeIndex, lineNumber, -1);
exception.hideStackTrace();
listener.statusError(exception);
return;
}
}
} catch (AbsentInformationException e) {
// Any of the thread.blah() methods can throw an AbsentInformationEx
// if that bit of data is missing. If so, just write out the error
// message to the console.
//e.printStackTrace(); // not useful
exception = new RunnerException(message);
exception.hideStackTrace();
listener.statusError(exception);
}
}
} catch (IncompatibleThreadStateException e) {
// This shouldn't happen, but if it does, print the exception in case
// it's something that needs to be debugged separately.
e.printStackTrace();
}
// Give up, nothing found inside the pile of stack frames
RunnerException rex = new RunnerException(message);
// exception is being created /here/, so stack trace is not useful
rex.hideStackTrace();
return rex;
}
@ -727,26 +607,7 @@ public class Runner implements MessageConsumer {
}
vm = null;
}
//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
@ -762,7 +623,10 @@ public class Runner implements MessageConsumer {
// that signals that the applet has been quit.
if (s.indexOf(PApplet.EXTERNAL_STOP) == 0) {
//System.out.println("external: quit");
editor.internalCloseRunner();
if (editor != null) {
//editor.internalCloseRunner(); // [091124]
editor.handleStop();
}
return;
}
@ -773,281 +637,23 @@ public class Runner implements MessageConsumer {
int space = nums.indexOf(' ');
int left = Integer.parseInt(nums.substring(0, space));
int top = Integer.parseInt(nums.substring(space + 1));
// this is only fired when connected to an editor
editor.setSketchLocation(new Point(left, top));
//System.out.println("external: move to " + left + " " + top);
return;
}
// Removed while doing cleaning for 0145,
// it seems that this is never actually printed out.
/*
// 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);
}
*/
// 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();
// //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 atIndex = s.indexOf("at ");
// if (atIndex == -1) {
// //System.err.println(s); // stop double-printing exceptions
// return;
// }
// s = s.substring(atIndex + 3);
//
// // added for 0124 to improve error handling
// // not highlighting lines if it's in the p5 code
// if (s.startsWith("processing.")) return;
// // no highlight if it's java.lang.whatever
// if (s.startsWith("java.")) return;
//
// // "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.getCodeCount(); i++) {
// SketchCode code = sketch.getCode(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) {
// //System.out.println("got line num " + lineNumber);
// // in case this was a tab that got embedded into the main .java
// lineNumber -= sketch.getCode(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();
// 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();
// 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;
}
}
}
}

View File

@ -37,10 +37,18 @@ public class RunnerException extends Exception /*RuntimeException*/ {
public RunnerException(String message) {
this(message, -1, -1, -1, true);
this(message, true);
}
public RunnerException(String message, boolean showStackTrace) {
this(message, -1, -1, -1, showStackTrace);
}
public RunnerException(String message, int file, int line) {
this(message, file, line, -1, true);
}
public RunnerException(String message, int file, int line, int column) {
this(message, file, line, column, true);
}

View File

@ -28,4 +28,6 @@ public interface RunnerListener {
public void statusError(String message);
public void statusError(Exception exception);
public void statusNotice(String message);
}

View File

@ -67,10 +67,18 @@ public class Platform extends processing.app.Platform {
return true;
}
// Attempt to use xdg-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "xdg-open" });
p.waitFor();
Preferences.set("launcher", "xdg-open");
return true;
} catch (Exception e) { }
// Attempt to use gnome-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
/*int result =*/ p.waitFor();
p.waitFor();
// Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
Preferences.set("launcher", "gnome-open");
return true;
@ -79,7 +87,7 @@ public class Platform extends processing.app.Platform {
// Attempt with kde-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
/*int result =*/ p.waitFor();
p.waitFor();
Preferences.set("launcher", "kde-open");
return true;
} catch (Exception e) { }
@ -100,7 +108,8 @@ public class Platform extends processing.app.Platform {
e.printStackTrace();
}
} else {
System.out.println("not available");
System.out.println("No launcher set, cannot open " +
file.getAbsolutePath());
}
}
}

View File

@ -25,12 +25,15 @@ package processing.app.macosx;
import java.awt.Insets;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.net.URI;
import javax.swing.UIManager;
import com.apple.eio.FileManager;
import processing.app.Base;
import processing.core.PApplet;
/**
@ -103,36 +106,45 @@ public class Platform extends processing.app.Platform {
public void openURL(String url) throws Exception {
if (!url.startsWith("http://")) {
if (PApplet.javaVersion < 1.6f) {
if (url.startsWith("http://")) {
// formerly com.apple.eio.FileManager.openURL(url);
// but due to deprecation, instead loading dynamically
try {
Class<?> eieio = Class.forName("com.apple.eio.FileManager");
Method openMethod =
eieio.getMethod("openURL", new Class[] { String.class });
openMethod.invoke(null, new Object[] { url });
} catch (Exception e) {
e.printStackTrace();
}
} else {
// Assume this is a file instead, and just open it.
// Extension of http://dev.processing.org/bugs/show_bug.cgi?id=1010
processing.core.PApplet.open(url);
/*
// prepend file:// on this guy since it's a file
url = "file://" + url;
// replace spaces with %20 for the file url
// otherwise the mac doesn't like to open it
// can't just use URLEncoder, since that makes slashes into
// %2F characters, which is no good. some might say "useless"
if (url.indexOf(' ') != -1) {
StringBuffer sb = new StringBuffer();
char c[] = url.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == ' ') {
sb.append("%20");
} else {
sb.append(c[i]);
}
}
url = sb.toString();
}
*/
} else {
try {
Class<?> desktopClass = Class.forName("java.awt.Desktop");
Method getMethod = desktopClass.getMethod("getDesktop");
Object desktop = getMethod.invoke(null, new Object[] { });
// for Java 1.6, replacing with java.awt.Desktop.browse()
// and java.awt.Desktop.open()
if (url.startsWith("http://")) { // browse to a location
Method browseMethod =
desktopClass.getMethod("browse", new Class[] { URI.class });
browseMethod.invoke(desktop, new Object[] { new URI(url) });
} else { // open a file
Method openMethod =
desktopClass.getMethod("open", new Class[] { File.class });
openMethod.invoke(desktop, new Object[] { new File(url) });
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// for Java 1.6, replace with java.awt.Desktop.browse() and java.awt.Desktop.open()
com.apple.eio.FileManager.openURL(url);
}
public boolean openFolderAvailable() {

View File

@ -50,7 +50,8 @@ public class ThinkDifferent implements ApplicationListener {
static protected void init(Base base) {
if (application == null) {
application = new com.apple.eawt.Application();
//application = new com.apple.eawt.Application();
application = com.apple.eawt.Application.getApplication();
}
if (adapter == null) {
adapter = new ThinkDifferent(base);

View File

@ -51,15 +51,9 @@ public class PdePreprocessor {
List prototypes;
String[] defaultImports;
// these ones have the .* at the end, since a class name might be at the end
// instead of .* which would make trouble other classes using this can lop
// off the . and anything after it to produce a package name consistently.
//public String extraImports[];
ArrayList<String> programImports;
// imports just from the code folder, treated differently
@ -71,24 +65,24 @@ public class PdePreprocessor {
PrintStream stream;
String program;
String buildPath;
// starts as sketch name, ends as main class name
String name;
/**
* Setup a new preprocessor.
*/
public PdePreprocessor() { }
public int writePrefix(String program, String buildPath,
String name, String codeFolderPackages[])
throws FileNotFoundException {
this.buildPath = buildPath;
this.name = name;
public PdePreprocessor() {
int tabSize = Preferences.getInteger("editor.tabs.size");
char[] indentChars = new char[tabSize];
Arrays.fill(indentChars, ' ');
indent = new String(indentChars);
}
public int writePrefix(String program, String buildPath,
String sketchName, String codeFolderPackages[]) throws FileNotFoundException {
this.buildPath = buildPath;
this.name = sketchName;
// 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:
@ -99,52 +93,13 @@ public class PdePreprocessor {
// an OutOfMemoryError or NullPointerException will happen.
// again, not gonna bother tracking this down, but here's a hack.
// http://dev.processing.org/bugs/show_bug.cgi?id=16
Sketch.scrubComments(program);
// this returns the scrubbed version, but more important for this
// function, it'll check to see if there are errors with the comments.
String scrubbed = Sketch.scrubComments(program);
// If there are errors, an exception is thrown and this fxn exits.
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);
}
program = substituteUnicode(program);
}
// These may change in-between (if the prefs panel adds this option)
// so grab them here on construction.
String prefsLine = Preferences.get("preproc.imports");
defaultImports = PApplet.splitTokens(prefsLine, ", ");
//String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)";
String importRegexp = "^\\s*#include\\s+[<\"](\\S+)[\">]";
programImports = new ArrayList<String>();
@ -184,8 +139,47 @@ public class PdePreprocessor {
return headerCount + prototypeCount;
}
static String substituteUnicode(String program) {
// 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);
}
return program;
}
/**
* preprocesses a pde file and write out a java file
* preprocesses a pde file and writes out a java file
* @return the classname of the exported Java
*/
//public String write(String program, String buildPath, String name,

View File

@ -24,7 +24,7 @@ import java.util.*;
* to the implementations of this class to do so.
*
* @author Slava Pestov
* @version $Id: InputHandler.java 4168 2008-08-09 17:24:37Z fry $
* @version $Id: InputHandler.java 6126 2010-02-16 23:43:53Z fry $
*/
public abstract class InputHandler extends KeyAdapter
{
@ -70,6 +70,9 @@ public abstract class InputHandler extends KeyAdapter
public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
public static final ActionListener REPEAT = new repeat();
public static final ActionListener TOGGLE_RECT = new toggle_rect();
public static final ActionListener CLIPBOARD_CUT = new clipboard_cut(); // [fry]
public static final ActionListener CLIPBOARD_COPY = new clipboard_copy();
public static final ActionListener CLIPBOARD_PASTE = new clipboard_paste();
// Default action
public static final ActionListener INSERT_CHAR = new insert_char();
@ -113,6 +116,9 @@ public abstract class InputHandler extends KeyAdapter
actions.put("repeat",REPEAT);
actions.put("toggle-rect",TOGGLE_RECT);
actions.put("insert-char",INSERT_CHAR);
actions.put("clipboard-cut",CLIPBOARD_CUT);
actions.put("clipboard-copy",CLIPBOARD_COPY);
actions.put("clipboard-paste",CLIPBOARD_PASTE);
}
/**
@ -1077,6 +1083,34 @@ public abstract class InputHandler extends KeyAdapter
}
}
public static class clipboard_cut implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).cut();
}
}
public static class clipboard_copy implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).copy();
}
}
public static class clipboard_paste implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).paste();
}
}
public static class insert_char implements ActionListener,
InputHandler.NonRepeatable
{

View File

@ -22,6 +22,9 @@ import java.awt.event.*;
import java.awt.*;
import java.util.Enumeration;
import java.util.Vector;
import java.awt.im.InputMethodRequests;
import processing.app.syntax.im.InputMethodSupport;
/**
* jEdit's text area component. It is more suited for editing program
@ -51,7 +54,7 @@ import java.util.Vector;
* + "}");</pre>
*
* @author Slava Pestov
* @version $Id: JEditTextArea.java 5625 2009-06-07 21:08:59Z fry $
* @version $Id: JEditTextArea.java 6123 2010-02-16 21:43:44Z fry $
*/
public class JEditTextArea extends JComponent
{
@ -127,6 +130,16 @@ public class JEditTextArea extends JComponent
});
}
/**
* Inline Input Method Support for Japanese.
*/
private InputMethodSupport inputMethodSupport = null;
public InputMethodRequests getInputMethodRequests() {
if (inputMethodSupport == null) {
inputMethodSupport = new InputMethodSupport(this);
}
return inputMethodSupport;
}
/**
* Get current position of the vertical scroll bar. [fry]

View File

@ -34,18 +34,22 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
inputHandler = new DefaultInputHandler();
//inputHandler.addDefaultKeyBindings(); // 0122
// use option on mac for things that are ctrl on windows/linux
// use option on mac for text edit controls that are ctrl on windows/linux
String mod = Base.isMacOS() ? "A" : "C";
// right now, ctrl-up/down is select up/down, but mod should be
// used instead, because the mac expects it to be option(alt)
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
// for 0122, shift-backspace is delete, for 0176, it's now a preference,
// to prevent holy warriors from attacking me for it.
if (Preferences.getBoolean("editor.keys.shift_backspace_is_delete")) {
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
} else {
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
}
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
//inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
// for 0122, shift-backspace is delete
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
// the following two were changing for 0122 for better mac/pc compatability
@ -57,12 +61,23 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
//inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
// http://dev.processing.org/bugs/show_bug.cgi?id=162
// added for 0176, though the bindings do not appear relevant for osx
if (Preferences.getBoolean("editor.keys.alternative_cut_copy_paste")) {
inputHandler.addKeyBinding("C+INSERT", InputHandler.CLIPBOARD_COPY);
inputHandler.addKeyBinding("S+INSERT", InputHandler.CLIPBOARD_PASTE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.CLIPBOARD_CUT);
}
// disabling for 0122, not sure what this does
//inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
// for 0122, these have been changed for better compatability
// for 0122, these have been changed for better compatibility
// HOME and END now mean the beginning/end of the document
if (Base.isMacOS()) {
// for 0176 changed this to a preference so that the Mac OS X people
// can get the "normal" behavior as well if they prefer.
if (Preferences.getBoolean("editor.keys.home_and_end_travel_far")) {
inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);

View File

@ -12,6 +12,7 @@
package processing.app.syntax;
import processing.app.*;
import processing.app.syntax.im.CompositionTextPainter;
import javax.swing.ToolTipManager;
import javax.swing.text.*;
@ -33,6 +34,9 @@ implements TabExpander, Printable
/** Current setting for editor.antialias preference */
boolean antialias;
/** A specific painter composed by the InputMethod.*/
protected CompositionTextPainter compositionTextPainter;
/**
* Creates a new repaint manager. This should be not be called
* directly.
@ -73,6 +77,16 @@ implements TabExpander, Printable
eolMarkers = defaults.eolMarkers;
}
/**
* Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
*/
public CompositionTextPainter getCompositionTextpainter(){
if(compositionTextPainter == null){
compositionTextPainter = new CompositionTextPainter(textArea);
}
return compositionTextPainter;
}
/**
* Returns if this component can be traversed by pressing the
* Tab key. This returns false.
@ -602,7 +616,12 @@ implements TabExpander, Printable
y += fm.getHeight();
x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) {
gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y);
@ -625,7 +644,12 @@ implements TabExpander, Printable
x = SyntaxUtilities.paintSyntaxLine(currentLine,
currentLineTokens,
styles, this, gfx, x, y);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) {
gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y);

View File

@ -0,0 +1,187 @@
package processing.app.syntax.im;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.text.BadLocationException;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* This class Manage texts from input method
* by begin-process-end steps.
*
* First, if a user start inputing via input method,
* beginCompositionText is called from InputMethodSupport.
* Second, the user continues from input method, processCompositionText is called
* and reflect user inputs to text area.
* Finally the user try to commit text, endCompositionText is called.
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextManager {
private JEditTextArea textArea;
private String prevComposeString;
private int prevCommittedCount;
private boolean isInputProcess;
private int initialCaretPosition;
public static final int COMPOSING_UNDERBAR_HEIGHT = 5;
/**
* Create text manager class with a textarea.
* @param textArea texarea component for PDE.
*/
public CompositionTextManager(JEditTextArea textArea) {
this.textArea = textArea;
prevComposeString = "";
isInputProcess = false;
prevCommittedCount = 0;
}
/**
* Get this text manager is whether in input process or not.
*/
public boolean getIsInputProcess() {
return isInputProcess;
}
/**
* Called when a user begins input from input method.
* This method initializes text manager.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void beginCompositionText(AttributedCharacterIterator text, int committed_count) {
isInputProcess = true;
prevComposeString = "";
initialCaretPosition = textArea.getCaretPosition();
processCompositionText(text, committed_count);
}
/**
* Called when a user processing input characters and
* select candidates from input method.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
int layoutCaretPosition = initialCaretPosition + committed_count;
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition);
int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
char c;
for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE
&& textLength > 0; c = text.next(), --textLength) {
unCommitedStringBuf.append(c);
}
String unCommittedString = unCommitedStringBuf.toString();
try {
if(canRemovePreviousInput(committed_count)){
textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
}
textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
if(committed_count > 0){
initialCaretPosition = initialCaretPosition + committed_count;
}
prevComposeString = unCommittedString;
prevCommittedCount = committed_count;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private boolean canRemovePreviousInput(int committed_count){
return (prevCommittedCount == committed_count || prevCommittedCount > committed_count);
}
/**
* Called when a user fixed text from input method or delete all
* composition text. This method resets CompositionTextPainter.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void endCompositionText(AttributedCharacterIterator text, int committed_count) {
isInputProcess = false;
/*
* If there are no committed characters, remove it all from textarea.
* This case will happen if a user delete all composing characters by backspace or delete key.
* If it does, these previous characters are needed to be deleted.
*/
if(committed_count == 0){
removeNotCommittedText(text);
}
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count);
prevComposeString = "";
isInputProcess = false;
}
private void removeNotCommittedText(AttributedCharacterIterator text){
if (prevComposeString.length() == 0) {
return;
}
try {
textArea.getDocument().remove(initialCaretPosition, prevComposeString.length());
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) {
AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex());
Font font = textArea.getPainter().getFont();
FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext();
composed.addAttribute(TextAttribute.FONT, font);
TextLayout layout = new TextLayout(composed.getIterator(), context);
return layout;
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = textArea.getCaretPosition()
- textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
public Rectangle getTextLocation() {
Point caret = getCaretLocation();
return getCaretRectangle(caret.x, caret.y);
}
private Rectangle getCaretRectangle(int x, int y) {
TextAreaPainter painter = textArea.getPainter();
Point origin = painter.getLocationOnScreen();
int height = painter.getFontMetrics().getHeight();
return new Rectangle(origin.x + x, origin.y + y, 0, height);
}
public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) {
int length = endIndex - beginIndex;
String textAreaString = textArea.getText(beginIndex, length);
return new AttributedString(textAreaString).getIterator();
}
public int getInsertPositionOffset() {
return textArea.getCaretPosition() * -1;
}
}

View File

@ -0,0 +1,124 @@
package processing.app.syntax.im;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.font.TextLayout;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* Paint texts from input method. Text via input method are transmitted by
* AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
* to handle AttributedCaharacterIterator.
*
* For practical purposes, paint to textarea is done by TextLayout class.
* Because TextLayout class is easy to draw composing texts. (For example,
* draw underline composing texts, focus when select from candidates text.)
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextPainter {
private TextLayout composedTextLayout;
private int composedBeginCaretPosition = 0;
private JEditTextArea textArea;
/**
* Constructor for painter.
* @param textarea textarea used by PDE.
*/
public CompositionTextPainter(JEditTextArea textArea) {
this.textArea = textArea;
composedTextLayout = null;
}
/**
* Check the painter has TextLayout.
* If a user input via InputMethod, this result will return true.
* @param textarea textarea used by PDE.
*/
public boolean hasComposedTextLayout() {
return (composedTextLayout != null);
}
/**
* Set TextLayout to the painter.
* TextLayout will be created and set by CompositionTextManager.
*
* @see CompositionTextManager
* @param textarea textarea used by PDE.
*/
public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
this.composedTextLayout = composedTextLayout;
this.composedBeginCaretPosition = composedStartCaretPosition;
}
/**
* Invalidate this TextLayout to set null.
* If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
*/
public void invalidateComposedTextLayout(int composedEndCaretPosition) {
this.composedTextLayout = null;
this.composedBeginCaretPosition = composedEndCaretPosition;
//this.composedBeginCaretPosition = textArea.getCaretPosition();
}
/**
* Draw text via input method with composed text information.
* This method can draw texts with some underlines to illustrate converting characters.
*
* This method is workaround for TextAreaPainter.
* Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
* AttributedCharacterIterator has very important information when composing text.
* It has a map where are converted characters and committed characters.
* Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
* So I choose to write some code as a workaround.
*
* This draw method is proceeded with the following steps.
* 1. Original TextAreaPainter draws characters.
* 2. This refillComposedArea method erase previous paint characters by textarea's background color.
* The refill area is only square that width and height defined by characters with input method.
* 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
*
* @param gfx set TextAreaPainter's Graphics object.
* @param fillBackGroundColor set textarea's background.
*/
public void draw(Graphics gfx, Color fillBackGroundColor) {
assert(composedTextLayout != null);
Point composedLoc = getCaretLocation();
refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
}
/**
* Fill color to erase characters drawn by original TextAreaPainter.
*
* @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
* @param x x-coordinate where to fill.
* @param y y-coordinate where to fill.
*/
private void refillComposedArea(Color fillColor, int x, int y) {
Graphics gfx = textArea.getPainter().getGraphics();
gfx.setColor(fillColor);
FontMetrics fm = textArea.getPainter().getFontMetrics();
int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
int paintHeight = fm.getHeight();
int paintWidth = (int) composedTextLayout.getBounds().getWidth();
gfx.fillRect(x, newY, paintWidth, paintHeight);
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
}

View File

@ -0,0 +1,105 @@
package processing.app.syntax.im;
import java.awt.Rectangle;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.font.TextHitInfo;
import java.awt.im.InputMethodRequests;
import java.text.AttributedCharacterIterator;
import processing.app.syntax.JEditTextArea;
/**
* Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more)
* This class is implemented by Java Input Method Framework and handles
* If you would like to know more about Java Input Method Framework,
* Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/
*
* This class is implemented to fix Bug #854.
* http://dev.processing.org/bugs/show_bug.cgi?id=854
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class InputMethodSupport implements InputMethodRequests,
InputMethodListener {
private int committed_count = 0;
private CompositionTextManager textManager;
public InputMethodSupport(JEditTextArea textArea) {
textManager = new CompositionTextManager(textArea);
textArea.enableInputMethods(true);
textArea.addInputMethodListener(this);
}
public Rectangle getTextLocation(TextHitInfo offset) {
return textManager.getTextLocation();
}
public TextHitInfo getLocationOffset(int x, int y) {
return null;
}
public int getInsertPositionOffset() {
return textManager.getInsertPositionOffset();
}
public AttributedCharacterIterator getCommittedText(int beginIndex,
int endIndex, AttributedCharacterIterator.Attribute[] attributes) {
return textManager.getCommittedText(beginIndex, endIndex);
}
public int getCommittedTextLength() {
return committed_count;
}
public AttributedCharacterIterator cancelLatestCommittedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
public AttributedCharacterIterator getSelectedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
/**
* Handles events from InputMethod.
* This method judges whether beginning of input or
* progress of input or end and call related method.
*
* @param event event from Input Method.
*/
public void inputMethodTextChanged(InputMethodEvent event) {
AttributedCharacterIterator text = event.getText();
committed_count = event.getCommittedCharacterCount();
if(isBeginInputProcess(text, textManager)){
textManager.beginCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
if (isInputProcess(text)){
textManager.processCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
textManager.endCompositionText(text, committed_count);
caretPositionChanged(event);
}
private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){
if(text == null)
return false;
return (isInputProcess(text) && !textManager.getIsInputProcess());
}
private boolean isInputProcess(AttributedCharacterIterator text){
if(text == null)
return false;
return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0);
}
public void caretPositionChanged(InputMethodEvent event) {
event.consume();
}
}

View File

@ -120,6 +120,7 @@ public class ColorSelector implements Tool, DocumentListener {
frame.setVisible(false);
}
});
Base.setIcon(frame);
hueField.getDocument().addDocumentListener(this);
@ -444,19 +445,25 @@ public class ColorSelector implements Tool, DocumentListener {
}
public Dimension getPreferredSize() {
//System.out.println("getting pref " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public Dimension getMinimumSize() {
//System.out.println("getting min " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public Dimension getMaximumSize() {
//System.out.println("getting max " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public void keyPressed() {
if (key == ESC) {
ColorSelector.this.frame.setVisible(false);
// don't quit out of processing
// http://dev.processing.org/bugs/show_bug.cgi?id=1006
key = 0;
}
}
}
@ -506,19 +513,25 @@ public class ColorSelector implements Tool, DocumentListener {
}
public Dimension getPreferredSize() {
//System.out.println("s getting pref " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public Dimension getMinimumSize() {
//System.out.println("s getting min " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public Dimension getMaximumSize() {
//System.out.println("s getting max " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH);
}
public void keyPressed() {
if (key == ESC) {
ColorSelector.this.frame.setVisible(false);
// don't quit out of processing
// http://dev.processing.org/bugs/show_bug.cgi?id=1006
key = 0;
}
}
}
@ -540,7 +553,7 @@ public class ColorSelector implements Tool, DocumentListener {
public Dimension getPreferredSize() {
if (!allowHex) {
return new Dimension(35, super.getPreferredSize().height);
return new Dimension(45, super.getPreferredSize().height);
}
return super.getPreferredSize();
}

View File

@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2004-10 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
@ -37,7 +37,7 @@ import javax.swing.event.*;
/**
* gui interface to font creation heaven/hell.
* GUI tool for font creation heaven/hell.
*/
public class CreateFont extends JFrame implements Tool {
Editor editor;
@ -46,30 +46,22 @@ public class CreateFont extends JFrame implements Tool {
Dimension windowSize;
JList fontSelector;
//JComboBox styleSelector;
JTextField sizeSelector;
JCheckBox allBox;
JButton charsetButton;
JCheckBox smoothBox;
JTextArea sample;
JComponent sample;
JButton okButton;
JTextField filenameField;
Hashtable table;
HashMap<String,Font> table;
boolean smooth = true;
boolean all = false;
Font font;
String[] list;
int selection = -1;
//static {
//System.out.println("yep yep yep");
//}
//static final String styles[] = {
//"Plain", "Bold", "Italic", "Bold Italic"
//};
CharacterSelector charSelector;
public CreateFont() {
@ -117,7 +109,7 @@ public class CreateFont extends JFrame implements Tool {
Font fonts[] = ge.getAllFonts();
String flist[] = new String[fonts.length];
table = new Hashtable();
table = new HashMap<String,Font>();
int index = 0;
for (int i = 0; i < fonts.length; i++) {
@ -150,20 +142,8 @@ public class CreateFont extends JFrame implements Tool {
Dimension d1 = new Dimension(13, 13);
pain.add(new Box.Filler(d1, d1, d1));
// see http://rinkworks.com/words/pangrams.shtml
sample = new JTextArea("The quick brown fox blah blah.") {
// Forsaking monastic tradition, twelve jovial friars gave up their
// vocation for a questionable existence on the flying trapeze.
public void paintComponent(Graphics g) {
//System.out.println("disabling aa");
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
smooth ?
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
super.paintComponent(g2);
}
};
sample = new SampleComponent(this);
// Seems that in some instances, no default font is set
// http://dev.processing.org/bugs/show_bug.cgi?id=777
sample.setFont(new Font("Dialog", Font.PLAIN, 12));
@ -193,14 +173,22 @@ public class CreateFont extends JFrame implements Tool {
smoothBox.setSelected(smooth);
panel.add(smoothBox);
allBox = new JCheckBox("All Characters");
allBox.addActionListener(new ActionListener() {
// allBox = new JCheckBox("All Characters");
// allBox.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// all = allBox.isSelected();
// }
// });
// allBox.setSelected(all);
// panel.add(allBox);
charsetButton = new JButton("Characters...");
charsetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
all = allBox.isSelected();
//showCharacterList();
charSelector.setVisible(true);
}
});
allBox.setSelected(all);
panel.add(allBox);
panel.add(charsetButton);
pain.add(panel);
@ -239,6 +227,7 @@ public class CreateFont extends JFrame implements Tool {
Base.registerWindowCloseKeys(root, disposer);
Base.setIcon(this);
setResizable(false);
pack();
// do this after pack so it doesn't affect layout
@ -251,6 +240,9 @@ public class CreateFont extends JFrame implements Tool {
setLocation((screen.width - windowSize.width) / 2,
(screen.height - windowSize.height) / 2);
// create this behind the scenes
charSelector = new CharacterSelector();
}
@ -259,26 +251,6 @@ public class CreateFont extends JFrame implements Tool {
}
/**
* make the window vertically resizable
*/
public Dimension getMaximumSize() {
return new Dimension(windowSize.width, 2000);
}
public Dimension getMinimumSize() {
return windowSize;
}
/*
public void show(File targetFolder) {
this.targetFolder = targetFolder;
show();
}
*/
public void update() {
int fontsize = 0;
try {
@ -313,7 +285,7 @@ public class CreateFont extends JFrame implements Tool {
return;
}
String filename = filenameField.getText();
String filename = filenameField.getText().trim();
if (filename.length() == 0) {
JOptionPane.showMessageDialog(this, "Enter a file name for the font.",
"Lameness", JOptionPane.WARNING_MESSAGE);
@ -323,23 +295,519 @@ public class CreateFont extends JFrame implements Tool {
filename += ".vlw";
}
// Please implement me properly. The schematic is below, but not debugged.
// http://dev.processing.org/bugs/show_bug.cgi?id=1464
// final String filename2 = filename;
// final int fontsize2 = fontsize;
// SwingUtilities.invokeLater(new Runnable() {
// public void run() {
try {
Font instance = (Font) table.get(list[selection]);
font = instance.deriveFont(Font.PLAIN, fontsize);
PFont f = new PFont(font, smooth, all ? null : PFont.DEFAULT_CHARSET);
//PFont f = new PFont(font, smooth, all ? null : PFont.CHARSET);
PFont f = new PFont(font, smooth, charSelector.getCharacters());
// PFont f = new PFont(font, smooth, null);
// char[] charset = charSelector.getCharacters();
// ProgressMonitor progressMonitor = new ProgressMonitor(CreateFont.this,
// "Creating font", "", 0, charset.length);
// progressMonitor.setProgress(0);
// for (int i = 0; i < charset.length; i++) {
// System.out.println(charset[i]);
// f.index(charset[i]); // load this char
// progressMonitor.setProgress(i+1);
// }
// make sure the 'data' folder exists
File folder = editor.getSketch().prepareDataFolder();
f.save(new FileOutputStream(new File(folder, filename)));
} catch (IOException e) {
JOptionPane.showMessageDialog(this,
JOptionPane.showMessageDialog(CreateFont.this,
"An error occurred while creating font.",
"No font for you",
JOptionPane.WARNING_MESSAGE);
e.printStackTrace();
}
// }
// });
setVisible(false);
}
/**
* make the window vertically resizable
*/
public Dimension getMaximumSize() {
return new Dimension(windowSize.width, 2000);
}
public Dimension getMinimumSize() {
return windowSize;
}
/*
public void show(File targetFolder) {
this.targetFolder = targetFolder;
show();
}
*/
}
/**
* Component that draws the sample text. This is its own subclassed component
* because Mac OS X controls seem to reset the RenderingHints for smoothing
* so that they cannot be overridden properly for JLabel or JTextArea.
* @author fry
*/
class SampleComponent extends JComponent {
// see http://rinkworks.com/words/pangrams.shtml
String text =
"Forsaking monastic tradition, twelve jovial friars gave up their " +
"vocation for a questionable existence on the flying trapeze.";
int high = 80;
CreateFont parent;
public SampleComponent(CreateFont p) {
this.parent = p;
// and yet, we still need an inner class to handle the basics.
// or no, maybe i'll refactor this as a separate class!
// maybe a few getters and setters? mmm?
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
String input =
(String) JOptionPane.showInputDialog(parent,
"Enter new sample text:",
"Sample Text",
JOptionPane.PLAIN_MESSAGE,
null, // icon
null, // choices
text);
if (input != null) {
text = input;
parent.repaint();
}
}
});
}
public void paintComponent(Graphics g) {
// System.out.println("smoothing set to " + smooth);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
Dimension dim = getSize();
g2.fillRect(0, 0, dim.width, dim.height);
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
parent.smooth ?
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
// add this one as well (after 1.0.9)
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
parent.smooth ?
RenderingHints.VALUE_ANTIALIAS_ON :
RenderingHints.VALUE_ANTIALIAS_OFF);
//super.paintComponent(g2);
Font font = getFont();
int ascent = g2.getFontMetrics().getAscent();
// System.out.println(f.getName());
g2.setFont(font);
g2.drawString(text, 5, dim.height - (dim.height - ascent) / 2);
}
public Dimension getPreferredSize() {
return new Dimension(400, high);
}
public Dimension getMaximumSize() {
return new Dimension(10000, high);
}
public Dimension getMinimumSize() {
return new Dimension(100, high);
}
}
/**
* Frame for selecting which characters will be included with the font.
*/
class CharacterSelector extends JFrame {
JRadioButton defaultCharsButton;
JRadioButton allCharsButton;
JRadioButton unicodeCharsButton;
JScrollPane unicodeBlockScroller;
JList charsetList;
public CharacterSelector() {
super("Character Selector");
charsetList = new CheckBoxList();
DefaultListModel model = new DefaultListModel();
charsetList.setModel(model);
for (String item : blockNames) {
model.addElement(new JCheckBox(item));
}
unicodeBlockScroller =
new JScrollPane(charsetList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
Container outer = getContentPane();
outer.setLayout(new BorderLayout());
JPanel pain = new JPanel();
pain.setBorder(new EmptyBorder(13, 13, 13, 13));
outer.add(pain, BorderLayout.CENTER);
pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS));
String labelText =
"Default characters will include most bitmaps for Mac OS\n" +
"and Windows Latin scripts. Including all characters may\n" +
"require large amounts of memory for all of the bitmaps.\n" +
"For greater control, you can select specific Unicode blocks.";
JTextArea textarea = new JTextArea(labelText);
textarea.setBorder(new EmptyBorder(13, 8, 13, 8));
textarea.setBackground(null);
textarea.setEditable(false);
textarea.setHighlighter(null);
textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
pain.add(textarea);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
//System.out.println("action " + unicodeCharsButton.isSelected());
//unicodeBlockScroller.setEnabled(unicodeCharsButton.isSelected());
charsetList.setEnabled(unicodeCharsButton.isSelected());
}
};
defaultCharsButton = new JRadioButton("Default Characters");
allCharsButton = new JRadioButton("All Characters");
unicodeCharsButton = new JRadioButton("Specific Unicode Blocks");
defaultCharsButton.addActionListener(listener);
allCharsButton.addActionListener(listener);
unicodeCharsButton.addActionListener(listener);
ButtonGroup group = new ButtonGroup();
group.add(defaultCharsButton);
group.add(allCharsButton);
group.add(unicodeCharsButton);
JPanel radioPanel = new JPanel();
//radioPanel.setBackground(Color.red);
radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS));
radioPanel.add(defaultCharsButton);
radioPanel.add(allCharsButton);
radioPanel.add(unicodeCharsButton);
JPanel rightStuff = new JPanel();
rightStuff.setLayout(new BoxLayout(rightStuff, BoxLayout.X_AXIS));
rightStuff.add(radioPanel);
rightStuff.add(Box.createHorizontalGlue());
pain.add(rightStuff);
pain.add(Box.createVerticalStrut(13));
// pain.add(radioPanel);
// pain.add(defaultCharsButton);
// pain.add(allCharsButton);
// pain.add(unicodeCharsButton);
defaultCharsButton.setSelected(true);
charsetList.setEnabled(false);
//frame.getContentPane().add(scroller);
pain.add(unicodeBlockScroller);
pain.add(Box.createVerticalStrut(8));
JPanel buttons = new JPanel();
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
okButton.setEnabled(true);
buttons.add(okButton);
pain.add(buttons);
JRootPane root = getRootPane();
root.setDefaultButton(okButton);
ActionListener disposer = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
setVisible(false);
}
};
Base.registerWindowCloseKeys(root, disposer);
Base.setIcon(this);
pack();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension windowSize = getSize();
setLocation((screen.width - windowSize.width) / 2,
(screen.height - windowSize.height) / 2);
}
protected char[] getCharacters() {
if (defaultCharsButton.isSelected()) {
return PFont.CHARSET;
}
char[] charset = new char[65536];
if (allCharsButton.isSelected()) {
for (int i = 0; i < 0xFFFF; i++) {
charset[i] = (char) i;
}
} else {
DefaultListModel model = (DefaultListModel) charsetList.getModel();
int index = 0;
for (int i = 0; i < BLOCKS.length; i++) {
if (((JCheckBox) model.get(i)).isSelected()) {
for (int j = blockStart[i]; j <= blockStop[i]; j++) {
charset[index++] = (char) j;
}
}
}
charset = PApplet.subset(charset, 0, index);
}
//System.out.println("Creating font with " + charset.length + " characters.");
return charset;
}
// http://www.unicode.org/Public/UNIDATA/Blocks.txt
static final String[] BLOCKS = {
"0000..007F; Basic Latin",
"0080..00FF; Latin-1 Supplement",
"0100..017F; Latin Extended-A",
"0180..024F; Latin Extended-B",
"0250..02AF; IPA Extensions",
"02B0..02FF; Spacing Modifier Letters",
"0300..036F; Combining Diacritical Marks",
"0370..03FF; Greek and Coptic",
"0400..04FF; Cyrillic",
"0500..052F; Cyrillic Supplement",
"0530..058F; Armenian",
"0590..05FF; Hebrew",
"0600..06FF; Arabic",
"0700..074F; Syriac",
"0750..077F; Arabic Supplement",
"0780..07BF; Thaana",
"07C0..07FF; NKo",
"0800..083F; Samaritan",
"0900..097F; Devanagari",
"0980..09FF; Bengali",
"0A00..0A7F; Gurmukhi",
"0A80..0AFF; Gujarati",
"0B00..0B7F; Oriya",
"0B80..0BFF; Tamil",
"0C00..0C7F; Telugu",
"0C80..0CFF; Kannada",
"0D00..0D7F; Malayalam",
"0D80..0DFF; Sinhala",
"0E00..0E7F; Thai",
"0E80..0EFF; Lao",
"0F00..0FFF; Tibetan",
"1000..109F; Myanmar",
"10A0..10FF; Georgian",
"1100..11FF; Hangul Jamo",
"1200..137F; Ethiopic",
"1380..139F; Ethiopic Supplement",
"13A0..13FF; Cherokee",
"1400..167F; Unified Canadian Aboriginal Syllabics",
"1680..169F; Ogham",
"16A0..16FF; Runic",
"1700..171F; Tagalog",
"1720..173F; Hanunoo",
"1740..175F; Buhid",
"1760..177F; Tagbanwa",
"1780..17FF; Khmer",
"1800..18AF; Mongolian",
"18B0..18FF; Unified Canadian Aboriginal Syllabics Extended",
"1900..194F; Limbu",
"1950..197F; Tai Le",
"1980..19DF; New Tai Lue",
"19E0..19FF; Khmer Symbols",
"1A00..1A1F; Buginese",
"1A20..1AAF; Tai Tham",
"1B00..1B7F; Balinese",
"1B80..1BBF; Sundanese",
"1C00..1C4F; Lepcha",
"1C50..1C7F; Ol Chiki",
"1CD0..1CFF; Vedic Extensions",
"1D00..1D7F; Phonetic Extensions",
"1D80..1DBF; Phonetic Extensions Supplement",
"1DC0..1DFF; Combining Diacritical Marks Supplement",
"1E00..1EFF; Latin Extended Additional",
"1F00..1FFF; Greek Extended",
"2000..206F; General Punctuation",
"2070..209F; Superscripts and Subscripts",
"20A0..20CF; Currency Symbols",
"20D0..20FF; Combining Diacritical Marks for Symbols",
"2100..214F; Letterlike Symbols",
"2150..218F; Number Forms",
"2190..21FF; Arrows",
"2200..22FF; Mathematical Operators",
"2300..23FF; Miscellaneous Technical",
"2400..243F; Control Pictures",
"2440..245F; Optical Character Recognition",
"2460..24FF; Enclosed Alphanumerics",
"2500..257F; Box Drawing",
"2580..259F; Block Elements",
"25A0..25FF; Geometric Shapes",
"2600..26FF; Miscellaneous Symbols",
"2700..27BF; Dingbats",
"27C0..27EF; Miscellaneous Mathematical Symbols-A",
"27F0..27FF; Supplemental Arrows-A",
"2800..28FF; Braille Patterns",
"2900..297F; Supplemental Arrows-B",
"2980..29FF; Miscellaneous Mathematical Symbols-B",
"2A00..2AFF; Supplemental Mathematical Operators",
"2B00..2BFF; Miscellaneous Symbols and Arrows",
"2C00..2C5F; Glagolitic",
"2C60..2C7F; Latin Extended-C",
"2C80..2CFF; Coptic",
"2D00..2D2F; Georgian Supplement",
"2D30..2D7F; Tifinagh",
"2D80..2DDF; Ethiopic Extended",
"2DE0..2DFF; Cyrillic Extended-A",
"2E00..2E7F; Supplemental Punctuation",
"2E80..2EFF; CJK Radicals Supplement",
"2F00..2FDF; Kangxi Radicals",
"2FF0..2FFF; Ideographic Description Characters",
"3000..303F; CJK Symbols and Punctuation",
"3040..309F; Hiragana",
"30A0..30FF; Katakana",
"3100..312F; Bopomofo",
"3130..318F; Hangul Compatibility Jamo",
"3190..319F; Kanbun",
"31A0..31BF; Bopomofo Extended",
"31C0..31EF; CJK Strokes",
"31F0..31FF; Katakana Phonetic Extensions",
"3200..32FF; Enclosed CJK Letters and Months",
"3300..33FF; CJK Compatibility",
"3400..4DBF; CJK Unified Ideographs Extension A",
"4DC0..4DFF; Yijing Hexagram Symbols",
"4E00..9FFF; CJK Unified Ideographs",
"A000..A48F; Yi Syllables",
"A490..A4CF; Yi Radicals",
"A4D0..A4FF; Lisu",
"A500..A63F; Vai",
"A640..A69F; Cyrillic Extended-B",
"A6A0..A6FF; Bamum",
"A700..A71F; Modifier Tone Letters",
"A720..A7FF; Latin Extended-D",
"A800..A82F; Syloti Nagri",
"A830..A83F; Common Indic Number Forms",
"A840..A87F; Phags-pa",
"A880..A8DF; Saurashtra",
"A8E0..A8FF; Devanagari Extended",
"A900..A92F; Kayah Li",
"A930..A95F; Rejang",
"A960..A97F; Hangul Jamo Extended-A",
"A980..A9DF; Javanese",
"AA00..AA5F; Cham",
"AA60..AA7F; Myanmar Extended-A",
"AA80..AADF; Tai Viet",
"ABC0..ABFF; Meetei Mayek",
"AC00..D7AF; Hangul Syllables",
"D7B0..D7FF; Hangul Jamo Extended-B",
"D800..DB7F; High Surrogates",
"DB80..DBFF; High Private Use Surrogates",
"DC00..DFFF; Low Surrogates",
"E000..F8FF; Private Use Area",
"F900..FAFF; CJK Compatibility Ideographs",
"FB00..FB4F; Alphabetic Presentation Forms",
"FB50..FDFF; Arabic Presentation Forms-A",
"FE00..FE0F; Variation Selectors",
"FE10..FE1F; Vertical Forms",
"FE20..FE2F; Combining Half Marks",
"FE30..FE4F; CJK Compatibility Forms",
"FE50..FE6F; Small Form Variants",
"FE70..FEFF; Arabic Presentation Forms-B",
"FF00..FFEF; Halfwidth and Fullwidth Forms",
"FFF0..FFFF; Specials"
};
static String[] blockNames;
static int[] blockStart;
static int[] blockStop;
static {
int count = BLOCKS.length;
blockNames = new String[count];
blockStart = new int[count];
blockStop = new int[count];
for (int i = 0; i < count; i++) {
String line = BLOCKS[i];
blockStart[i] = PApplet.unhex(line.substring(0, 4));
blockStop[i] = PApplet.unhex(line.substring(6, 10));
blockNames[i] = line.substring(12);
}
// PApplet.println(codePointStop);
// PApplet.println(codePoints);
}
}
// Code for this CheckBoxList class found on the net, though I've lost the
// link. If you run across the original version, please let me know so that
// the original author can be credited properly. It was from a snippet
// collection, but it seems to have been picked up so many places with others
// placing their copyright on it, that I haven't been able to determine the
// original author. [fry 20100216]
class CheckBoxList extends JList {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public CheckBoxList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (isEnabled()) {
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(!checkbox.isSelected());
repaint();
}
}
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected,
boolean cellHasFocus) {
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ? getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ? getSelectionForeground() : getForeground());
//checkbox.setEnabled(isEnabled());
checkbox.setEnabled(list.isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}

View File

@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2008 Ben Fry and Casey Reas
Copyright (c) 2008-2009 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
@ -25,6 +25,9 @@ package processing.app.windows;
import java.io.File;
import java.io.UnsupportedEncodingException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import processing.app.Base;
import processing.app.Preferences;
import processing.app.windows.Registry.REGISTRY_ROOT_KEY;
@ -265,4 +268,38 @@ public class Platform extends processing.app.Platform {
// not tested
//Runtime.getRuntime().exec("start explorer \"" + folder + "\"");
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Code partially thanks to Richard Quirk from:
// http://quirkygba.blogspot.com/2009/11/setting-environment-variables-in-java.html
static WinLibC clib = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
public interface WinLibC extends Library {
//WinLibC INSTANCE = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
//libc = Native.loadLibrary("msvcrt", WinLibC.class);
public int _putenv(String name);
}
public void setenv(String variable, String value) {
//WinLibC clib = WinLibC.INSTANCE;
clib._putenv(variable + "=" + value);
}
public String getenv(String variable) {
return System.getenv(variable);
}
public int unsetenv(String variable) {
//WinLibC clib = WinLibC.INSTANCE;
//clib._putenv(variable + "=");
//return 0;
return clib._putenv(variable + "=");
}
}