mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
major work on how libraries and natives are handled
This commit is contained in:
@@ -30,7 +30,6 @@ import java.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import processing.app.debug.Compiler;
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
@@ -81,11 +80,12 @@ public class Base {
|
||||
static private File librariesFolder;
|
||||
static private File toolsFolder;
|
||||
|
||||
ArrayList<LibraryFolder> builtinLibraries;
|
||||
ArrayList<LibraryFolder> coreLibraries;
|
||||
ArrayList<LibraryFolder> contribLibraries;
|
||||
|
||||
// maps imported packages to their library folder
|
||||
static HashMap<String, File> importToLibraryTable;
|
||||
// static HashMap<String, File> importToLibraryTable;
|
||||
static HashMap<String, LibraryFolder> importToLibraryTable;
|
||||
|
||||
// classpath for all known libraries for p5
|
||||
// (both those in the p5/libs folder and those with lib subfolders
|
||||
@@ -1131,44 +1131,84 @@ public class Base {
|
||||
}
|
||||
|
||||
|
||||
PrintWriter pw;
|
||||
public void rebuildLibraryList() {
|
||||
// reset the table mapping imports to libraries
|
||||
importToLibraryTable = new HashMap<String, LibraryFolder>();
|
||||
|
||||
try {
|
||||
coreLibraries = LibraryFolder.list(librariesFolder);
|
||||
contribLibraries = LibraryFolder.list(getSketchbookLibrariesFolder());
|
||||
} catch (IOException e) {
|
||||
Base.showWarning("Unhappiness",
|
||||
"An error occurred while loading libraries.\n" +
|
||||
"not all the books will be in place.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PrintWriter pw;
|
||||
|
||||
public void rebuildImportMenu() { //JMenu importMenu) {
|
||||
//System.out.println("rebuilding import menu");
|
||||
importMenu.removeAll();
|
||||
|
||||
// reset the table mapping imports to libraries
|
||||
importToLibraryTable = new HashMap<String, File>();
|
||||
rebuildLibraryList();
|
||||
|
||||
try {
|
||||
pw = new PrintWriter(new FileWriter(System.getProperty("user.home") + "/Desktop/libs.csv"));
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
ActionListener listener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
activeEditor.getSketch().importLibrary(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
|
||||
// try {
|
||||
// pw = new PrintWriter(new FileWriter(System.getProperty("user.home") + "/Desktop/libs.csv"));
|
||||
// } catch (IOException e1) {
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
|
||||
for (LibraryFolder library : coreLibraries) {
|
||||
JMenuItem item = new JMenuItem(library.getName());
|
||||
item.addActionListener(listener);
|
||||
item.setActionCommand(library.getJarPath());
|
||||
importMenu.add(item);
|
||||
}
|
||||
|
||||
if (contribLibraries.size() != 0) {
|
||||
importMenu.addSeparator();
|
||||
JMenuItem contrib = new JMenuItem("Contributed");
|
||||
contrib.setEnabled(false);
|
||||
|
||||
for (LibraryFolder library : contribLibraries) {
|
||||
JMenuItem item = new JMenuItem(library.getName());
|
||||
item.addActionListener(listener);
|
||||
item.setActionCommand(library.getJarPath());
|
||||
importMenu.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Add from the "libraries" subfolder in the Processing directory
|
||||
try {
|
||||
addLibraries(importMenu, librariesFolder);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Add libraries found in the sketchbook folder
|
||||
int separatorIndex = importMenu.getItemCount();
|
||||
try {
|
||||
File sketchbookLibraries = getSketchbookLibrariesFolder();
|
||||
boolean found = addLibraries(importMenu, sketchbookLibraries);
|
||||
if (found) {
|
||||
JMenuItem contrib = new JMenuItem("Contributed");
|
||||
contrib.setEnabled(false);
|
||||
importMenu.insert(contrib, separatorIndex);
|
||||
importMenu.insertSeparator(separatorIndex);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// // Add from the "libraries" subfolder in the Processing directory
|
||||
// try {
|
||||
// addLibraries(importMenu, librariesFolder);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// // Add libraries found in the sketchbook folder
|
||||
// int separatorIndex = importMenu.getItemCount();
|
||||
// try {
|
||||
// File sketchbookLibraries = getSketchbookLibrariesFolder();
|
||||
// boolean found = addLibraries(importMenu, sketchbookLibraries);
|
||||
// if (found) {
|
||||
// JMenuItem contrib = new JMenuItem("Contributed");
|
||||
// contrib.setEnabled(false);
|
||||
// importMenu.insert(contrib, separatorIndex);
|
||||
// importMenu.insertSeparator(separatorIndex);
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
pw.flush();
|
||||
pw.close();
|
||||
// pw.flush();
|
||||
// pw.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1277,6 +1317,7 @@ public class Base {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
protected boolean addLibraries(JMenu menu, File folder) throws IOException {
|
||||
if (!folder.isDirectory()) return false;
|
||||
|
||||
@@ -1345,8 +1386,9 @@ public class Base {
|
||||
String packages[] =
|
||||
Compiler.packageListFromClassPath(libraryClassPath);
|
||||
for (String pkg : packages) {
|
||||
pw.println(pkg + "\t" + libraryFolder.getAbsolutePath());
|
||||
File already = importToLibraryTable.get(pkg);
|
||||
// pw.println(pkg + "\t" + libraryFolder.getAbsolutePath());
|
||||
LibraryFolder library = importToLibraryTable.get(pkg);
|
||||
File already = library.getPath();
|
||||
if (already != null) {
|
||||
Base.showWarning("Library Calling", "The library found in\n" +
|
||||
libraryFolder.getAbsolutePath() + "\n" +
|
||||
@@ -1376,6 +1418,7 @@ public class Base {
|
||||
}
|
||||
return ifound;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// .................................................................
|
||||
@@ -2177,24 +2220,24 @@ public class Base {
|
||||
*/
|
||||
static public HashMap<String,String> readSettings(File inputFile) {
|
||||
HashMap<String,String> outgoing = new HashMap<String,String>();
|
||||
if (!inputFile.exists()) return outgoing; // return empty hash
|
||||
if (inputFile.exists()) {
|
||||
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;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
String attr = line.substring(0, equals).trim();
|
||||
String valu = line.substring(equals + 1).trim();
|
||||
outgoing.put(attr, valu);
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2008 Ben Fry and Casey Reas
|
||||
Copyright (c) 2008-10 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
|
||||
@@ -50,8 +50,12 @@ import processing.app.debug.*;
|
||||
* --export-application Export an application.
|
||||
* --platform Specify the platform (export to application only).
|
||||
* Should be one of 'windows', 'macosx', or 'linux'.
|
||||
* --bits Must be specified if libraries are used that are
|
||||
* 32- or 64-bit specific such as the OpenGL library.
|
||||
* Otherwise specify 0 or leave it out.
|
||||
*
|
||||
* --preferences=<file> Specify a preferences file to use (optional).
|
||||
* --preferences=<file> Specify a preferences file to use. Required if the
|
||||
* sketch uses libraries found in your sketchbook folder.
|
||||
* </PRE>
|
||||
*
|
||||
* To build the command line version, first build for your platform,
|
||||
@@ -71,6 +75,7 @@ public class Commander implements RunnerListener {
|
||||
static final String exportAppletArg = "--export-applet";
|
||||
static final String exportApplicationArg = "--export-application";
|
||||
static final String platformArg = "--platform=";
|
||||
static final String bitsArg = "--bits=";
|
||||
static final String preferencesArg = "--preferences=";
|
||||
|
||||
static final int HELP = -1;
|
||||
@@ -104,6 +109,7 @@ public class Commander implements RunnerListener {
|
||||
String outputPath = null;
|
||||
String preferencesPath = null;
|
||||
int platformIndex = PApplet.platform; // default to this platform
|
||||
int platformBits = 0;
|
||||
int mode = HELP;
|
||||
|
||||
for (String arg : args) {
|
||||
@@ -222,14 +228,14 @@ public class Commander implements RunnerListener {
|
||||
}
|
||||
} else if (mode == EXPORT_APPLICATION) {
|
||||
if (outputPath != null) {
|
||||
success = sketch.exportApplication(outputPath, platformIndex);
|
||||
success = sketch.exportApplication(outputPath, platformIndex, platformBits);
|
||||
} else {
|
||||
//String sketchFolder =
|
||||
// pdePath.substring(0, pdePath.lastIndexOf(File.separatorChar));
|
||||
outputPath =
|
||||
sketchFolder + File.separatorChar +
|
||||
"application." + Base.getPlatformName(platformIndex);
|
||||
success = sketch.exportApplication(outputPath, platformIndex);
|
||||
success = sketch.exportApplication(outputPath, platformIndex, platformBits);
|
||||
}
|
||||
}
|
||||
System.exit(success ? 0 : 1);
|
||||
@@ -298,7 +304,11 @@ public class Commander implements RunnerListener {
|
||||
out.println("--export-application Export an application.");
|
||||
out.println("--platform Specify the platform (export to application only).");
|
||||
out.println(" Should be one of 'windows', 'macosx', or 'linux'.");
|
||||
out.println("--bits Must be specified if libraries are used that are");
|
||||
out.println(" 32- or 64-bit specific such as the OpenGL library.");
|
||||
out.println(" Otherwise specify 0 or leave it out.");
|
||||
out.println();
|
||||
out.println("--preferences=<file> Specify a preferences file to use (optional).");
|
||||
out.println("--preferences=<file> Specify a preferences file to use. Required if the");
|
||||
out.println(" sketch uses libraries found in your sketchbook folder.");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
package processing.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import processing.app.debug.Compiler;
|
||||
import processing.core.PApplet;
|
||||
import processing.core.PConstants;
|
||||
|
||||
//import java.awt.event.*;
|
||||
//import java.io.*;
|
||||
//import java.util.*;
|
||||
@@ -11,9 +21,14 @@ package processing.app;
|
||||
//import processing.core.PApplet;
|
||||
|
||||
|
||||
public class LibraryFolder implements Comparable {
|
||||
String name; // pdf
|
||||
String prettyName; // PDF Export
|
||||
//public class LibraryFolder implements PConstants, Comparable {
|
||||
public class LibraryFolder implements PConstants {
|
||||
File folder;
|
||||
File libraryFolder; // name/library
|
||||
File examplesFolder; // name/examples
|
||||
|
||||
String name; // "pdf" or "PDF Export"
|
||||
// String prettyName; // PDF Export
|
||||
String author; // Ben Fry
|
||||
String authorURL; // http://processing.org
|
||||
String sentence; // Write graphics to PDF files.
|
||||
@@ -22,107 +37,345 @@ public class LibraryFolder implements Comparable {
|
||||
String prettyVersion; // "1.0.2"
|
||||
// String[] packages;
|
||||
|
||||
|
||||
// incomplete, commented out for debugging so as not to break the build
|
||||
/*
|
||||
static ArrayList<LibraryFolder> findLibraries(File folder) {
|
||||
if (!folder.isDirectory()) return null;
|
||||
|
||||
String list[] = folder.list(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
// skip .DS_Store files, .svn folders, etc
|
||||
if (name.charAt(0) == '.') return false;
|
||||
return (new File(dir, name).isDirectory());
|
||||
// static final int BITS_ANY = 0;
|
||||
// static final int BITS_32 = 1;
|
||||
// static final int BITS_64 = 2;
|
||||
// String[][][] exportList; // [platform][bits][index]
|
||||
HashMap<String,String[]> exportList;
|
||||
String[] appletExportList;
|
||||
boolean[] multipleArch = new boolean[platformNames.length];
|
||||
|
||||
/**
|
||||
* For runtime, the native library path for this platform. e.g. on Windows 64,
|
||||
* this might be the windows64 subfolder with the library.
|
||||
*/
|
||||
String nativeLibraryPath;
|
||||
|
||||
/** How many bits this machine is */
|
||||
static int nativeBits;
|
||||
static {
|
||||
nativeBits = 32; // perhaps start with 32
|
||||
String bits = System.getProperty("sun.arch.data.model");
|
||||
if (bits != null) {
|
||||
if (bits.equals("64")) {
|
||||
nativeBits = 64;
|
||||
}
|
||||
});
|
||||
// if a bad folder or inaccessible, this might come back null
|
||||
if (list == null) return null;
|
||||
} else {
|
||||
// if some other strange vm, maybe try this instead
|
||||
if (System.getProperty("java.vm.name").contains("64")) {
|
||||
nativeBits = 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// alphabetize list, since it's not always alpha order
|
||||
// Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
|
||||
/** Filter to pull out just files and no directories */
|
||||
FilenameFilter simpleFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
// skip .DS_Store files, .svn folders, etc
|
||||
if (name.charAt(0) == '.') return false;
|
||||
if (name.equals("CVS")) return false;
|
||||
File file = new File(dir, name);
|
||||
return (!file.isDirectory());
|
||||
}
|
||||
};
|
||||
|
||||
// ActionListener listener = new ActionListener() {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// activeEditor.getSketch().importLibrary(e.getActionCommand());
|
||||
// }
|
||||
// };
|
||||
FilenameFilter jarFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
if (name.charAt(0) == '.') return false; // skip ._blah.jar crap on OS X
|
||||
if (new File(dir, name).isDirectory()) return false;
|
||||
String lc = name.toLowerCase();
|
||||
return lc.endsWith(".jar") || lc.endsWith(".zip");
|
||||
}
|
||||
};
|
||||
|
||||
boolean ifound = false;
|
||||
|
||||
ArrayList<LibraryFolder> outgoing = new ArrayList<LibraryFolder>();
|
||||
|
||||
for (String potentialName : list) {
|
||||
File subfolder = new File(folder, potentialName);
|
||||
File libraryFolder = new File(subfolder, "library");
|
||||
File libraryJar = new File(libraryFolder, potentialName + ".jar");
|
||||
// If a .jar file of the same prefix as the folder exists
|
||||
// inside the 'library' subfolder of the sketch
|
||||
if (libraryJar.exists()) {
|
||||
String sanityCheck = Sketch.sanitizeName(potentialName);
|
||||
if (!sanityCheck.equals(potentialName)) {
|
||||
String mess =
|
||||
"The library \"" + potentialName + "\" cannot be used.\n" +
|
||||
"Library names must contain only basic letters and numbers.\n" +
|
||||
"(ASCII only and no spaces, and it cannot start with a number)";
|
||||
Base.showMessage("Ignoring bad library name", mess);
|
||||
continue;
|
||||
static protected ArrayList<LibraryFolder> list(File folder) throws IOException {
|
||||
ArrayList<LibraryFolder> libraries = new ArrayList<LibraryFolder>();
|
||||
list(folder, libraries);
|
||||
return libraries;
|
||||
}
|
||||
|
||||
|
||||
static protected void list(File folder, ArrayList<LibraryFolder> libraries) throws IOException {
|
||||
if (folder.isDirectory()) {
|
||||
String[] list = folder.list(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
// skip .DS_Store files, .svn folders, etc
|
||||
if (name.charAt(0) == '.') return false;
|
||||
if (name.equals("CVS")) return false;
|
||||
return (new File(dir, name).isDirectory());
|
||||
}
|
||||
});
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list != null) {
|
||||
// alphabetize list, since it's not always alpha order
|
||||
// replaced hella slow bubble sort with this feller for 0093
|
||||
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
String libraryName = potentialName;
|
||||
File exportFile = new File(libraryFolder, "info.txt");
|
||||
//System.out.println(exportFile.getAbsolutePath());
|
||||
if (exportFile.exists()) {
|
||||
String[] exportLines = PApplet.loadStrings(exportFile);
|
||||
for (String line : exportLines) {
|
||||
String[] pieces = PApplet.trim(PApplet.split(line, '='));
|
||||
// System.out.println(pieces);
|
||||
if (pieces[0].equals("name")) {
|
||||
libraryName = pieces[1].trim();
|
||||
for (String potentialName : list) {
|
||||
File baseFolder = new File(folder, potentialName);
|
||||
File libraryFolder = new File(baseFolder, "library");
|
||||
File libraryJar = new File(libraryFolder, potentialName + ".jar");
|
||||
// If a .jar file of the same prefix as the folder exists
|
||||
// inside the 'library' subfolder of the sketch
|
||||
if (libraryJar.exists()) {
|
||||
String sanityCheck = Sketch.sanitizeName(potentialName);
|
||||
if (sanityCheck.equals(potentialName)) {
|
||||
libraries.add(new LibraryFolder(baseFolder));
|
||||
|
||||
} else {
|
||||
String mess =
|
||||
"The library \"" + potentialName + "\" cannot be used.\n" +
|
||||
"Library names must contain only basic letters and numbers.\n" +
|
||||
"(ASCII only and no spaces, and it cannot start with a number)";
|
||||
Base.showMessage("Ignoring bad library name", mess);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LibraryFolder(File folder) {
|
||||
this.folder = folder;
|
||||
libraryFolder = new File(folder, "library");
|
||||
examplesFolder = new File(folder, "examples");
|
||||
|
||||
// get the path for all .jar files in this code folder
|
||||
String libraryClassPath =
|
||||
Compiler.contentsToClassPath(libraryFolder);
|
||||
// grab all jars and classes from this folder,
|
||||
// and append them to the library classpath
|
||||
librariesClassPath +=
|
||||
File.pathSeparatorChar + libraryClassPath;
|
||||
// need to associate each import with a library folder
|
||||
String[] packages =
|
||||
Compiler.packageListFromClassPath(libraryClassPath);
|
||||
for (String pkg : packages) {
|
||||
importToLibraryTable.put(pkg, libraryFolder);
|
||||
File exportSettings = new File(libraryFolder, "export.txt");
|
||||
HashMap<String,String> exportTable = Base.readSettings(exportSettings);
|
||||
|
||||
name = exportTable.get("name");
|
||||
if (name == null) {
|
||||
name = folder.getName();
|
||||
}
|
||||
|
||||
exportList = new HashMap<String, String[]>();
|
||||
|
||||
// get the list of files just in the library root
|
||||
String[] baseList = folder.list(simpleFilter);
|
||||
|
||||
String appletExportStr = exportTable.get("applet");
|
||||
if (appletExportStr != null) {
|
||||
appletExportList = PApplet.splitTokens(appletExportStr, ", ");
|
||||
} else {
|
||||
appletExportList = baseList;
|
||||
}
|
||||
|
||||
// for the host platform, need to figure out what's available
|
||||
File nativeLibraryFolder = libraryFolder;
|
||||
String hostPlatform = platformNames[PApplet.platform];
|
||||
// see if there's a 'windows', 'macosx', or 'linux' folder
|
||||
File hostLibrary = new File(libraryFolder, hostPlatform);
|
||||
if (hostLibrary.exists()) {
|
||||
nativeLibraryFolder = hostLibrary;
|
||||
}
|
||||
// check for bit-specific version, e.g. on windows, check if there
|
||||
// is a window32 or windows64 folder (on windows)
|
||||
hostLibrary = new File(libraryFolder, hostPlatform + nativeBits);
|
||||
if (hostLibrary.exists()) {
|
||||
nativeLibraryFolder = hostLibrary;
|
||||
}
|
||||
// save that folder for later use
|
||||
nativeLibraryPath = nativeLibraryFolder.getAbsolutePath();
|
||||
|
||||
// for each individual platform that this library supports, figure out what's around
|
||||
for (int i = 1; i < platformNames.length; i++) {
|
||||
String platformName = platformNames[i];
|
||||
String platformName32 = platformName + "32";
|
||||
String platformName64 = platformName + "64";
|
||||
|
||||
String platformAll = exportTable.get("application." + platformName);
|
||||
String[] platformList = platformAll == null ? null : PApplet.splitTokens(platformAll, ", ");
|
||||
|
||||
String platform32 = exportTable.get("application." + platformName + "32");
|
||||
String[] platformList32 = platform32 == null ? null : PApplet.splitTokens(platform32, ", ");
|
||||
|
||||
String platform64 = exportTable.get("application." + platformName + "64");
|
||||
String[] platformList64 = platform64 == null ? null : PApplet.splitTokens(platform64, ", ");
|
||||
|
||||
if (platformAll == null) {
|
||||
File folderAll = new File(libraryFolder, platformName);
|
||||
if (folderAll.exists()) {
|
||||
platformList = PApplet.concat(baseList, folderAll.list(simpleFilter));
|
||||
}
|
||||
}
|
||||
if (platform32 == null) {
|
||||
File folder32 = new File(libraryFolder, platformName32);
|
||||
if (folder32.exists()) {
|
||||
platformList32 = PApplet.concat(baseList, folder32.list(simpleFilter));
|
||||
}
|
||||
}
|
||||
if (platform64 == null) {
|
||||
File folder64 = new File(libraryFolder, platformName64);
|
||||
if (folder64.exists()) {
|
||||
platformList64 = PApplet.concat(baseList, folder64.list(simpleFilter));
|
||||
}
|
||||
}
|
||||
|
||||
JMenuItem item = new JMenuItem(libraryName);
|
||||
item.addActionListener(listener);
|
||||
item.setActionCommand(libraryJar.getAbsolutePath());
|
||||
menu.add(item);
|
||||
ifound = true;
|
||||
if (platformList32 != null || platformList64 != null) {
|
||||
multipleArch[i] = true;
|
||||
}
|
||||
|
||||
} else { // not a library, but is still a folder, so recurse
|
||||
JMenu submenu = new JMenu(potentialName);
|
||||
// needs to be separate var, otherwise would set ifound to false
|
||||
boolean found = addLibraries(submenu, subfolder);
|
||||
if (found) {
|
||||
menu.add(submenu);
|
||||
ifound = true;
|
||||
// if there aren't any relevant imports specified or in their own folders,
|
||||
// then use the baseList (root of the library folder) as the default.
|
||||
if (platformList == null && platformList32 == null && platformList64 == null) {
|
||||
exportList.put(platformName, baseList);
|
||||
|
||||
} else {
|
||||
// once we've figured out which side our bread is buttered on, save it.
|
||||
// (also concatenate the list of files in the root folder as well
|
||||
if (platformList != null) {
|
||||
exportList.put(platformName, platformList);
|
||||
}
|
||||
if (platformList32 != null) {
|
||||
exportList.put(platformName32, platformList32);
|
||||
}
|
||||
if (platformList64 != null) {
|
||||
exportList.put(platformName64, platformList64);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ifound;
|
||||
|
||||
// get the path for all .jar files in this code folder
|
||||
String[] packages =
|
||||
Compiler.packageListFromClassPath(getClassPath());
|
||||
// PApplet.println(packages);
|
||||
for (String pkg : packages) {
|
||||
// pw.println(pkg + "\t" + libraryFolder.getAbsolutePath());
|
||||
LibraryFolder library = Base.importToLibraryTable.get(pkg);
|
||||
if (library != null) {
|
||||
// Base.showWarning("Library Calling", "The library found in\n" +
|
||||
// getPath() + "\n" +
|
||||
// "conflicts with the library found in\n" +
|
||||
// library.getPath() + "\n" +
|
||||
// "which already defines the package " + pkg, null);
|
||||
System.err.println("The library found in " + getPath());
|
||||
System.err.println("conflicts with " + library.getPath());
|
||||
System.err.println("which already defines the package " + pkg);
|
||||
System.err.println();
|
||||
} else {
|
||||
// PApplet.println("adding pkg " + pkg + " for " + name);
|
||||
Base.importToLibraryTable.put(pkg, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public LibraryFolder() {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public String getPath() {
|
||||
return folder.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
public String getLibraryPath() {
|
||||
return libraryFolder.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return prettyName.compareTo(((LibraryFolder) o).prettyName);
|
||||
public String getJarPath() {
|
||||
return new File(folder, "library/" + name + ".jar").getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
// this prepends a colon so that it can be appended to other paths safely
|
||||
public String getClassPath() {
|
||||
StringBuilder cp = new StringBuilder();
|
||||
|
||||
// PApplet.println(libraryFolder.getAbsolutePath());
|
||||
// PApplet.println(libraryFolder.list());
|
||||
String[] jarHeads = libraryFolder.list(jarFilter);
|
||||
for (String jar : jarHeads) {
|
||||
cp.append(File.pathSeparatorChar);
|
||||
cp.append(new File(libraryFolder, jar).getAbsolutePath());
|
||||
}
|
||||
jarHeads = new File(nativeLibraryPath).list(jarFilter);
|
||||
for (String jar : jarHeads) {
|
||||
cp.append(File.pathSeparatorChar);
|
||||
cp.append(new File(nativeLibraryPath, jar).getAbsolutePath());
|
||||
}
|
||||
//cp.setLength(cp.length() - 1); // remove the last separator
|
||||
return cp.toString();
|
||||
}
|
||||
|
||||
|
||||
public String getNativePath() {
|
||||
// PApplet.println("native lib folder " + nativeLibraryPath);
|
||||
return nativeLibraryPath;
|
||||
}
|
||||
|
||||
|
||||
// public String[] getAppletExports() {
|
||||
// return appletExportList;
|
||||
// }
|
||||
|
||||
|
||||
protected File[] wrapFiles(String[] list) {
|
||||
File[] outgoing = new File[list.length];
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
outgoing[i] = new File(libraryFolder, list[i]);
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
public File[] getAppletExports() {
|
||||
return wrapFiles(appletExportList);
|
||||
}
|
||||
|
||||
|
||||
public File[] getApplicationExports(int platform, int bits) {
|
||||
String[] list = getApplicationExportList(platform, bits);
|
||||
return wrapFiles(list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the necessary exports for the specified platform.
|
||||
* If no 32 or 64-bit version of the exports exists, it returns the version
|
||||
* that doesn't specify bit depth.
|
||||
*/
|
||||
public String[] getApplicationExportList(int platform, int bits) {
|
||||
String platformName = PApplet.platformNames[platform];
|
||||
if (bits == 32) {
|
||||
String[] pieces = exportList.get(platformName + "32");
|
||||
if (pieces != null) return pieces;
|
||||
} else if (bits == 64) {
|
||||
String[] pieces = exportList.get(platformName + "64");
|
||||
if (pieces != null) return pieces;
|
||||
}
|
||||
return exportList.get(platformName);
|
||||
}
|
||||
|
||||
|
||||
// public boolean hasMultiplePlatforms() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
public boolean hasMultipleArch(int platform) {
|
||||
return multipleArch[platform];
|
||||
}
|
||||
|
||||
|
||||
// static boolean hasMultipleArch(String platformName, ArrayList<LibraryFolder> libraries) {
|
||||
// int platform = Base.getPlatformIndex(platformName);
|
||||
static boolean hasMultipleArch(int platform, ArrayList<LibraryFolder> libraries) {
|
||||
for (LibraryFolder library : libraries) {
|
||||
if (library.hasMultipleArch(platform)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// public int compareTo(Object o) {
|
||||
// return prettyName.compareTo(((LibraryFolder) o).prettyName);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ public class Sketch {
|
||||
/**
|
||||
* List of library folders.
|
||||
*/
|
||||
private ArrayList<File> importedLibraries;
|
||||
private ArrayList<LibraryFolder> importedLibraries;
|
||||
//private ArrayList<File> importedLibraries;
|
||||
|
||||
/**
|
||||
* path is location of the main .pde file, because this is also
|
||||
@@ -1427,24 +1428,30 @@ public class Sketch {
|
||||
|
||||
// grab the imports from the code just preproc'd
|
||||
|
||||
importedLibraries = new ArrayList<File>();
|
||||
// importedLibraries = new ArrayList<File>();
|
||||
importedLibraries = new ArrayList<LibraryFolder>();
|
||||
for (String item : result.extraImports) {
|
||||
// remove things up to the last dot
|
||||
int dot = item.lastIndexOf('.');
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=1145
|
||||
String entry = (dot == -1) ? item : item.substring(0, dot);
|
||||
File libFolder = Base.importToLibraryTable.get(entry);
|
||||
// File libFolder = Base.importToLibraryTable.get(entry);
|
||||
LibraryFolder library = Base.importToLibraryTable.get(entry);
|
||||
|
||||
if (libFolder != null) {
|
||||
if (!importedLibraries.contains(libFolder)) {
|
||||
importedLibraries.add(libFolder);
|
||||
classPath += Compiler.contentsToClassPath(libFolder);
|
||||
libraryPath += File.pathSeparator + libFolder.getAbsolutePath();
|
||||
if (library != null) {
|
||||
if (!importedLibraries.contains(library)) {
|
||||
importedLibraries.add(library);
|
||||
classPath += library.getClassPath(); //Compiler.contentsToClassPath(libFolder);
|
||||
//libraryPath += File.pathSeparator + libFolder.getAbsolutePath();
|
||||
libraryPath += File.pathSeparator + library.getNativePath();
|
||||
// } else {
|
||||
// PApplet.println("skipping additional inclusion of " + libFolder);
|
||||
}
|
||||
} else {
|
||||
PApplet.println("no library found for " + entry);
|
||||
}
|
||||
}
|
||||
// PApplet.println(PApplet.split(libraryPath, File.pathSeparatorChar));
|
||||
|
||||
// Finally, add the regular Java CLASSPATH
|
||||
String javaClassPath = System.getProperty("java.class.path");
|
||||
@@ -1499,9 +1506,9 @@ public class Sketch {
|
||||
return foundMain;
|
||||
}
|
||||
|
||||
public ArrayList<File> getImportedLibraries() {
|
||||
return importedLibraries;
|
||||
}
|
||||
// public ArrayList<File> getImportedLibraries() {
|
||||
// return importedLibraries;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
@@ -1822,54 +1829,50 @@ public class Sketch {
|
||||
// if a file called 'export.txt' is in there, it contains
|
||||
// a list of the files that should be exported.
|
||||
// otherwise, all files are exported.
|
||||
for (File libraryFolder : importedLibraries) {
|
||||
if (libraryFolder.getAbsolutePath().equals(openglLibraryPath)) {
|
||||
for (LibraryFolder library : importedLibraries) {
|
||||
if (library.getPath().equals(openglLibraryPath)) {
|
||||
openglApplet = true;
|
||||
}
|
||||
// in the list is a File object that points the
|
||||
// library sketch's "library" folder
|
||||
File exportSettings = new File(libraryFolder, "export.txt");
|
||||
HashMap<String,String> exportTable = Base.readSettings(exportSettings);
|
||||
String appletList = (String) exportTable.get("applet");
|
||||
String exportList[] = null;
|
||||
if (appletList != null) {
|
||||
exportList = PApplet.splitTokens(appletList, ", ");
|
||||
} else {
|
||||
exportList = libraryFolder.list();
|
||||
}
|
||||
for (int i = 0; i < exportList.length; i++) {
|
||||
if (exportList[i].equals(".") ||
|
||||
exportList[i].equals("..")) continue;
|
||||
// File exportSettings = new File(library.getLi, "export.txt");
|
||||
// HashMap<String,String> exportTable = Base.readSettings(exportSettings);
|
||||
// String appletList = exportTable.get("applet");
|
||||
// String exportList[] = null;
|
||||
// if (appletList != null) {
|
||||
// exportList = PApplet.splitTokens(appletList, ", ");
|
||||
// } else {
|
||||
// exportList = libraryFolder.list();
|
||||
// }
|
||||
// File[] exportList = library.getAppletExports();
|
||||
// for (int i = 0; i < exportList.length; i++) {
|
||||
// for (String item : exportList) {
|
||||
for (File exportFile : library.getAppletExports()) {
|
||||
String exportName = exportFile.getName();
|
||||
// if (exportList[i].equals(".") ||
|
||||
// exportList[i].equals("..")) continue;
|
||||
// exportList[i] = PApplet.trim(exportList[i]);
|
||||
// if (item.equals("")) continue; // should not be possible
|
||||
|
||||
exportList[i] = PApplet.trim(exportList[i]);
|
||||
if (exportList[i].equals("")) continue;
|
||||
|
||||
File exportFile = new File(libraryFolder, exportList[i]);
|
||||
// File exportFile = new File(library.getLibraryPath(), item);
|
||||
if (!exportFile.exists()) {
|
||||
System.err.println("File " + exportList[i] + " does not exist");
|
||||
System.err.println("File " + exportFile.getAbsolutePath() + " does not exist");
|
||||
|
||||
} else if (exportFile.isDirectory()) {
|
||||
System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
|
||||
System.err.println("Ignoring sub-folder \"" + exportFile.getAbsolutePath() + "\"");
|
||||
|
||||
} else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
|
||||
exportFile.getName().toLowerCase().endsWith(".jar")) {
|
||||
} else if (exportName.toLowerCase().endsWith(".zip") ||
|
||||
exportName.toLowerCase().endsWith(".jar")) {
|
||||
if (separateJar) {
|
||||
String exportFilename = exportFile.getName();
|
||||
Base.copyFile(exportFile, new File(appletFolder, exportFilename));
|
||||
// if (renderer.equals("OPENGL") &&
|
||||
// exportFilename.indexOf("natives") != -1) {
|
||||
// don't add these to the archives list
|
||||
// } else {
|
||||
archives.append("," + exportFilename);
|
||||
// }
|
||||
Base.copyFile(exportFile, new File(appletFolder, exportName));
|
||||
archives.append("," + exportName);
|
||||
} else {
|
||||
String path = exportFile.getAbsolutePath();
|
||||
packClassPathIntoZipFile(path, zos, zipFileContents);
|
||||
}
|
||||
|
||||
} else { // just copy the file over.. prolly a .dll or something
|
||||
Base.copyFile(exportFile,
|
||||
new File(appletFolder, exportFile.getName()));
|
||||
Base.copyFile(exportFile, new File(appletFolder, exportName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2255,36 +2258,41 @@ public class Sketch {
|
||||
* Export to application via GUI.
|
||||
*/
|
||||
protected boolean exportApplication() throws IOException, RunnerException {
|
||||
if (Preferences.getBoolean("export.application.platform.windows")) {
|
||||
String windowsPath =
|
||||
new File(folder, "application.windows").getAbsolutePath();
|
||||
if (!exportApplication(windowsPath, PConstants.WINDOWS)) {
|
||||
return false;
|
||||
String path = null;
|
||||
for (String platformName : PConstants.platformNames) {
|
||||
int platform = Base.getPlatformIndex(platformName);
|
||||
if (Preferences.getBoolean("export.application.platform." + platformName)) {
|
||||
if (LibraryFolder.hasMultipleArch(platform, importedLibraries)) {
|
||||
// export the 32-bit version
|
||||
path = new File(folder, "application." + platformName + "32").getAbsolutePath();
|
||||
if (!exportApplication(path, platform, 32)) {
|
||||
return false;
|
||||
}
|
||||
// export the 64-bit version
|
||||
path = new File(folder, "application." + platformName + "64").getAbsolutePath();
|
||||
if (!exportApplication(path, platform, 64)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Preferences.getBoolean("export.application.platform.macosx")) {
|
||||
String macosxPath =
|
||||
new File(folder, "application.macosx").getAbsolutePath();
|
||||
if (!exportApplication(macosxPath, PConstants.MACOSX)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Preferences.getBoolean("export.application.platform.linux")) {
|
||||
String linuxPath =
|
||||
new File(folder, "application.linux").getAbsolutePath();
|
||||
if (!exportApplication(linuxPath, PConstants.LINUX)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true; // all good
|
||||
}
|
||||
|
||||
|
||||
// public boolean exportApplication(String destPath,
|
||||
// String platformName,
|
||||
// int exportBits) throws IOException, RunnerException {
|
||||
// return exportApplication(destPath, Base.getPlatformIndex(platformName), exportBits);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Export to application without GUI.
|
||||
*/
|
||||
public boolean exportApplication(String destPath,
|
||||
int exportPlatform) throws IOException, RunnerException {
|
||||
int exportPlatform,
|
||||
int exportBits) throws IOException, RunnerException {
|
||||
// make sure the user didn't hide the sketch folder
|
||||
ensureExistence();
|
||||
|
||||
@@ -2473,71 +2481,78 @@ public class Sketch {
|
||||
// if a file called 'export.txt' is in there, it contains
|
||||
// a list of the files that should be exported.
|
||||
// otherwise, all files are exported.
|
||||
for (File libraryFolder : importedLibraries) {
|
||||
for (LibraryFolder library : importedLibraries) {
|
||||
// File libraryFolder = library.getLibraryPath();
|
||||
//System.out.println(libraryFolder + " " + libraryFolder.getAbsolutePath());
|
||||
// in the list is a File object that points the
|
||||
// library sketch's "library" folder
|
||||
File exportSettings = new File(libraryFolder, "export.txt");
|
||||
HashMap<String,String> exportTable = Base.readSettings(exportSettings);
|
||||
String commaList = null;
|
||||
String exportList[] = null;
|
||||
// File exportSettings = new File(libraryFolder, "export.txt");
|
||||
// HashMap<String,String> exportTable = Base.readSettings(exportSettings);
|
||||
// String commaList = null;
|
||||
// String exportList[] = null;
|
||||
|
||||
// first check to see if there's something like application.blargh
|
||||
if (exportPlatform == PConstants.MACOSX) {
|
||||
commaList = (String) exportTable.get("application.macosx");
|
||||
} else if (exportPlatform == PConstants.WINDOWS) {
|
||||
commaList = (String) exportTable.get("application.windows");
|
||||
} else if (exportPlatform == PConstants.LINUX) {
|
||||
commaList = (String) exportTable.get("application.linux");
|
||||
} else {
|
||||
// next check to see if something for 'application' is specified
|
||||
commaList = (String) exportTable.get("application");
|
||||
}
|
||||
if (commaList == null) {
|
||||
// otherwise just dump the whole folder
|
||||
exportList = libraryFolder.list();
|
||||
} else {
|
||||
exportList = PApplet.splitTokens(commaList, ", ");
|
||||
}
|
||||
// if (exportPlatform == PConstants.MACOSX) {
|
||||
// commaList = (String) exportTable.get("application.macosx");
|
||||
// } else if (exportPlatform == PConstants.WINDOWS) {
|
||||
// commaList = (String) exportTable.get("application.windows");
|
||||
// } else if (exportPlatform == PConstants.LINUX) {
|
||||
// commaList = (String) exportTable.get("application.linux");
|
||||
// } else {
|
||||
// // next check to see if something for 'application' is specified
|
||||
// commaList = (String) exportTable.get("application");
|
||||
// }
|
||||
// if (commaList == null) {
|
||||
// // otherwise just dump the whole folder
|
||||
// exportList = libraryFolder.list();
|
||||
// } else {
|
||||
// exportList = PApplet.splitTokens(commaList, ", ");
|
||||
// }
|
||||
|
||||
// add each item from the library folder / export list to the output
|
||||
for (int i = 0; i < exportList.length; i++) {
|
||||
if (exportList[i].equals(".") ||
|
||||
exportList[i].equals("..")) continue;
|
||||
for (File exportFile : library.getApplicationExports(exportPlatform, exportBits)) {
|
||||
String exportName = exportFile.getName();
|
||||
// String[] exportList = library.getExports(exportPlatform, exportBits);
|
||||
// for (String item : exportList) {
|
||||
// for (int i = 0; i < exportList.length; i++) {
|
||||
// if (exportList[i].equals(".") ||
|
||||
// exportList[i].equals("..")) continue;
|
||||
|
||||
exportList[i] = PApplet.trim(exportList[i]);
|
||||
if (exportList[i].equals("")) continue;
|
||||
// exportList[i] = PApplet.trim(exportList[i]);
|
||||
// if (exportList[i].equals("")) continue;
|
||||
|
||||
File exportFile = new File(libraryFolder, exportList[i]);
|
||||
// File exportFile = new File(libraryFolder, exportList[i]);
|
||||
// File exportFile = new File(library.getLibraryPath(), )
|
||||
if (!exportFile.exists()) {
|
||||
System.err.println("File " + exportList[i] + " does not exist");
|
||||
System.err.println("File " + exportFile.getName() + " does not exist");
|
||||
|
||||
} else if (exportFile.isDirectory()) {
|
||||
//System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
|
||||
if (exportPlatform == PConstants.MACOSX) {
|
||||
// For OS X, copy subfolders to Contents/Resources/Java
|
||||
Base.copyDir(exportFile, new File(jarFolder, exportFile.getName()));
|
||||
Base.copyDir(exportFile, new File(jarFolder, exportName));
|
||||
} else {
|
||||
// For other platforms, just copy the folder to the same directory
|
||||
// as the application.
|
||||
Base.copyDir(exportFile, new File(destFolder, exportFile.getName()));
|
||||
Base.copyDir(exportFile, new File(destFolder, exportName));
|
||||
}
|
||||
|
||||
} else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
|
||||
exportFile.getName().toLowerCase().endsWith(".jar")) {
|
||||
//packClassPathIntoZipFile(exportFile.getAbsolutePath(), zos);
|
||||
Base.copyFile(exportFile, new File(jarFolder, exportList[i]));
|
||||
jarListVector.add(exportList[i]);
|
||||
// Base.copyFile(exportFile, new File(jarFolder, exportList[i]));
|
||||
// jarListVector.add(exportList[i]);
|
||||
Base.copyFile(exportFile, new File(jarFolder, exportName));
|
||||
jarListVector.add(exportName);
|
||||
|
||||
} else if ((exportPlatform == PConstants.MACOSX) &&
|
||||
(exportFile.getName().toLowerCase().endsWith(".jnilib"))) {
|
||||
// jnilib files can be placed in Contents/Resources/Java
|
||||
Base.copyFile(exportFile, new File(jarFolder, exportList[i]));
|
||||
Base.copyFile(exportFile, new File(jarFolder, exportName));
|
||||
|
||||
} else {
|
||||
// copy the file to the main directory.. prolly a .dll or something
|
||||
Base.copyFile(exportFile,
|
||||
new File(destFolder, exportFile.getName()));
|
||||
Base.copyFile(exportFile, new File(destFolder, exportName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
# If you want to support more platforms, see the jogl.dev.java.net to get the
|
||||
# natives libraries for the platform in question (i.e. solaris). Then, add it
|
||||
# them to the applet line for export. For applications, you'll have to make the
|
||||
# changes by hand, i.e. use the linux version of the export, and modify its
|
||||
# contents to include the necessary files for your platform.
|
||||
# natives libraries for the platform in question (i.e. Solaris).
|
||||
|
||||
name = OpenGL
|
||||
|
||||
application.macosx = opengl.jar, jogl.jar, libjogl.jnilib, libjogl_awt.jnilib, libjogl_cg.jnilib, gluegen-rt.jar, libgluegen-rt.jnilib
|
||||
|
||||
application.windows = opengl.jar, jogl.jar, jogl.dll, jogl_awt.dll, jogl_cg.dll, gluegen-rt.jar, gluegen-rt.dll
|
||||
|
||||
application.linux = opengl.jar, jogl.jar, gluegen-rt.jar, libjogl.so, libjogl_awt.so, libjogl_cg.so, libgluegen-rt.so
|
||||
|
||||
# In releases later than (but not including) 1.0.9, the applet JAR files
|
||||
# are downloaded directly from Sun, so that a single version is cached
|
||||
# on the user's computer, rather than increasing the download size with
|
||||
|
||||
@@ -42,7 +42,7 @@ _ add processing.js export tool from florian
|
||||
_ http://github.com/fjenett/processingjstool/
|
||||
_ http://github.com/fjenett/processingjstool/zipball/v0.0.6
|
||||
|
||||
_ accented letter input is broken (on os x)
|
||||
_ accented letter input is broken (on os x and windows)
|
||||
_ http://code.google.com/p/processing/issues/detail?id=335
|
||||
|
||||
_ auto-format screws up if/else/else if blocks
|
||||
|
||||
Reference in New Issue
Block a user