mirror of
https://github.com/arduino/Arduino.git
synced 2024-12-01 12:24:14 +01:00
Merge branch 'ide-1.5.x-gui-refactor' into ide-1.5.x
This commit is contained in:
commit
6aff4f4077
@ -3,7 +3,6 @@
|
||||
<classpathentry excluding="processing/app/tools/format/|processing/app/tools/format/src/|processing/app/Trace.java|processing/app/RunnerClassLoader.java" kind="src" path="app/src"/>
|
||||
<classpathentry kind="src" path="app/test"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="lib" path="app/lib/antlr.jar"/>
|
||||
<classpathentry kind="lib" path="app/lib/apple.jar"/>
|
||||
<classpathentry kind="lib" path="app/lib/ecj.jar"/>
|
||||
@ -21,5 +20,6 @@
|
||||
<classpathentry kind="lib" path="app/lib/jmdns-3.4.1.jar"/>
|
||||
<classpathentry kind="lib" path="app/lib/jsch-0.1.50.jar"/>
|
||||
<classpathentry kind="lib" path="app/lib/jssc-2.8.0.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/arduino-core"/>
|
||||
<classpathentry kind="output" path="app/bin"/>
|
||||
</classpath>
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,8 +1,8 @@
|
||||
app/bin/
|
||||
app/pde.jar
|
||||
build/macosx/work/
|
||||
core/bin/
|
||||
core/core.jar
|
||||
arduino-core/bin/
|
||||
arduino-core/arduino-core.jar
|
||||
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.o
|
||||
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.lst
|
||||
hardware/arduino/bootloaders/caterina_LUFA/Caterina.sym
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry excluding="processing/app/tools/format/" kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="test"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="lib/antlr.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jna.jar"/>
|
||||
<classpathentry kind="lib" path="lib/ecj.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="lib" path="lib/apple.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-codec-1.7.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-exec-1.1.jar"/>
|
||||
@ -14,5 +14,7 @@
|
||||
<classpathentry kind="lib" path="lib/jmdns-3.4.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jsch-0.1.50.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jssc-2.8.0.jar"/>
|
||||
<classpathentry kind="lib" path="test-lib/junit-4.11.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/arduino-core"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<include name="*.jar"/>
|
||||
</fileset>
|
||||
<pathelement path="${env.JAVA_HOME}/lib/tools.jar"/>
|
||||
<pathelement path="../core/core.jar"/>
|
||||
<pathelement path="../arduino-core/arduino-core.jar"/>
|
||||
</path>
|
||||
|
||||
<path id="class.path.test">
|
||||
@ -25,9 +25,9 @@
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../core/core.jar" />
|
||||
<available file="../arduino-core/arduino-core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built" message="Please build the core library first and make sure it sits in ../core/core.jar" />
|
||||
<fail unless="core-built" message="Please build the Arduino-core library first and make sure it sits in ../arduino-core/arduino-core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
|
||||
@ -80,9 +80,6 @@
|
||||
includeAntRuntime="false"
|
||||
debug="true"
|
||||
classpathref="class.path" />
|
||||
<copy todir="bin" overwrite="true" verbose="true">
|
||||
<fileset dir="src" includes="**/*.properties" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="compile" description="Runs the test">
|
||||
|
17
app/src/cc/arduino/packages/MonitorFactory.java
Normal file
17
app/src/cc/arduino/packages/MonitorFactory.java
Normal file
@ -0,0 +1,17 @@
|
||||
package cc.arduino.packages;
|
||||
|
||||
import processing.app.AbstractMonitor;
|
||||
import processing.app.NetworkMonitor;
|
||||
import processing.app.SerialMonitor;
|
||||
|
||||
public class MonitorFactory {
|
||||
|
||||
public AbstractMonitor newMonitor(BoardPort port) {
|
||||
if ("network".equals(port.getProtocol())) {
|
||||
return new NetworkMonitor(port);
|
||||
}
|
||||
|
||||
return new SerialMonitor(port);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package processing.app;
|
||||
|
||||
import processing.app.debug.MessageConsumer;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
@ -14,6 +14,7 @@ import java.awt.event.WindowEvent;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractMonitor extends JFrame implements MessageConsumer {
|
||||
|
||||
protected final JLabel noLineEndingAlert;
|
||||
|
@ -27,30 +27,27 @@ import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.apache.commons.logging.impl.LogFactoryImpl;
|
||||
import org.apache.commons.logging.impl.NoOpLog;
|
||||
|
||||
import cc.arduino.packages.DiscoveryManager;
|
||||
import processing.app.debug.TargetBoard;
|
||||
import processing.app.debug.TargetPackage;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.debug.TargetPlatformException;
|
||||
import processing.app.helpers.CommandlineParser;
|
||||
import processing.app.helpers.FileUtils;
|
||||
import processing.app.helpers.GUIUserNotifier;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.filefilters.OnlyDirs;
|
||||
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
|
||||
import processing.app.javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import processing.app.legacy.PApplet;
|
||||
import processing.app.macosx.ThinkDifferent;
|
||||
import processing.app.packages.Library;
|
||||
import processing.app.packages.LibraryList;
|
||||
import processing.app.tools.MenuScroller;
|
||||
import processing.app.tools.ZipDeflater;
|
||||
import processing.core.*;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
|
||||
@ -61,29 +58,12 @@ import static processing.app.I18n._;
|
||||
* files and images, etc) that comes from that.
|
||||
*/
|
||||
public class Base {
|
||||
public static final int REVISION = 158;
|
||||
public static final int REVISION = BaseNoGui.REVISION;
|
||||
/** This might be replaced by main() if there's a lib/version.txt file. */
|
||||
static String VERSION_NAME = "0158";
|
||||
static String VERSION_NAME = BaseNoGui.VERSION_NAME;
|
||||
/** Set true if this a proper release rather than a numbered revision. */
|
||||
static public boolean RELEASE = false;
|
||||
static public boolean RELEASE = BaseNoGui.RELEASE;
|
||||
|
||||
static Map<Integer, String> platformNames = new HashMap<Integer, String>();
|
||||
static {
|
||||
platformNames.put(PConstants.WINDOWS, "windows");
|
||||
platformNames.put(PConstants.MACOSX, "macosx");
|
||||
platformNames.put(PConstants.LINUX, "linux");
|
||||
}
|
||||
|
||||
static HashMap<String, Integer> platformIndices = new HashMap<String, Integer>();
|
||||
static {
|
||||
platformIndices.put("windows", PConstants.WINDOWS);
|
||||
platformIndices.put("macosx", PConstants.MACOSX);
|
||||
platformIndices.put("linux", PConstants.LINUX);
|
||||
}
|
||||
static Platform platform;
|
||||
|
||||
private static DiscoveryManager discoveryManager = new DiscoveryManager();
|
||||
|
||||
static private boolean commandLine;
|
||||
|
||||
// A single instance of the preferences window
|
||||
@ -93,33 +73,17 @@ public class Base {
|
||||
// so that the errors while building don't show up again.
|
||||
boolean builtOnce;
|
||||
|
||||
static File buildFolder;
|
||||
|
||||
// these are static because they're used by Sketch
|
||||
static private File examplesFolder;
|
||||
static private File toolsFolder;
|
||||
|
||||
static private List<File> librariesFolders;
|
||||
|
||||
// maps library name to their library folder
|
||||
static private LibraryList libraries;
|
||||
|
||||
// maps #included files to their library folder
|
||||
static Map<String, Library> importToLibraryTable;
|
||||
|
||||
// classpath for all known libraries for p5
|
||||
// (both those in the p5/libs folder and those with lib subfolders
|
||||
// found in the sketchbook)
|
||||
static public String librariesClassPath;
|
||||
|
||||
static public Map<String, TargetPackage> packages;
|
||||
|
||||
// Location for untitled items
|
||||
static File untitledFolder;
|
||||
|
||||
// Current directory to use for relative paths specified on the
|
||||
// commandline
|
||||
static String currentDirectory = System.getProperty("user.dir");
|
||||
static String currentDirectory = BaseNoGui.currentDirectory;
|
||||
|
||||
// p5 icon for the window
|
||||
// static Image icon;
|
||||
@ -127,61 +91,21 @@ public class Base {
|
||||
// int editorCount;
|
||||
List<Editor> editors = Collections.synchronizedList(new ArrayList<Editor>());
|
||||
Editor activeEditor;
|
||||
private final Map<String, Map<String, Object>> boardsViaNetwork;
|
||||
|
||||
static File portableFolder = null;
|
||||
static final String portableSketchbookFolder = "sketchbook";
|
||||
|
||||
static public void main(String args[]) throws Exception {
|
||||
System.setProperty(LogFactoryImpl.LOG_PROPERTY, NoOpLog.class.getCanonicalName());
|
||||
Logger.getLogger("javax.jmdns").setLevel(Level.OFF);
|
||||
BaseNoGui.initLogger();
|
||||
|
||||
BaseNoGui.notifier = new GUIUserNotifier();
|
||||
|
||||
initPlatform();
|
||||
|
||||
// Portable folder
|
||||
portableFolder = getContentFile("portable");
|
||||
if (!portableFolder.exists())
|
||||
portableFolder = null;
|
||||
BaseNoGui.initPortableFolder();
|
||||
|
||||
String preferencesFile = null;
|
||||
|
||||
// Do a first pass over the commandline arguments, the rest of them
|
||||
// will be processed by the Base constructor. Note that this loop
|
||||
// does not look at the last element of args, to prevent crashing
|
||||
// when no parameter was specified to an option. Later, Base() will
|
||||
// then show an error for these.
|
||||
for (int i = 0; i < args.length - 1; i++) {
|
||||
if (args[i].equals("--preferences-file")) {
|
||||
++i;
|
||||
preferencesFile = args[i];
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--curdir")) {
|
||||
i++;
|
||||
currentDirectory = args[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// run static initialization that grabs all the prefs
|
||||
Preferences.init(absoluteFile(preferencesFile));
|
||||
|
||||
try {
|
||||
File versionFile = getContentFile("lib/version.txt");
|
||||
if (versionFile.exists()) {
|
||||
String version = PApplet.loadStrings(versionFile)[0];
|
||||
if (!version.equals(VERSION_NAME) && !version.equals("${version}")) {
|
||||
VERSION_NAME = version;
|
||||
RELEASE = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// help 3rd party installers find the correct hardware path
|
||||
Preferences.set("last.ide." + VERSION_NAME + ".hardwarepath", getHardwarePath());
|
||||
Preferences.set("last.ide." + VERSION_NAME + ".daterun", "" + (new Date()).getTime() / 1000);
|
||||
BaseNoGui.initParameters(args);
|
||||
|
||||
BaseNoGui.initVersion();
|
||||
VERSION_NAME = BaseNoGui.VERSION_NAME;
|
||||
RELEASE = BaseNoGui.RELEASE;
|
||||
|
||||
// if (System.getProperty("mrj.version") != null) {
|
||||
// //String jv = System.getProperty("java.version");
|
||||
@ -232,7 +156,7 @@ public class Base {
|
||||
|
||||
// Set the look and feel before opening the window
|
||||
try {
|
||||
platform.setLookAndFeel();
|
||||
getPlatform().setLookAndFeel();
|
||||
} catch (Exception e) {
|
||||
String mess = e.getMessage();
|
||||
if (mess.indexOf("ch.randelshofer.quaqua.QuaquaLookAndFeel") == -1) {
|
||||
@ -261,21 +185,7 @@ public class Base {
|
||||
|
||||
|
||||
static protected void initPlatform() {
|
||||
try {
|
||||
Class<?> platformClass = Class.forName("processing.app.Platform");
|
||||
if (Base.isMacOS()) {
|
||||
platformClass = Class.forName("processing.app.macosx.Platform");
|
||||
} else if (Base.isWindows()) {
|
||||
platformClass = Class.forName("processing.app.windows.Platform");
|
||||
} else if (Base.isLinux()) {
|
||||
platformClass = Class.forName("processing.app.linux.Platform");
|
||||
}
|
||||
platform = (Platform) platformClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
Base.showError(_("Problem Setting the Platform"),
|
||||
_("An unknown error occurred while trying to load\n" +
|
||||
"platform-specific code for your machine."), e);
|
||||
}
|
||||
BaseNoGui.initPlatform();
|
||||
}
|
||||
|
||||
|
||||
@ -283,11 +193,11 @@ public class Base {
|
||||
try {
|
||||
Class.forName("com.sun.jdi.VirtualMachine");
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
Base.showPlatforms();
|
||||
Base.showError(_("Please install JDK 1.5 or later"),
|
||||
_("Arduino requires a full JDK (not just a JRE)\n" +
|
||||
"to run. Please install JDK 1.5 or later.\n" +
|
||||
"More information can be found in the reference."), cnfe);
|
||||
showPlatforms();
|
||||
showError(_("Please install JDK 1.5 or later"),
|
||||
_("Arduino requires a full JDK (not just a JRE)\n" +
|
||||
"to run. Please install JDK 1.5 or later.\n" +
|
||||
"More information can be found in the reference."), cnfe);
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,49 +206,21 @@ public class Base {
|
||||
// directory when starting the IDE (which is not the same as the
|
||||
// current working directory!).
|
||||
static public File absoluteFile(String path) {
|
||||
if (path == null) return null;
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.isAbsolute()) {
|
||||
file = new File(currentDirectory, path);
|
||||
}
|
||||
return file;
|
||||
return BaseNoGui.absoluteFile(path);
|
||||
}
|
||||
|
||||
protected static enum ACTION { GUI, NOOP, VERIFY, UPLOAD, GET_PREF };
|
||||
|
||||
public Base(String[] args) throws Exception {
|
||||
platform.init(this);
|
||||
getPlatform().init();
|
||||
if (OSUtils.isMacOS())
|
||||
ThinkDifferent.init(this);
|
||||
|
||||
this.boardsViaNetwork = new ConcurrentHashMap<String, Map<String, Object>>();
|
||||
|
||||
// Get the sketchbook path, and make sure it's set properly
|
||||
String sketchbookPath = Preferences.get("sketchbook.path");
|
||||
|
||||
// If a value is at least set, first check to see if the folder exists.
|
||||
// If it doesn't, warn the user that the sketchbook folder is being reset.
|
||||
if (sketchbookPath != null) {
|
||||
File sketchbookFolder;
|
||||
if (portableFolder != null)
|
||||
sketchbookFolder = new File(portableFolder, sketchbookPath);
|
||||
else
|
||||
sketchbookFolder = Base.absoluteFile(sketchbookPath);
|
||||
if (!sketchbookFolder.exists()) {
|
||||
Base.showWarning(_("Sketchbook folder disappeared"),
|
||||
_("The sketchbook folder no longer exists.\n" +
|
||||
"Arduino will switch to the default sketchbook\n" +
|
||||
"location, and create a new sketchbook folder if\n" +
|
||||
"necessary. Arduino will then stop talking about\n" +
|
||||
"himself in the third person."), null);
|
||||
sketchbookPath = null;
|
||||
}
|
||||
}
|
||||
String sketchbookPath = BaseNoGui.getSketchbookPath();
|
||||
|
||||
// If no path is set, get the default sketchbook folder for this platform
|
||||
if (sketchbookPath == null) {
|
||||
File defaultFolder = getDefaultSketchbookFolder();
|
||||
if (portableFolder != null)
|
||||
Preferences.set("sketchbook.path", portableSketchbookFolder);
|
||||
File defaultFolder = getDefaultSketchbookFolderOrPromptForIt();
|
||||
if (BaseNoGui.getPortableFolder() != null)
|
||||
Preferences.set("sketchbook.path", BaseNoGui.getPortableSketchbookFolder());
|
||||
else
|
||||
Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath());
|
||||
if (!defaultFolder.exists()) {
|
||||
@ -346,128 +228,14 @@ public class Base {
|
||||
}
|
||||
}
|
||||
|
||||
packages = new HashMap<String, TargetPackage>();
|
||||
loadHardware(getHardwareFolder());
|
||||
loadHardware(getSketchbookHardwareFolder());
|
||||
if (packages.size() == 0) {
|
||||
System.out.println(_("No valid configured cores found! Exiting..."));
|
||||
System.exit(3);
|
||||
}
|
||||
BaseNoGui.initPackages();
|
||||
|
||||
// Setup board-dependent variables.
|
||||
onBoardOrPortChange();
|
||||
|
||||
ACTION action = ACTION.GUI;
|
||||
boolean doVerboseBuild = false;
|
||||
boolean doVerboseUpload = false;
|
||||
boolean forceSavePrefs = false;
|
||||
String getPref = null;
|
||||
List<String> filenames = new LinkedList<String>();
|
||||
CommandlineParser parser = CommandlineParser.newCommandlineParser(args);
|
||||
|
||||
// Map of possible actions and corresponding options
|
||||
final Map<String, ACTION> actions = new HashMap<String, ACTION>();
|
||||
actions.put("--verify", ACTION.VERIFY);
|
||||
actions.put("--upload", ACTION.UPLOAD);
|
||||
actions.put("--get-pref", ACTION.GET_PREF);
|
||||
|
||||
// Check if any files were passed in on the command line
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
ACTION a = actions.get(args[i]);
|
||||
if (a != null) {
|
||||
if (action != ACTION.GUI && action != ACTION.NOOP) {
|
||||
String[] valid = actions.keySet().toArray(new String[0]);
|
||||
String mess = I18n.format(_("Can only pass one of: {0}"), PApplet.join(valid, ", "));
|
||||
showError(null, mess, 3);
|
||||
}
|
||||
if (a == ACTION.GET_PREF) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --get-pref"), 3);
|
||||
getPref = args[i];
|
||||
}
|
||||
action = a;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose") || args[i].equals("-v")) {
|
||||
doVerboseBuild = true;
|
||||
doVerboseUpload = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose-build")) {
|
||||
doVerboseBuild = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose-upload")) {
|
||||
doVerboseUpload = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--board")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --board"), 3);
|
||||
processBoardArgument(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--port")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --port"), 3);
|
||||
Base.selectSerialPort(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--curdir")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --curdir"), 3);
|
||||
// Argument should be already processed by Base.main(...)
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--pref")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --pref"), 3);
|
||||
processPrefArgument(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--save-prefs")) {
|
||||
forceSavePrefs = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--preferences-file")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
showError(null, _("Argument required for --preferences-file"), 3);
|
||||
// Argument should be already processed by Base.main(...)
|
||||
continue;
|
||||
}
|
||||
if (args[i].startsWith("--"))
|
||||
showError(null, I18n.format(_("unknown option: {0}"), args[i]), 3);
|
||||
|
||||
filenames.add(args[i]);
|
||||
}
|
||||
|
||||
if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1)
|
||||
showError(null, _("Must specify exactly one sketch file"), 3);
|
||||
|
||||
if ((action == ACTION.NOOP || action == ACTION.GET_PREF) && filenames.size() != 0)
|
||||
showError(null, _("Cannot specify any sketch files"), 3);
|
||||
|
||||
if ((action != ACTION.UPLOAD && action != ACTION.VERIFY) && (doVerboseBuild || doVerboseUpload))
|
||||
showError(null, _("--verbose, --verbose-upload and --verbose-build can only be used together with --verify or --upload"), 3);
|
||||
|
||||
for (String path: filenames) {
|
||||
for (String path: parser.getFilenames()) {
|
||||
// Correctly resolve relative paths
|
||||
File file = absoluteFile(path);
|
||||
|
||||
@ -475,7 +243,7 @@ public class Base {
|
||||
// being passed in with 8.3 syntax, which makes the sketch loader code
|
||||
// unhappy, since the sketch folder naming doesn't match up correctly.
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=1089
|
||||
if (isWindows()) {
|
||||
if (OSUtils.isWindows()) {
|
||||
try {
|
||||
file = file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
@ -483,13 +251,13 @@ public class Base {
|
||||
}
|
||||
}
|
||||
|
||||
boolean showEditor = (action == ACTION.GUI);
|
||||
if (!forceSavePrefs)
|
||||
boolean showEditor = parser.isGuiMode();
|
||||
if (!parser.isForceSavePrefs())
|
||||
Preferences.setDoSave(showEditor);
|
||||
if (handleOpen(file, nextEditorLocation(), showEditor) == null) {
|
||||
String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path);
|
||||
// Open failure is fatal in upload/verify mode
|
||||
if (action == ACTION.VERIFY || action == ACTION.UPLOAD)
|
||||
if (parser.isVerifyOrUploadMode())
|
||||
showError(null, mess, 2);
|
||||
else
|
||||
showWarning(null, mess, null);
|
||||
@ -501,12 +269,10 @@ public class Base {
|
||||
// them.
|
||||
Preferences.save();
|
||||
|
||||
switch (action) {
|
||||
case VERIFY:
|
||||
case UPLOAD:
|
||||
if (parser.isVerifyOrUploadMode()) {
|
||||
// Set verbosity for command line build
|
||||
Preferences.set("build.verbose", "" + doVerboseBuild);
|
||||
Preferences.set("upload.verbose", "" + doVerboseUpload);
|
||||
Preferences.set("build.verbose", "" + parser.isDoVerboseBuild());
|
||||
Preferences.set("upload.verbose", "" + parser.isDoVerboseUpload());
|
||||
|
||||
// Make sure these verbosity preferences are only for the
|
||||
// current session
|
||||
@ -514,7 +280,7 @@ public class Base {
|
||||
|
||||
Editor editor = editors.get(0);
|
||||
|
||||
if (action == ACTION.UPLOAD) {
|
||||
if (parser.isUploadMode()) {
|
||||
// Build and upload
|
||||
editor.exportHandler.run();
|
||||
} else {
|
||||
@ -529,8 +295,8 @@ public class Base {
|
||||
|
||||
// No errors exit gracefully
|
||||
System.exit(0);
|
||||
break;
|
||||
case GUI:
|
||||
}
|
||||
else if (parser.isGuiMode()) {
|
||||
// Check if there were previously opened sketches to be restored
|
||||
restoreSketches();
|
||||
|
||||
@ -543,81 +309,20 @@ public class Base {
|
||||
if (Preferences.getBoolean("update.check")) {
|
||||
new UpdateCheck(this);
|
||||
}
|
||||
break;
|
||||
case NOOP:
|
||||
}
|
||||
else if (parser.isNoOpMode()) {
|
||||
// Do nothing (intended for only changing preferences)
|
||||
System.exit(0);
|
||||
break;
|
||||
case GET_PREF:
|
||||
String value = Preferences.get(getPref, null);
|
||||
}
|
||||
else if (parser.isGetPrefMode()) {
|
||||
String value = Preferences.get(parser.getGetPref(), null);
|
||||
if (value != null) {
|
||||
System.out.println(value);
|
||||
System.exit(0);
|
||||
} else {
|
||||
System.exit(4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processBoardArgument(String selectBoard) {
|
||||
// No board selected? Nothing to do
|
||||
if (selectBoard == null)
|
||||
return;
|
||||
|
||||
String[] split = selectBoard.split(":", 4);
|
||||
|
||||
if (split.length < 3) {
|
||||
showError(null, I18n.format(_("{0}: Invalid board name, it should be of the form \"package:arch:board\" or \"package:arch:board:options\""), selectBoard), 3);
|
||||
}
|
||||
|
||||
TargetPackage targetPackage = getTargetPackage(split[0]);
|
||||
if (targetPackage == null) {
|
||||
showError(null, I18n.format(_("{0}: Unknown package"), split[0]), 3);
|
||||
}
|
||||
|
||||
TargetPlatform targetPlatform = targetPackage.get(split[1]);
|
||||
if (targetPlatform == null) {
|
||||
showError(null, I18n.format(_("{0}: Unknown architecture"), split[1]), 3);
|
||||
}
|
||||
|
||||
TargetBoard targetBoard = targetPlatform.getBoard(split[2]);
|
||||
if (targetBoard == null) {
|
||||
showError(null, I18n.format(_("{0}: Unknown board"), split[2]), 3);
|
||||
}
|
||||
|
||||
selectBoard(targetBoard);
|
||||
|
||||
if (split.length > 3) {
|
||||
String[] options = split[3].split(",");
|
||||
for (String option : options) {
|
||||
String[] keyValue = option.split("=", 2);
|
||||
|
||||
if (keyValue.length != 2)
|
||||
showError(null, I18n.format(_("{0}: Invalid option, should be of the form \"name=value\""), option, targetBoard.getId()), 3);
|
||||
String key = keyValue[0].trim();
|
||||
String value = keyValue[1].trim();
|
||||
|
||||
if (!targetBoard.hasMenu(key))
|
||||
showError(null, I18n.format(_("{0}: Invalid option for board \"{1}\""), key, targetBoard.getId()), 3);
|
||||
if (targetBoard.getMenuLabel(key, value) == null)
|
||||
showError(null, I18n.format(_("{0}: Invalid option for \"{1}\" option for board \"{2}\""), value, key, targetBoard.getId()), 3);
|
||||
|
||||
Preferences.set("custom_" + key, targetBoard.getId() + "_" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void processPrefArgument(String arg) {
|
||||
String[] split = arg.split("=", 2);
|
||||
if (split.length != 2 || split[0].isEmpty())
|
||||
showError(null, I18n.format(_("{0}: Invalid argument to --pref, should be of the form \"pref=value\""), arg), 3);
|
||||
|
||||
Preferences.set(split[0], split[1]);
|
||||
}
|
||||
|
||||
public Map<String, Map<String, Object>> getBoardsViaNetwork() {
|
||||
return new HashMap<String, Map<String, Object>>(boardsViaNetwork);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -662,8 +367,8 @@ public class Base {
|
||||
int opened = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
String path = Preferences.get("last.sketch" + i + ".path");
|
||||
if (portableFolder != null) {
|
||||
File absolute = new File(portableFolder, path);
|
||||
if (BaseNoGui.getPortableFolder() != null) {
|
||||
File absolute = new File(BaseNoGui.getPortableFolder(), path);
|
||||
try {
|
||||
path = absolute.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
@ -708,8 +413,8 @@ public class Base {
|
||||
!editor.getSketch().isModified()) {
|
||||
continue;
|
||||
}
|
||||
if (portableFolder != null) {
|
||||
path = FileUtils.relativePath(portableFolder.toString(), path);
|
||||
if (BaseNoGui.getPortableFolder() != null) {
|
||||
path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path);
|
||||
if (path == null)
|
||||
continue;
|
||||
}
|
||||
@ -732,8 +437,8 @@ public class Base {
|
||||
if (path.startsWith(untitledPath)) {
|
||||
path = "";
|
||||
} else
|
||||
if (portableFolder != null) {
|
||||
path = FileUtils.relativePath(portableFolder.toString(), path);
|
||||
if (BaseNoGui.getPortableFolder() != null) {
|
||||
path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path);
|
||||
if (path == null)
|
||||
path = "";
|
||||
}
|
||||
@ -771,7 +476,7 @@ public class Base {
|
||||
activeEditor = whichEditor;
|
||||
|
||||
// set the current window to be the console that's getting output
|
||||
EditorConsole.setEditor(activeEditor);
|
||||
EditorConsoleStream.setCurrent(activeEditor.console);
|
||||
}
|
||||
|
||||
|
||||
@ -858,13 +563,13 @@ public class Base {
|
||||
if (index == 26) {
|
||||
// In 0159, avoid running past z by sending people outdoors.
|
||||
if (!breakTime) {
|
||||
Base.showWarning(_("Time for a Break"),
|
||||
_("You've reached the limit for auto naming of new sketches\n" +
|
||||
"for the day. How about going for a walk instead?"), null);
|
||||
showWarning(_("Time for a Break"),
|
||||
_("You've reached the limit for auto naming of new sketches\n" +
|
||||
"for the day. How about going for a walk instead?"), null);
|
||||
breakTime = true;
|
||||
} else {
|
||||
Base.showWarning(_("Sunshine"),
|
||||
_("No really, time for some fresh air for you."), null);
|
||||
showWarning(_("Sunshine"),
|
||||
_("No really, time for some fresh air for you."), null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -963,7 +668,7 @@ public class Base {
|
||||
*/
|
||||
public void handleOpenPrompt() throws Exception {
|
||||
// get the frontmost window frame for placing file dialog
|
||||
JFileChooser fd = new JFileChooser(Preferences.get("last.folder", Base.getSketchbookFolder().getAbsolutePath()));
|
||||
JFileChooser fd = new JFileChooser(Preferences.get("last.folder", getSketchbookFolder().getAbsolutePath()));
|
||||
fd.setDialogTitle(_("Open an Arduino sketch..."));
|
||||
fd.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fd.setFileFilter(new FileNameExtensionFilter(_("Sketches (*.ino, *.pde)"), "ino", "pde"));
|
||||
@ -1093,7 +798,7 @@ public class Base {
|
||||
// untitled sketch, just give up and let the user quit.
|
||||
// if (Preferences.getBoolean("sketchbook.closing_last_window_quits") ||
|
||||
// (editor.untitled && !editor.getSketch().isModified())) {
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
Object[] options = { "OK", "Cancel" };
|
||||
String prompt =
|
||||
_("<html> " +
|
||||
@ -1176,7 +881,7 @@ public class Base {
|
||||
// Save out the current prefs state
|
||||
Preferences.save();
|
||||
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
// If this was fired from the menu or an AppleEvent (the Finder),
|
||||
// then Mac OS X will send the terminate signal itself.
|
||||
System.exit(0);
|
||||
@ -1257,7 +962,7 @@ public class Base {
|
||||
|
||||
// Add each of the subfolders of examples directly to the menu
|
||||
try {
|
||||
boolean found = addSketches(menu, examplesFolder, true);
|
||||
boolean found = addSketches(menu, BaseNoGui.getExamplesFolder(), true);
|
||||
if (found) menu.addSeparator();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -1278,17 +983,15 @@ public class Base {
|
||||
}
|
||||
|
||||
public LibraryList getIDELibs() {
|
||||
if (libraries == null)
|
||||
if (getLibraries() == null)
|
||||
return new LibraryList();
|
||||
LibraryList res = new LibraryList(libraries);
|
||||
LibraryList res = new LibraryList(getLibraries());
|
||||
res.removeAll(getUserLibs());
|
||||
return res;
|
||||
}
|
||||
|
||||
public LibraryList getUserLibs() {
|
||||
if (libraries == null)
|
||||
return new LibraryList();
|
||||
return libraries.filterLibrariesInSubfolder(getSketchbookFolder());
|
||||
return BaseNoGui.getUserLibs();
|
||||
}
|
||||
|
||||
public void rebuildImportMenu(JMenu importMenu) {
|
||||
@ -1343,7 +1046,7 @@ public class Base {
|
||||
menu.removeAll();
|
||||
|
||||
// Add examples from distribution "example" folder
|
||||
boolean found = addSketches(menu, examplesFolder, false);
|
||||
boolean found = addSketches(menu, BaseNoGui.getExamplesFolder(), false);
|
||||
if (found) menu.addSeparator();
|
||||
|
||||
// Add examples from libraries
|
||||
@ -1365,98 +1068,15 @@ public class Base {
|
||||
}
|
||||
|
||||
public LibraryList scanLibraries(List<File> folders) throws IOException {
|
||||
LibraryList res = new LibraryList();
|
||||
for (File folder : folders)
|
||||
res.addOrReplaceAll(scanLibraries(folder));
|
||||
return res;
|
||||
return BaseNoGui.scanLibraries(folders);
|
||||
}
|
||||
|
||||
public LibraryList scanLibraries(File folder) throws IOException {
|
||||
LibraryList res = new LibraryList();
|
||||
|
||||
String list[] = folder.list(new OnlyDirs());
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null)
|
||||
return res;
|
||||
|
||||
for (String libName : list) {
|
||||
File subfolder = new File(folder, libName);
|
||||
if (!Sketch.isSanitaryName(libName)) {
|
||||
String mess = I18n.format(_("The library \"{0}\" 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)"),
|
||||
libName);
|
||||
Base.showMessage(_("Ignoring bad library name"), mess);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Library lib = Library.create(subfolder);
|
||||
// (also replace previously found libs with the same name)
|
||||
if (lib != null)
|
||||
res.addOrReplace(lib);
|
||||
} catch (IOException e) {
|
||||
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"),
|
||||
subfolder, e.getMessage()));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return BaseNoGui.scanLibraries(folder);
|
||||
}
|
||||
|
||||
public void onBoardOrPortChange() {
|
||||
TargetPlatform targetPlatform = getTargetPlatform();
|
||||
if (targetPlatform == null)
|
||||
return;
|
||||
|
||||
// Calculate paths for libraries and examples
|
||||
examplesFolder = getContentFile("examples");
|
||||
toolsFolder = getContentFile("tools");
|
||||
|
||||
File platformFolder = targetPlatform.getFolder();
|
||||
librariesFolders = new ArrayList<File>();
|
||||
librariesFolders.add(getContentFile("libraries"));
|
||||
String core = getBoardPreferences().get("build.core");
|
||||
if (core.contains(":")) {
|
||||
String referencedCore = core.split(":")[0];
|
||||
TargetPlatform referencedPlatform = Base.getTargetPlatform(referencedCore, targetPlatform.getId());
|
||||
if (referencedPlatform != null) {
|
||||
File referencedPlatformFolder = referencedPlatform.getFolder();
|
||||
librariesFolders.add(new File(referencedPlatformFolder, "libraries"));
|
||||
}
|
||||
}
|
||||
librariesFolders.add(new File(platformFolder, "libraries"));
|
||||
librariesFolders.add(getSketchbookLibrariesFolder());
|
||||
|
||||
// Scan for libraries in each library folder.
|
||||
// Libraries located in the latest folders on the list can override
|
||||
// other libraries with the same name.
|
||||
try {
|
||||
libraries = scanLibraries(librariesFolders);
|
||||
} catch (IOException e) {
|
||||
showWarning(_("Error"), _("Error loading libraries"), e);
|
||||
}
|
||||
|
||||
// Populate importToLibraryTable
|
||||
importToLibraryTable = new HashMap<String, Library>();
|
||||
for (Library lib : libraries) {
|
||||
try {
|
||||
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
|
||||
for (String header : headers) {
|
||||
Library old = importToLibraryTable.get(header);
|
||||
if (old != null) {
|
||||
// If a library was already found with this header, keep
|
||||
// it if the library's name matches the header name.
|
||||
String name = header.substring(0, header.length() - 2);
|
||||
if (old.getFolder().getPath().endsWith(name))
|
||||
continue;
|
||||
}
|
||||
importToLibraryTable.put(header, lib);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
showWarning(_("Error"), I18n
|
||||
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
|
||||
}
|
||||
}
|
||||
BaseNoGui.onBoardOrPortChange();
|
||||
|
||||
// Update editors status bar
|
||||
for (Editor editor : editors)
|
||||
@ -1475,7 +1095,7 @@ public class Base {
|
||||
|
||||
// Generate custom menus for all platforms
|
||||
Set<String> titles = new HashSet<String>();
|
||||
for (TargetPackage targetPackage : packages.values()) {
|
||||
for (TargetPackage targetPackage : BaseNoGui.packages.values()) {
|
||||
for (TargetPlatform targetPlatform : targetPackage.platforms())
|
||||
titles.addAll(targetPlatform.getCustomMenus().values());
|
||||
}
|
||||
@ -1483,7 +1103,7 @@ public class Base {
|
||||
makeBoardCustomMenu(toolsMenu, _(title));
|
||||
|
||||
// Cycle through all packages
|
||||
for (TargetPackage targetPackage : packages.values()) {
|
||||
for (TargetPackage targetPackage : BaseNoGui.packages.values()) {
|
||||
// For every package cycle through all platform
|
||||
for (TargetPlatform targetPlatform : targetPackage.platforms()) {
|
||||
|
||||
@ -1670,30 +1290,17 @@ public class Base {
|
||||
|
||||
|
||||
private void selectBoard(TargetBoard targetBoard) {
|
||||
TargetPlatform targetPlatform = targetBoard.getContainerPlatform();
|
||||
TargetPackage targetPackage = targetPlatform.getContainerPackage();
|
||||
|
||||
Preferences.set("target_package", targetPackage.getId());
|
||||
Preferences.set("target_platform", targetPlatform.getId());
|
||||
Preferences.set("board", targetBoard.getId());
|
||||
|
||||
File platformFolder = targetPlatform.getFolder();
|
||||
Preferences.set("runtime.platform.path", platformFolder.getAbsolutePath());
|
||||
Preferences.set("runtime.hardware.path", platformFolder.getParentFile().getAbsolutePath());
|
||||
BaseNoGui.selectBoard(targetBoard);
|
||||
}
|
||||
|
||||
public static void selectSerialPort(String port) {
|
||||
Preferences.set("serial.port", port);
|
||||
if (port.startsWith("/dev/"))
|
||||
Preferences.set("serial.port.file", port.substring(5));
|
||||
else
|
||||
Preferences.set("serial.port.file", port);
|
||||
BaseNoGui.selectSerialPort(port);
|
||||
}
|
||||
|
||||
public void rebuildProgrammerMenu(JMenu menu) {
|
||||
menu.removeAll();
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
for (TargetPackage targetPackage : packages.values()) {
|
||||
for (TargetPackage targetPackage : BaseNoGui.packages.values()) {
|
||||
for (TargetPlatform targetPlatform : targetPackage.platforms()) {
|
||||
for (String programmer : targetPlatform.getProgrammers().keySet()) {
|
||||
String id = targetPackage.getId() + ":" + programmer;
|
||||
@ -1801,7 +1408,7 @@ public class Base {
|
||||
// if a .pde file of the same prefix as the folder exists..
|
||||
if (entry.exists()) {
|
||||
|
||||
if (!Sketch.isSanitaryName(name)) {
|
||||
if (!BaseNoGui.isSanitaryName(name)) {
|
||||
if (!builtOnce) {
|
||||
String complaining = I18n
|
||||
.format(
|
||||
@ -1811,7 +1418,7 @@ public class Base {
|
||||
+ "and it cannot start with a number).\n"
|
||||
+ "To get rid of this message, remove the sketch from\n"
|
||||
+ "{1}"), name, entry.getAbsolutePath());
|
||||
Base.showMessage(_("Ignoring sketch with bad name"), complaining);
|
||||
showMessage(_("Ignoring sketch with bad name"), complaining);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1879,30 +1486,7 @@ public class Base {
|
||||
}
|
||||
|
||||
protected void loadHardware(File folder) {
|
||||
if (!folder.isDirectory()) return;
|
||||
|
||||
String list[] = folder.list(new OnlyDirs());
|
||||
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null) return;
|
||||
|
||||
// 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);
|
||||
|
||||
for (String target : list) {
|
||||
// Skip reserved 'tools' folder.
|
||||
if (target.equals("tools"))
|
||||
continue;
|
||||
File subfolder = new File(folder, target);
|
||||
|
||||
try {
|
||||
packages.put(target, new TargetPackage(target, subfolder));
|
||||
} catch (TargetPlatformException e) {
|
||||
System.out.println("WARNING: Error loading hardware folder " + target);
|
||||
System.out.println(" " + e.getMessage());
|
||||
}
|
||||
}
|
||||
BaseNoGui.loadHardware(folder);
|
||||
}
|
||||
|
||||
|
||||
@ -1914,7 +1498,7 @@ public class Base {
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public void handleAbout() {
|
||||
final Image image = Base.getLibImage("about.jpg", activeEditor);
|
||||
final Image image = getLibImage("about.jpg", activeEditor);
|
||||
final Window window = new Window(activeEditor) {
|
||||
public void paint(Graphics g) {
|
||||
g.drawImage(image, 0, 0, null);
|
||||
@ -1925,7 +1509,7 @@ public class Base {
|
||||
|
||||
g.setFont(new Font("SansSerif", Font.PLAIN, 11));
|
||||
g.setColor(Color.white);
|
||||
g.drawString(Base.VERSION_NAME, 50, 30);
|
||||
g.drawString(VERSION_NAME, 50, 30);
|
||||
}
|
||||
};
|
||||
window.addMouseListener(new MouseAdapter() {
|
||||
@ -1980,7 +1564,7 @@ public class Base {
|
||||
|
||||
|
||||
static public Platform getPlatform() {
|
||||
return platform;
|
||||
return BaseNoGui.getPlatform();
|
||||
}
|
||||
|
||||
|
||||
@ -2002,85 +1586,11 @@ public class Base {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map a platform constant to its name.
|
||||
* @param which PConstants.WINDOWS, PConstants.MACOSX, PConstants.LINUX
|
||||
* @return one of "windows", "macosx", or "linux"
|
||||
*/
|
||||
static public String getPlatformName(int which) {
|
||||
return platformNames.get(which);
|
||||
}
|
||||
|
||||
|
||||
static public int getPlatformIndex(String what) {
|
||||
Integer entry = platformIndices.get(what);
|
||||
return (entry == null) ? -1 : entry.intValue();
|
||||
}
|
||||
|
||||
|
||||
// These were changed to no longer rely on PApplet and PConstants because
|
||||
// of conflicts that could happen with older versions of core.jar, where
|
||||
// the MACOSX constant would instead read as the LINUX constant.
|
||||
|
||||
|
||||
/**
|
||||
* returns true if Processing is running on a Mac OS X machine.
|
||||
*/
|
||||
static public boolean isMacOS() {
|
||||
//return PApplet.platform == PConstants.MACOSX;
|
||||
return System.getProperty("os.name").indexOf("Mac") != -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns true if running on windows.
|
||||
*/
|
||||
static public boolean isWindows() {
|
||||
//return PApplet.platform == PConstants.WINDOWS;
|
||||
return System.getProperty("os.name").indexOf("Windows") != -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* true if running on linux.
|
||||
*/
|
||||
static public boolean isLinux() {
|
||||
//return PApplet.platform == PConstants.LINUX;
|
||||
return System.getProperty("os.name").indexOf("Linux") != -1;
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
static public File getSettingsFolder() {
|
||||
if (portableFolder != null)
|
||||
return portableFolder;
|
||||
|
||||
File settingsFolder = null;
|
||||
|
||||
String preferencesPath = Preferences.get("settings.path");
|
||||
if (preferencesPath != null) {
|
||||
settingsFolder = absoluteFile(preferencesPath);
|
||||
|
||||
} else {
|
||||
try {
|
||||
settingsFolder = platform.getSettingsFolder();
|
||||
} catch (Exception e) {
|
||||
showError(_("Problem getting data folder"),
|
||||
_("Error getting the Arduino data folder."), e);
|
||||
}
|
||||
}
|
||||
|
||||
// create the folder if it doesn't exist already
|
||||
if (!settingsFolder.exists()) {
|
||||
if (!settingsFolder.mkdirs()) {
|
||||
showError(_("Settings issues"),
|
||||
_("Arduino cannot run because it could not\n" +
|
||||
"create a folder to store your settings."), null);
|
||||
}
|
||||
}
|
||||
return settingsFolder;
|
||||
return BaseNoGui.getSettingsFolder();
|
||||
}
|
||||
|
||||
|
||||
@ -2092,25 +1602,12 @@ public class Base {
|
||||
* @return filename wrapped as a File object inside the settings folder
|
||||
*/
|
||||
static public File getSettingsFile(String filename) {
|
||||
return new File(getSettingsFolder(), filename);
|
||||
return BaseNoGui.getSettingsFile(filename);
|
||||
}
|
||||
|
||||
|
||||
static public File getBuildFolder() {
|
||||
if (buildFolder == null) {
|
||||
String buildPath = Preferences.get("build.path");
|
||||
if (buildPath != null) {
|
||||
buildFolder = Base.absoluteFile(buildPath);
|
||||
if (!buildFolder.exists())
|
||||
buildFolder.mkdirs();
|
||||
} else {
|
||||
//File folder = new File(getTempFolder(), "build");
|
||||
//if (!folder.exists()) folder.mkdirs();
|
||||
buildFolder = createTempFolder("build");
|
||||
buildFolder.deleteOnExit();
|
||||
}
|
||||
}
|
||||
return buildFolder;
|
||||
return BaseNoGui.getBuildFolder();
|
||||
}
|
||||
|
||||
|
||||
@ -2122,51 +1619,37 @@ public class Base {
|
||||
* to avoid conflicts in multi-user environments. (Bug 177)
|
||||
*/
|
||||
static public File createTempFolder(String name) {
|
||||
try {
|
||||
File folder = File.createTempFile(name, null);
|
||||
//String tempPath = ignored.getParent();
|
||||
//return new File(tempPath);
|
||||
folder.delete();
|
||||
folder.mkdirs();
|
||||
return folder;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
return BaseNoGui.createTempFolder(name);
|
||||
}
|
||||
|
||||
|
||||
static public LibraryList getLibraries() {
|
||||
return libraries;
|
||||
return BaseNoGui.getLibraries();
|
||||
}
|
||||
|
||||
|
||||
static public String getExamplesPath() {
|
||||
return examplesFolder.getAbsolutePath();
|
||||
return BaseNoGui.getExamplesPath();
|
||||
}
|
||||
|
||||
|
||||
static public List<File> getLibrariesPath() {
|
||||
return librariesFolders;
|
||||
return BaseNoGui.getLibrariesPath();
|
||||
}
|
||||
|
||||
|
||||
static public File getToolsFolder() {
|
||||
return toolsFolder;
|
||||
return BaseNoGui.getToolsFolder();
|
||||
}
|
||||
|
||||
|
||||
static public String getToolsPath() {
|
||||
return toolsFolder.getAbsolutePath();
|
||||
return BaseNoGui.getToolsPath();
|
||||
}
|
||||
|
||||
|
||||
static public File getHardwareFolder() {
|
||||
// calculate on the fly because it's needed by Preferences.init() to find
|
||||
// the boards.txt and programmers.txt preferences files (which happens
|
||||
// before the other folders / paths get cached).
|
||||
return getContentFile("hardware");
|
||||
return BaseNoGui.getHardwareFolder();
|
||||
}
|
||||
|
||||
//Get the core libraries
|
||||
@ -2175,17 +1658,12 @@ public class Base {
|
||||
}
|
||||
|
||||
static public String getHardwarePath() {
|
||||
return getHardwareFolder().getAbsolutePath();
|
||||
return BaseNoGui.getHardwarePath();
|
||||
}
|
||||
|
||||
|
||||
static public String getAvrBasePath() {
|
||||
String path = getHardwarePath() + File.separator + "tools" +
|
||||
File.separator + "avr" + File.separator + "bin" + File.separator;
|
||||
if (Base.isLinux() && !(new File(path)).exists()) {
|
||||
return ""; // use distribution provided avr tools if bundled tools missing
|
||||
}
|
||||
return path;
|
||||
return BaseNoGui.getAvrBasePath();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2195,7 +1673,7 @@ public class Base {
|
||||
* @return
|
||||
*/
|
||||
static public TargetPackage getTargetPackage(String packageName) {
|
||||
return packages.get(packageName);
|
||||
return BaseNoGui.getTargetPackage(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2204,9 +1682,7 @@ public class Base {
|
||||
* @return
|
||||
*/
|
||||
static public TargetPlatform getTargetPlatform() {
|
||||
String packageName = Preferences.get("target_package");
|
||||
String platformName = Preferences.get("target_platform");
|
||||
return getTargetPlatform(packageName, platformName);
|
||||
return BaseNoGui.getTargetPlatform();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2218,31 +1694,15 @@ public class Base {
|
||||
*/
|
||||
static public TargetPlatform getTargetPlatform(String packageName,
|
||||
String platformName) {
|
||||
TargetPackage p = packages.get(packageName);
|
||||
if (p == null)
|
||||
return null;
|
||||
return p.get(platformName);
|
||||
return BaseNoGui.getTargetPlatform(packageName, platformName);
|
||||
}
|
||||
|
||||
static public TargetPlatform getCurrentTargetPlatformFromPackage(String pack) {
|
||||
return getTargetPlatform(pack, Preferences.get("target_platform"));
|
||||
return BaseNoGui.getCurrentTargetPlatformFromPackage(pack);
|
||||
}
|
||||
|
||||
static public PreferencesMap getBoardPreferences() {
|
||||
TargetBoard board = getTargetBoard();
|
||||
|
||||
PreferencesMap prefs = new PreferencesMap(board.getPreferences());
|
||||
for (String menuId : board.getMenuIds()) {
|
||||
String entry = Preferences.get("custom_" + menuId);
|
||||
if (board.hasMenu(menuId) && entry != null &&
|
||||
entry.startsWith(board.getId())) {
|
||||
String selectionId = entry.substring(entry.indexOf("_") + 1);
|
||||
prefs.putAll(board.getMenuPreferences(menuId, selectionId));
|
||||
prefs.put("name", prefs.get("name") + ", " +
|
||||
board.getMenuLabel(menuId, selectionId));
|
||||
}
|
||||
}
|
||||
return prefs;
|
||||
return BaseNoGui.getBoardPreferences();
|
||||
}
|
||||
|
||||
public static TargetBoard getTargetBoard() {
|
||||
@ -2251,36 +1711,22 @@ public class Base {
|
||||
}
|
||||
|
||||
static public File getPortableFolder() {
|
||||
return portableFolder;
|
||||
return BaseNoGui.getPortableFolder();
|
||||
}
|
||||
|
||||
|
||||
static public String getPortableSketchbookFolder() {
|
||||
return portableSketchbookFolder;
|
||||
return BaseNoGui.getPortableSketchbookFolder();
|
||||
}
|
||||
|
||||
|
||||
static public File getSketchbookFolder() {
|
||||
if (portableFolder != null)
|
||||
return new File(portableFolder, Preferences.get("sketchbook.path"));
|
||||
return absoluteFile(Preferences.get("sketchbook.path"));
|
||||
return BaseNoGui.getSketchbookFolder();
|
||||
}
|
||||
|
||||
|
||||
static public File getSketchbookLibrariesFolder() {
|
||||
File libdir = new File(getSketchbookFolder(), "libraries");
|
||||
if (!libdir.exists()) {
|
||||
try {
|
||||
libdir.mkdirs();
|
||||
File readme = new File(libdir, "readme.txt");
|
||||
FileWriter freadme = new FileWriter(readme);
|
||||
freadme.write(_("For information on installing libraries, see: " +
|
||||
"http://arduino.cc/en/Guide/Libraries\n"));
|
||||
freadme.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return libdir;
|
||||
return BaseNoGui.getSketchbookLibrariesFolder();
|
||||
}
|
||||
|
||||
|
||||
@ -2290,18 +1736,13 @@ public class Base {
|
||||
|
||||
|
||||
static public File getSketchbookHardwareFolder() {
|
||||
return new File(getSketchbookFolder(), "hardware");
|
||||
return BaseNoGui.getSketchbookHardwareFolder();
|
||||
}
|
||||
|
||||
|
||||
protected File getDefaultSketchbookFolder() {
|
||||
if (portableFolder != null)
|
||||
return new File(portableFolder, portableSketchbookFolder);
|
||||
protected File getDefaultSketchbookFolderOrPromptForIt() {
|
||||
|
||||
File sketchbookFolder = null;
|
||||
try {
|
||||
sketchbookFolder = platform.getDefaultSketchbookFolder();
|
||||
} catch (Exception e) { }
|
||||
File sketchbookFolder = BaseNoGui.getDefaultSketchbookFolder();
|
||||
|
||||
if (sketchbookFolder == null) {
|
||||
sketchbookFolder = promptSketchbookLocation();
|
||||
@ -2336,7 +1777,7 @@ public class Base {
|
||||
}
|
||||
|
||||
String prompt = _("Select (or create new) folder for sketches...");
|
||||
folder = Base.selectFolder(prompt, null, null);
|
||||
folder = selectFolder(prompt, null, null);
|
||||
if (folder == null) {
|
||||
System.exit(0);
|
||||
}
|
||||
@ -2356,7 +1797,7 @@ public class Base {
|
||||
*/
|
||||
static public void openURL(String url) {
|
||||
try {
|
||||
platform.openURL(url);
|
||||
getPlatform().openURL(url);
|
||||
|
||||
} catch (Exception e) {
|
||||
showWarning(_("Problem Opening URL"),
|
||||
@ -2370,7 +1811,7 @@ public class Base {
|
||||
* @return true If a means of opening a folder is known to be available.
|
||||
*/
|
||||
static protected boolean openFolderAvailable() {
|
||||
return platform.openFolderAvailable();
|
||||
return BaseNoGui.getPlatform().openFolderAvailable();
|
||||
}
|
||||
|
||||
|
||||
@ -2380,7 +1821,7 @@ public class Base {
|
||||
*/
|
||||
static public void openFolder(File file) {
|
||||
try {
|
||||
platform.openFolder(file);
|
||||
BaseNoGui.getPlatform().openFolder(file);
|
||||
|
||||
} catch (Exception e) {
|
||||
showWarning(_("Problem Opening Folder"),
|
||||
@ -2417,7 +1858,7 @@ public class Base {
|
||||
static public void setIcon(Frame frame) {
|
||||
// don't use the low-res icon on Mac OS X; the window should
|
||||
// already have the right icon from the .app file.
|
||||
if (Base.isMacOS()) return;
|
||||
if (OSUtils.isMacOS()) return;
|
||||
|
||||
Image image = Toolkit.getDefaultToolkit().createImage(PApplet.ICON_IMAGE);
|
||||
frame.setIconImage(image);
|
||||
@ -2464,18 +1905,18 @@ public class Base {
|
||||
|
||||
|
||||
static public void showReference(String filename) {
|
||||
File referenceFolder = Base.getContentFile("reference");
|
||||
File referenceFolder = getContentFile("reference");
|
||||
File referenceFile = new File(referenceFolder, filename);
|
||||
openURL(referenceFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
static public void showGettingStarted() {
|
||||
if (Base.isMacOS()) {
|
||||
Base.showReference(_("Guide_MacOSX.html"));
|
||||
} else if (Base.isWindows()) {
|
||||
Base.showReference(_("Guide_Windows.html"));
|
||||
if (OSUtils.isMacOS()) {
|
||||
showReference(_("Guide_MacOSX.html"));
|
||||
} else if (OSUtils.isWindows()) {
|
||||
showReference(_("Guide_Windows.html"));
|
||||
} else {
|
||||
Base.openURL(_("http://www.arduino.cc/playground/Learning/Linux"));
|
||||
openURL(_("http://www.arduino.cc/playground/Learning/Linux"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2512,15 +1953,7 @@ public class Base {
|
||||
* much of a bummer, but something to notify the user about.
|
||||
*/
|
||||
static public void showMessage(String title, String message) {
|
||||
if (title == null) title = _("Message");
|
||||
|
||||
if (commandLine) {
|
||||
System.out.println(title + ": " + message);
|
||||
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
BaseNoGui.showMessage(title, message);
|
||||
}
|
||||
|
||||
|
||||
@ -2528,16 +1961,7 @@ public class Base {
|
||||
* Non-fatal error message with optional stack trace side dish.
|
||||
*/
|
||||
static public void showWarning(String title, String message, Exception e) {
|
||||
if (title == null) title = _("Warning");
|
||||
|
||||
if (commandLine) {
|
||||
System.out.println(title + ": " + message);
|
||||
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
if (e != null) e.printStackTrace();
|
||||
BaseNoGui.showWarning(title, message, e);
|
||||
}
|
||||
|
||||
|
||||
@ -2555,17 +1979,7 @@ public class Base {
|
||||
* for errors that allow P5 to continue running.
|
||||
*/
|
||||
static public void showError(String title, String message, Throwable e, int exit_code) {
|
||||
if (title == null) title = _("Error");
|
||||
|
||||
if (commandLine) {
|
||||
System.err.println(title + ": " + message);
|
||||
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
if (e != null) e.printStackTrace();
|
||||
System.exit(exit_code);
|
||||
BaseNoGui.showError(title, message, e, exit_code);
|
||||
}
|
||||
|
||||
|
||||
@ -2576,7 +1990,7 @@ public class Base {
|
||||
// incomplete
|
||||
static public int showYesNoCancelQuestion(Editor editor, String title,
|
||||
String primary, String secondary) {
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
int result =
|
||||
JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title,
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
@ -2652,7 +2066,7 @@ public class Base {
|
||||
|
||||
static public int showYesNoQuestion(Frame editor, String title,
|
||||
String primary, String secondary) {
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
return JOptionPane.showConfirmDialog(editor,
|
||||
"<html><body>" +
|
||||
"<b>" + primary + "</b>" +
|
||||
@ -2733,19 +2147,7 @@ public class Base {
|
||||
*/
|
||||
|
||||
static public File getContentFile(String name) {
|
||||
String path = System.getProperty("user.dir");
|
||||
|
||||
// Get a path to somewhere inside the .app folder
|
||||
if (Base.isMacOS()) {
|
||||
// <key>javaroot</key>
|
||||
// <string>$JAVAROOT</string>
|
||||
String javaroot = System.getProperty("javaroot");
|
||||
if (javaroot != null) {
|
||||
path = javaroot;
|
||||
}
|
||||
}
|
||||
File working = new File(path);
|
||||
return new File(working, name);
|
||||
return BaseNoGui.getContentFile(name);
|
||||
}
|
||||
|
||||
|
||||
@ -2779,7 +2181,7 @@ public class Base {
|
||||
* Return an InputStream for a file inside the Processing lib folder.
|
||||
*/
|
||||
static public InputStream getLibStream(String filename) throws IOException {
|
||||
return new FileInputStream(new File(getContentFile("lib"), filename));
|
||||
return BaseNoGui.getLibStream(filename);
|
||||
}
|
||||
|
||||
|
||||
@ -2791,11 +2193,7 @@ public class Base {
|
||||
* characters inside a String (and adding 1).
|
||||
*/
|
||||
static public int countLines(String what) {
|
||||
int count = 1;
|
||||
for (char c : what.toCharArray()) {
|
||||
if (c == '\n') count++;
|
||||
}
|
||||
return count;
|
||||
return BaseNoGui.countLines(what);
|
||||
}
|
||||
|
||||
|
||||
@ -2873,38 +2271,15 @@ public class Base {
|
||||
* Grab the contents of a file as a string.
|
||||
*/
|
||||
static public String loadFile(File file) throws IOException {
|
||||
String[] contents = PApplet.loadStrings(file);
|
||||
if (contents == null) return null;
|
||||
return PApplet.join(contents, "\n");
|
||||
}
|
||||
return BaseNoGui.loadFile(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Spew the contents of a String object out to a file.
|
||||
*/
|
||||
static public void saveFile(String str, File file) throws IOException {
|
||||
File temp = File.createTempFile(file.getName(), null, file.getParentFile());
|
||||
PApplet.saveStrings(temp, new String[] { str });
|
||||
if (file.exists()) {
|
||||
boolean result = file.delete();
|
||||
if (!result) {
|
||||
throw new IOException(
|
||||
I18n.format(
|
||||
_("Could not remove old version of {0}"),
|
||||
file.getAbsolutePath()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
boolean result = temp.renameTo(file);
|
||||
if (!result) {
|
||||
throw new IOException(
|
||||
I18n.format(
|
||||
_("Could not replace {0}"),
|
||||
file.getAbsolutePath()
|
||||
)
|
||||
);
|
||||
}
|
||||
BaseNoGui.saveFile(str, file);
|
||||
}
|
||||
|
||||
|
||||
@ -2938,12 +2313,7 @@ public class Base {
|
||||
* Remove all files in a directory and the directory itself.
|
||||
*/
|
||||
static public void removeDir(File dir) {
|
||||
if (dir.exists()) {
|
||||
removeDescendants(dir);
|
||||
if (!dir.delete()) {
|
||||
System.err.println(I18n.format(_("Could not delete {0}"), dir));
|
||||
}
|
||||
}
|
||||
BaseNoGui.removeDir(dir);
|
||||
}
|
||||
|
||||
|
||||
@ -2954,24 +2324,7 @@ public class Base {
|
||||
* (i.e. when cleaning temp files from lib/build)
|
||||
*/
|
||||
static public void removeDescendants(File dir) {
|
||||
if (!dir.exists()) return;
|
||||
|
||||
String files[] = dir.list();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].equals(".") || files[i].equals("..")) continue;
|
||||
File dead = new File(dir, files[i]);
|
||||
if (!dead.isDirectory()) {
|
||||
if (!Preferences.getBoolean("compiler.save_build_files")) {
|
||||
if (!dead.delete()) {
|
||||
// temporarily disabled
|
||||
System.err.println(I18n.format(_("Could not delete {0}"), dead));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
removeDir(dead);
|
||||
//dead.delete();
|
||||
}
|
||||
}
|
||||
BaseNoGui.removeDescendants(dir);
|
||||
}
|
||||
|
||||
|
||||
@ -3081,7 +2434,7 @@ public class Base {
|
||||
// is there a valid library?
|
||||
File libFolder = sourceFile;
|
||||
String libName = libFolder.getName();
|
||||
if (!Sketch.isSanitaryName(libName)) {
|
||||
if (!BaseNoGui.isSanitaryName(libName)) {
|
||||
String mess = I18n.format(_("The library \"{0}\" 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)"),
|
||||
@ -3110,6 +2463,6 @@ public class Base {
|
||||
}
|
||||
|
||||
public static DiscoveryManager getDiscoveryManager() {
|
||||
return discoveryManager;
|
||||
return BaseNoGui.getDiscoveryManager();
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,17 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
import cc.arduino.packages.UploaderAndMonitorFactory;
|
||||
import cc.arduino.packages.MonitorFactory;
|
||||
|
||||
import com.jcraft.jsch.JSchException;
|
||||
|
||||
import processing.app.debug.*;
|
||||
import processing.app.forms.PasswordAuthorizationDialog;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMapException;
|
||||
import processing.app.legacy.PApplet;
|
||||
import processing.app.syntax.*;
|
||||
import processing.app.tools.*;
|
||||
import processing.core.*;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.awt.*;
|
||||
@ -339,10 +342,9 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
new DataFlavor("text/uri-list;class=java.lang.String");
|
||||
|
||||
if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
|
||||
java.util.List list = (java.util.List)
|
||||
List<File> list = (List<File>)
|
||||
transferable.getTransferData(DataFlavor.javaFileListFlavor);
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
File file = (File) list.get(i);
|
||||
for (File file : list) {
|
||||
if (sketch.addFile(file)) {
|
||||
successful++;
|
||||
}
|
||||
@ -590,7 +592,7 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
fileMenu.add(item);
|
||||
|
||||
// macosx already has its own preferences and quit menu
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
fileMenu.addSeparator();
|
||||
|
||||
item = newJMenuItem(_("Preferences"), ',');
|
||||
@ -853,8 +855,9 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
// Class file to search for
|
||||
String classFileName = "/" + base + ".class";
|
||||
|
||||
ZipFile zipFile = null;
|
||||
try {
|
||||
ZipFile zipFile = new ZipFile(file);
|
||||
zipFile = new ZipFile(file);
|
||||
Enumeration<?> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry) entries.nextElement();
|
||||
@ -874,6 +877,12 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
} catch (IOException e) {
|
||||
//System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (zipFile != null)
|
||||
try {
|
||||
zipFile.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -1102,7 +1111,7 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
menu.add(item);
|
||||
|
||||
// macosx already has its own about menu
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
menu.addSeparator();
|
||||
item = new JMenuItem(_("About Arduino"));
|
||||
item.addActionListener(new ActionListener() {
|
||||
@ -1127,7 +1136,7 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
undoItem.addActionListener(undoAction = new UndoAction());
|
||||
menu.add(undoItem);
|
||||
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
redoItem = newJMenuItem(_("Redo"), 'Y');
|
||||
} else {
|
||||
redoItem = newJMenuItemShift(_("Redo"), 'Z');
|
||||
@ -1631,19 +1640,19 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
* Switch between tabs, this swaps out the Document object
|
||||
* that's currently being manipulated.
|
||||
*/
|
||||
protected void setCode(SketchCode code) {
|
||||
SyntaxDocument document = (SyntaxDocument) code.getDocument();
|
||||
protected void setCode(SketchCodeDocument codeDoc) {
|
||||
SyntaxDocument document = (SyntaxDocument) codeDoc.getDocument();
|
||||
|
||||
if (document == null) { // this document not yet inited
|
||||
document = new SyntaxDocument();
|
||||
code.setDocument(document);
|
||||
|
||||
codeDoc.setDocument(document);
|
||||
|
||||
// turn on syntax highlighting
|
||||
document.setTokenMarker(new PdeKeywords());
|
||||
|
||||
// insert the program text into the document object
|
||||
try {
|
||||
document.insertString(0, code.getProgram(), null);
|
||||
document.insertString(0, codeDoc.getCode().getProgram(), null);
|
||||
} catch (BadLocationException bl) {
|
||||
bl.printStackTrace();
|
||||
}
|
||||
@ -1653,27 +1662,27 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
|
||||
// connect the undo listener to the editor
|
||||
document.addUndoableEditListener(new UndoableEditListener() {
|
||||
public void undoableEditHappened(UndoableEditEvent e) {
|
||||
if (compoundEdit != null) {
|
||||
compoundEdit.addEdit(e.getEdit());
|
||||
public void undoableEditHappened(UndoableEditEvent e) {
|
||||
if (compoundEdit != null) {
|
||||
compoundEdit.addEdit(e.getEdit());
|
||||
|
||||
} else if (undo != null) {
|
||||
undo.addEdit(new CaretAwareUndoableEdit(e.getEdit(), textarea));
|
||||
undoAction.updateUndoState();
|
||||
redoAction.updateRedoState();
|
||||
}
|
||||
} else if (undo != null) {
|
||||
undo.addEdit(new CaretAwareUndoableEdit(e.getEdit(), textarea));
|
||||
undoAction.updateUndoState();
|
||||
redoAction.updateRedoState();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// update the document object that's in use
|
||||
textarea.setDocument(document,
|
||||
code.getSelectionStart(), code.getSelectionStop(),
|
||||
code.getScrollPosition());
|
||||
codeDoc.getSelectionStart(), codeDoc.getSelectionStop(),
|
||||
codeDoc.getScrollPosition());
|
||||
|
||||
textarea.requestFocus(); // get the caret blinking
|
||||
|
||||
this.undo = code.getUndo();
|
||||
this.undo = codeDoc.getUndo();
|
||||
undoAction.updateUndoState();
|
||||
redoAction.updateRedoState();
|
||||
}
|
||||
@ -1861,9 +1870,8 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
|
||||
} catch (BadLocationException bl) {
|
||||
bl.printStackTrace();
|
||||
} finally {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
protected void handleFindReference() {
|
||||
@ -2024,7 +2032,7 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
|
||||
String prompt = I18n.format(_("Save changes to \"{0}\"? "), sketch.getName());
|
||||
|
||||
if (!Base.isMacOS()) {
|
||||
if (!OSUtils.isMacOS()) {
|
||||
int result =
|
||||
JOptionPane.showConfirmDialog(this, prompt, _("Close"),
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
@ -2116,89 +2124,79 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
* Second stage of open, occurs after having checked to see if the
|
||||
* modifications (if any) to the previous sketch need to be saved.
|
||||
*/
|
||||
protected boolean handleOpenInternal(File file) {
|
||||
protected boolean handleOpenInternal(File sketchFile) {
|
||||
// check to make sure that this .pde file is
|
||||
// in a folder of the same name
|
||||
String fileName = file.getName();
|
||||
File parent = file.getParentFile();
|
||||
String parentName = parent.getName();
|
||||
String pdeName = parentName + ".pde";
|
||||
File altPdeFile = new File(parent, pdeName);
|
||||
String inoName = parentName + ".ino";
|
||||
File altInoFile = new File(parent, inoName);
|
||||
String fileName = sketchFile.getName();
|
||||
|
||||
if (pdeName.equals(fileName) || inoName.equals(fileName)) {
|
||||
// no beef with this guy
|
||||
File file = SketchData.checkSketchFile(sketchFile);
|
||||
|
||||
} else if (altPdeFile.exists()) {
|
||||
// user selected a .java from the same sketch, but open the .pde instead
|
||||
file = altPdeFile;
|
||||
} else if (altInoFile.exists()) {
|
||||
file = altInoFile;
|
||||
} else if (!fileName.endsWith(".ino") && !fileName.endsWith(".pde")) {
|
||||
Base.showWarning(_("Bad file selected"),
|
||||
_("Arduino can only open its own sketches\n" +
|
||||
"and other files ending in .ino or .pde"), null);
|
||||
return false;
|
||||
if (file == null)
|
||||
{
|
||||
if (!fileName.endsWith(".ino") && !fileName.endsWith(".pde")) {
|
||||
|
||||
} else {
|
||||
String properParent =
|
||||
fileName.substring(0, fileName.length() - 4);
|
||||
|
||||
Object[] options = { _("OK"), _("Cancel") };
|
||||
String prompt = I18n.format(
|
||||
_("The file \"{0}\" needs to be inside\n" +
|
||||
"a sketch folder named \"{1}\".\n" +
|
||||
"Create this folder, move the file, and continue?"),
|
||||
fileName,
|
||||
properParent
|
||||
);
|
||||
|
||||
int result = JOptionPane.showOptionDialog(this,
|
||||
prompt,
|
||||
_("Moving"),
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
if (result == JOptionPane.YES_OPTION) {
|
||||
// create properly named folder
|
||||
File properFolder = new File(file.getParent(), properParent);
|
||||
if (properFolder.exists()) {
|
||||
Base.showWarning(_("Error"),
|
||||
I18n.format(
|
||||
_("A folder named \"{0}\" already exists. " +
|
||||
"Can't open sketch."),
|
||||
properParent
|
||||
),
|
||||
null);
|
||||
return false;
|
||||
}
|
||||
if (!properFolder.mkdirs()) {
|
||||
//throw new IOException("Couldn't create sketch folder");
|
||||
Base.showWarning(_("Error"),
|
||||
_("Could not create the sketch folder."), null);
|
||||
return false;
|
||||
}
|
||||
// copy the sketch inside
|
||||
File properPdeFile = new File(properFolder, file.getName());
|
||||
try {
|
||||
Base.copyFile(file, properPdeFile);
|
||||
} catch (IOException e) {
|
||||
Base.showWarning(_("Error"), _("Could not copy to a proper location."), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove the original file, so user doesn't get confused
|
||||
file.delete();
|
||||
|
||||
// update with the new path
|
||||
file = properPdeFile;
|
||||
|
||||
} else if (result == JOptionPane.NO_OPTION) {
|
||||
Base.showWarning(_("Bad file selected"),
|
||||
_("Arduino can only open its own sketches\n" +
|
||||
"and other files ending in .ino or .pde"), null);
|
||||
return false;
|
||||
|
||||
} else {
|
||||
String properParent =
|
||||
fileName.substring(0, fileName.length() - 4);
|
||||
|
||||
Object[] options = { _("OK"), _("Cancel") };
|
||||
String prompt = I18n.format(_("The file \"{0}\" needs to be inside\n" +
|
||||
"a sketch folder named \"{1}\".\n" +
|
||||
"Create this folder, move the file, and continue?"),
|
||||
fileName,
|
||||
properParent);
|
||||
|
||||
int result = JOptionPane.showOptionDialog(this,
|
||||
prompt,
|
||||
_("Moving"),
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]);
|
||||
|
||||
if (result == JOptionPane.YES_OPTION) {
|
||||
// create properly named folder
|
||||
File properFolder = new File(sketchFile.getParent(), properParent);
|
||||
if (properFolder.exists()) {
|
||||
Base.showWarning(_("Error"),
|
||||
I18n.format(
|
||||
_("A folder named \"{0}\" already exists. " +
|
||||
"Can't open sketch."),
|
||||
properParent
|
||||
),
|
||||
null);
|
||||
return false;
|
||||
}
|
||||
if (!properFolder.mkdirs()) {
|
||||
//throw new IOException("Couldn't create sketch folder");
|
||||
Base.showWarning(_("Error"),
|
||||
_("Could not create the sketch folder."), null);
|
||||
return false;
|
||||
}
|
||||
// copy the sketch inside
|
||||
File properPdeFile = new File(properFolder, sketchFile.getName());
|
||||
try {
|
||||
Base.copyFile(file, properPdeFile);
|
||||
} catch (IOException e) {
|
||||
Base.showWarning(_("Error"), _("Could not copy to a proper location."), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove the original file, so user doesn't get confused
|
||||
sketchFile.delete();
|
||||
|
||||
// update with the new path
|
||||
file = properPdeFile;
|
||||
|
||||
} else if (result == JOptionPane.NO_OPTION) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2524,7 +2522,7 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
return;
|
||||
}
|
||||
|
||||
serialMonitor = new UploaderAndMonitorFactory().newMonitor(port, base);
|
||||
serialMonitor = new MonitorFactory().newMonitor(port);
|
||||
serialMonitor.setIconImage(getIconImage());
|
||||
|
||||
boolean success = false;
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
@ -22,15 +20,27 @@
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultStyledDocument;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
|
||||
import processing.app.helpers.OSUtils;
|
||||
|
||||
|
||||
/**
|
||||
@ -40,50 +50,33 @@ import java.util.*;
|
||||
* don't take over System.err, and debug while watching just System.out
|
||||
* or just write println() or whatever directly to systemOut or systemErr.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class EditorConsole extends JScrollPane {
|
||||
Editor editor;
|
||||
|
||||
JTextPane consoleTextPane;
|
||||
BufferedStyledDocument consoleDoc;
|
||||
|
||||
MutableAttributeSet stdStyle;
|
||||
MutableAttributeSet errStyle;
|
||||
|
||||
int maxLineCount;
|
||||
|
||||
static File errFile;
|
||||
static File outFile;
|
||||
static File tempFolder;
|
||||
SimpleAttributeSet stdStyle;
|
||||
SimpleAttributeSet errStyle;
|
||||
|
||||
// Single static instance shared because there's only one real System.out.
|
||||
// Within the input handlers, the currentConsole variable will be used to
|
||||
// echo things to the correct location.
|
||||
|
||||
static public PrintStream systemOut;
|
||||
static public PrintStream systemErr;
|
||||
public EditorConsole(Editor _editor) {
|
||||
editor = _editor;
|
||||
|
||||
static PrintStream consoleOut;
|
||||
static PrintStream consoleErr;
|
||||
int maxLineCount = Preferences.getInteger("console.length");
|
||||
|
||||
static OutputStream stdoutFile;
|
||||
static OutputStream stderrFile;
|
||||
|
||||
static EditorConsole currentConsole;
|
||||
|
||||
|
||||
public EditorConsole(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
maxLineCount = Preferences.getInteger("console.length");
|
||||
|
||||
consoleDoc = new BufferedStyledDocument(10000, maxLineCount);
|
||||
consoleDoc = new BufferedStyledDocument(4000, maxLineCount);
|
||||
consoleTextPane = new JTextPane(consoleDoc);
|
||||
consoleTextPane.setEditable(false);
|
||||
|
||||
// necessary?
|
||||
MutableAttributeSet standard = new SimpleAttributeSet();
|
||||
StyleConstants.setAlignment(standard, StyleConstants.ALIGN_LEFT);
|
||||
consoleDoc.setParagraphAttributes(0, 0, standard, true);
|
||||
SimpleAttributeSet leftAlignAttr = new SimpleAttributeSet();
|
||||
StyleConstants.setAlignment(leftAlignAttr, StyleConstants.ALIGN_LEFT);
|
||||
consoleDoc.setParagraphAttributes(0, 0, leftAlignAttr, true);
|
||||
|
||||
// build styles for different types of console output
|
||||
Color bgColor = Theme.getColor("console.color");
|
||||
@ -112,62 +105,22 @@ public class EditorConsole extends JScrollPane {
|
||||
consoleTextPane.setBackground(bgColor);
|
||||
|
||||
// add the jtextpane to this scrollpane
|
||||
this.setViewportView(consoleTextPane);
|
||||
setViewportView(consoleTextPane);
|
||||
|
||||
// calculate height of a line of text in pixels
|
||||
// and size window accordingly
|
||||
FontMetrics metrics = this.getFontMetrics(font);
|
||||
FontMetrics metrics = getFontMetrics(font);
|
||||
int height = metrics.getAscent() + metrics.getDescent();
|
||||
int lines = Preferences.getInteger("console.lines"); //, 4);
|
||||
int lines = Preferences.getInteger("console.lines");
|
||||
int sizeFudge = 6; //10; // unclear why this is necessary, but it is
|
||||
setPreferredSize(new Dimension(1024, (height * lines) + sizeFudge));
|
||||
setMinimumSize(new Dimension(1024, (height * 4) + sizeFudge));
|
||||
|
||||
if (systemOut == null) {
|
||||
systemOut = System.out;
|
||||
systemErr = System.err;
|
||||
|
||||
// Create a temporary folder which will have a randomized name. Has to
|
||||
// be randomized otherwise another instance of Processing (or one of its
|
||||
// sister IDEs) might collide with the file causing permissions problems.
|
||||
// The files and folders are not deleted on exit because they may be
|
||||
// needed for debugging or bug reporting.
|
||||
tempFolder = Base.createTempFolder("console");
|
||||
tempFolder.deleteOnExit();
|
||||
try {
|
||||
String outFileName = Preferences.get("console.output.file");
|
||||
if (outFileName != null) {
|
||||
outFile = new File(tempFolder, outFileName);
|
||||
outFile.deleteOnExit();
|
||||
stdoutFile = new FileOutputStream(outFile);
|
||||
}
|
||||
|
||||
String errFileName = Preferences.get("console.error.file");
|
||||
if (errFileName != null) {
|
||||
errFile = new File(tempFolder, errFileName);
|
||||
errFile.deleteOnExit();
|
||||
stderrFile = new FileOutputStream(errFile);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Base.showWarning(_("Console Error"),
|
||||
_("A problem occurred while trying to open the\nfiles used to store the console output."), e);
|
||||
}
|
||||
consoleOut = new PrintStream(new EditorConsoleStream(false));
|
||||
consoleErr = new PrintStream(new EditorConsoleStream(true));
|
||||
|
||||
if (Preferences.getBoolean("console")) {
|
||||
try {
|
||||
System.setOut(consoleOut);
|
||||
System.setErr(consoleErr);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(systemOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorConsoleStream.init();
|
||||
|
||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||
// ugly white border around this object, so turn it off.
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
setBorder(null);
|
||||
}
|
||||
|
||||
@ -179,7 +132,7 @@ public class EditorConsole extends JScrollPane {
|
||||
@Override
|
||||
public void run() {
|
||||
// only if new text has been added
|
||||
if (consoleDoc.hasAppendage) {
|
||||
if (consoleDoc.isChanged()) {
|
||||
// insert the text that's been added in the meantime
|
||||
consoleDoc.insertAll();
|
||||
// always move to the end of the text as it's added
|
||||
@ -191,75 +144,6 @@ public class EditorConsole extends JScrollPane {
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
static public void setEditor(Editor editor) {
|
||||
currentConsole = editor.console;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the streams so that the temporary files can be deleted.
|
||||
* <p/>
|
||||
* File.deleteOnExit() cannot be used because the stdout and stderr
|
||||
* files are inside a folder, and have to be deleted before the
|
||||
* folder itself is deleted, which can't be guaranteed when using
|
||||
* the deleteOnExit() method.
|
||||
*/
|
||||
public void handleQuit() {
|
||||
// replace original streams to remove references to console's streams
|
||||
System.setOut(systemOut);
|
||||
System.setErr(systemErr);
|
||||
|
||||
// close the PrintStream
|
||||
consoleOut.close();
|
||||
consoleErr.close();
|
||||
|
||||
// also have to close the original FileOutputStream
|
||||
// otherwise it won't be shut down completely
|
||||
try {
|
||||
stdoutFile.close();
|
||||
stderrFile.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(systemOut);
|
||||
}
|
||||
|
||||
outFile.delete();
|
||||
errFile.delete();
|
||||
tempFolder.delete();
|
||||
}
|
||||
|
||||
|
||||
public void write(byte b[], int offset, int length, boolean err) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
// added sync for 0091.. not sure if it helps or hinders
|
||||
synchronized public void message(String what, boolean err, boolean advance) {
|
||||
if (err) {
|
||||
systemErr.print(what);
|
||||
//systemErr.print("CE" + what);
|
||||
} else {
|
||||
systemOut.print(what);
|
||||
//systemOut.print("CO" + what);
|
||||
}
|
||||
|
||||
if (advance) {
|
||||
appendText("\n", err);
|
||||
if (err) {
|
||||
systemErr.println();
|
||||
} else {
|
||||
systemOut.println();
|
||||
}
|
||||
}
|
||||
|
||||
// to console display
|
||||
appendText(what, err);
|
||||
// moved down here since something is punting
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append a piece of text to the console.
|
||||
@ -273,7 +157,7 @@ public class EditorConsole extends JScrollPane {
|
||||
* Updates are buffered to the console and displayed at regular
|
||||
* intervals on Swing's event-dispatching thread. (patch by David Mellis)
|
||||
*/
|
||||
synchronized private void appendText(String txt, boolean e) {
|
||||
synchronized void appendText(String txt, boolean e) {
|
||||
consoleDoc.appendString(txt, e ? errStyle : stdStyle);
|
||||
}
|
||||
|
||||
@ -286,93 +170,6 @@ public class EditorConsole extends JScrollPane {
|
||||
// maybe not a good idea in the long run?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
private static class EditorConsoleStream extends OutputStream {
|
||||
//static EditorConsole current;
|
||||
final boolean err; // whether stderr or stdout
|
||||
final byte single[] = new byte[1];
|
||||
|
||||
public EditorConsoleStream(boolean err) {
|
||||
this.err = err;
|
||||
}
|
||||
|
||||
public void close() { }
|
||||
|
||||
public void flush() { }
|
||||
|
||||
public void write(byte b[]) { // appears never to be used
|
||||
if (currentConsole != null) {
|
||||
currentConsole.write(b, 0, b.length, err);
|
||||
} else {
|
||||
try {
|
||||
if (err) {
|
||||
systemErr.write(b);
|
||||
} else {
|
||||
systemOut.write(b);
|
||||
}
|
||||
} catch (IOException e) { } // just ignore, where would we write?
|
||||
}
|
||||
|
||||
OutputStream echo = err ? stderrFile : stdoutFile;
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(byte b[], int offset, int length) {
|
||||
if (currentConsole != null) {
|
||||
currentConsole.write(b, offset, length, err);
|
||||
} else {
|
||||
if (err) {
|
||||
systemErr.write(b, offset, length);
|
||||
} else {
|
||||
systemOut.write(b, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream echo = err ? stderrFile : stdoutFile;
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b, offset, length);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
single[0] = (byte)b;
|
||||
if (currentConsole != null) {
|
||||
currentConsole.write(single, 0, 1, err);
|
||||
} else {
|
||||
// redirect for all the extra handling above
|
||||
write(new byte[] { (byte) b }, 0, 1);
|
||||
}
|
||||
|
||||
OutputStream echo = err ? stderrFile : stdoutFile;
|
||||
if (echo != null) {
|
||||
try {
|
||||
echo.write(b);
|
||||
echo.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
echo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -386,78 +183,73 @@ public class EditorConsole extends JScrollPane {
|
||||
* appendString() is called from multiple threads, and insertAll from the
|
||||
* swing event thread, so they need to be synchronized
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
class BufferedStyledDocument extends DefaultStyledDocument {
|
||||
ArrayList<ElementSpec> elements = new ArrayList<ElementSpec>();
|
||||
int maxLineLength, maxLineCount;
|
||||
int currentLineLength = 0;
|
||||
boolean needLineBreak = false;
|
||||
boolean hasAppendage = false;
|
||||
private List<ElementSpec> elements = new ArrayList<ElementSpec>();
|
||||
private int maxLineLength, maxLineCount;
|
||||
private int currentLineLength = 0;
|
||||
private boolean changed = false;
|
||||
|
||||
public BufferedStyledDocument(int maxLineLength, int maxLineCount) {
|
||||
this.maxLineLength = maxLineLength;
|
||||
this.maxLineCount = maxLineCount;
|
||||
public BufferedStyledDocument(int _maxLineLength, int _maxLineCount) {
|
||||
maxLineLength = _maxLineLength;
|
||||
maxLineCount = _maxLineCount;
|
||||
}
|
||||
|
||||
/** buffer a string for insertion at the end of the DefaultStyledDocument */
|
||||
public synchronized void appendString(String str, AttributeSet a) {
|
||||
// do this so that it's only updated when needed (otherwise console
|
||||
// updates every 250 ms when an app isn't even running.. see bug 180)
|
||||
hasAppendage = true;
|
||||
|
||||
// process each line of the string
|
||||
while (str.length() > 0) {
|
||||
// newlines within an element have (almost) no effect, so we need to
|
||||
// replace them with proper paragraph breaks (start and end tags)
|
||||
if (needLineBreak || currentLineLength > maxLineLength) {
|
||||
public synchronized void appendString(String text, AttributeSet a) {
|
||||
changed = true;
|
||||
char[] chars = text.toCharArray();
|
||||
int start = 0;
|
||||
int stop = 0;
|
||||
while (stop < chars.length) {
|
||||
char c = chars[stop];
|
||||
stop++;
|
||||
currentLineLength++;
|
||||
if (c == '\n' || currentLineLength > maxLineLength) {
|
||||
elements.add(new ElementSpec(a, ElementSpec.ContentType, chars, start,
|
||||
stop - start));
|
||||
elements.add(new ElementSpec(a, ElementSpec.EndTagType));
|
||||
elements.add(new ElementSpec(a, ElementSpec.StartTagType));
|
||||
currentLineLength = 0;
|
||||
}
|
||||
|
||||
if (str.indexOf('\n') == -1) {
|
||||
elements.add(new ElementSpec(a, ElementSpec.ContentType,
|
||||
str.toCharArray(), 0, str.length()));
|
||||
currentLineLength += str.length();
|
||||
needLineBreak = false;
|
||||
str = str.substring(str.length()); // eat the string
|
||||
} else {
|
||||
elements.add(new ElementSpec(a, ElementSpec.ContentType,
|
||||
str.toCharArray(), 0, str.indexOf('\n') + 1));
|
||||
needLineBreak = true;
|
||||
str = str.substring(str.indexOf('\n') + 1); // eat the line
|
||||
start = stop;
|
||||
}
|
||||
}
|
||||
elements.add(new ElementSpec(a, ElementSpec.ContentType, chars, start,
|
||||
stop - start));
|
||||
}
|
||||
|
||||
/** insert the buffered strings */
|
||||
public synchronized void insertAll() {
|
||||
ElementSpec[] elementArray = new ElementSpec[elements.size()];
|
||||
elements.toArray(elementArray);
|
||||
|
||||
try {
|
||||
// check how many lines have been used so far
|
||||
// Insert new elements at the bottom
|
||||
ElementSpec[] elementArray = elements.toArray(new ElementSpec[0]);
|
||||
insert(getLength(), elementArray);
|
||||
|
||||
// check how many lines have been used
|
||||
// if too many, shave off a few lines from the beginning
|
||||
Element element = super.getDefaultRootElement();
|
||||
int lineCount = element.getElementCount();
|
||||
Element root = getDefaultRootElement();
|
||||
int lineCount = root.getElementCount();
|
||||
int overage = lineCount - maxLineCount;
|
||||
if (overage > 0) {
|
||||
// if 1200 lines, and 1000 lines is max,
|
||||
// find the position of the end of the 200th line
|
||||
//systemOut.println("overage is " + overage);
|
||||
Element lineElement = element.getElement(overage);
|
||||
if (lineElement == null) return; // do nuthin
|
||||
Element lineElement = root.getElement(overage);
|
||||
if (lineElement == null)
|
||||
return; // do nuthin
|
||||
|
||||
int endOffset = lineElement.getEndOffset();
|
||||
// remove to the end of the 200th line
|
||||
super.remove(0, endOffset);
|
||||
int endOffset = lineElement.getEndOffset();
|
||||
remove(0, endOffset);
|
||||
}
|
||||
super.insert(super.getLength(), elementArray);
|
||||
|
||||
} catch (BadLocationException e) {
|
||||
// ignore the error otherwise this will cause an infinite loop
|
||||
// maybe not a good idea in the long run?
|
||||
}
|
||||
elements.clear();
|
||||
hasAppendage = false;
|
||||
changed = false;
|
||||
}
|
||||
|
||||
public boolean isChanged() {
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
150
app/src/processing/app/EditorConsoleStream.java
Normal file
150
app/src/processing/app/EditorConsoleStream.java
Normal file
@ -0,0 +1,150 @@
|
||||
package processing.app;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
class EditorConsoleStream extends OutputStream {
|
||||
static File tempFolder;
|
||||
static File outFile;
|
||||
static File errFile;
|
||||
|
||||
static EditorConsole currentConsole;
|
||||
|
||||
static OutputStream stderrFile;
|
||||
static OutputStream stdoutFile;
|
||||
static PrintStream consoleErr;
|
||||
static PrintStream consoleOut;
|
||||
static public PrintStream systemErr;
|
||||
static public PrintStream systemOut;
|
||||
|
||||
public static void init() {
|
||||
if (systemOut == null) {
|
||||
systemOut = System.out;
|
||||
systemErr = System.err;
|
||||
|
||||
// Create a temporary folder which will have a randomized name. Has to
|
||||
// be randomized otherwise another instance of Processing (or one of its
|
||||
// sister IDEs) might collide with the file causing permissions problems.
|
||||
// The files and folders are not deleted on exit because they may be
|
||||
// needed for debugging or bug reporting.
|
||||
tempFolder = Base.createTempFolder("console");
|
||||
tempFolder.deleteOnExit();
|
||||
try {
|
||||
String outFileName = Preferences.get("console.output.file");
|
||||
if (outFileName != null) {
|
||||
outFile = new File(tempFolder, outFileName);
|
||||
outFile.deleteOnExit();
|
||||
stdoutFile = new FileOutputStream(outFile);
|
||||
}
|
||||
|
||||
String errFileName = Preferences.get("console.error.file");
|
||||
if (errFileName != null) {
|
||||
errFile = new File(tempFolder, errFileName);
|
||||
errFile.deleteOnExit();
|
||||
stderrFile = new FileOutputStream(errFile);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Base.showWarning(_("Console Error"),
|
||||
_("A problem occurred while trying to open the\nfiles used to store the console output."),
|
||||
e);
|
||||
}
|
||||
consoleOut = new PrintStream(new EditorConsoleStream(false));
|
||||
consoleErr = new PrintStream(new EditorConsoleStream(true));
|
||||
|
||||
if (Preferences.getBoolean("console")) {
|
||||
try {
|
||||
System.setOut(consoleOut);
|
||||
System.setErr(consoleErr);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(systemOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the streams so that the temporary files can be deleted.
|
||||
* <p/>
|
||||
* File.deleteOnExit() cannot be used because the stdout and stderr files are
|
||||
* inside a folder, and have to be deleted before the folder itself is
|
||||
* deleted, which can't be guaranteed when using the deleteOnExit() method.
|
||||
*/
|
||||
public static void quit() {
|
||||
// replace original streams to remove references to console's streams
|
||||
System.setOut(systemOut);
|
||||
System.setErr(systemErr);
|
||||
|
||||
// close the PrintStream
|
||||
consoleOut.close();
|
||||
consoleErr.close();
|
||||
|
||||
// also have to close the original FileOutputStream
|
||||
// otherwise it won't be shut down completely
|
||||
try {
|
||||
stdoutFile.close();
|
||||
stderrFile.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
outFile.delete();
|
||||
errFile.delete();
|
||||
tempFolder.delete();
|
||||
}
|
||||
|
||||
final boolean err; // whether stderr or stdout
|
||||
PrintStream system;
|
||||
OutputStream file;
|
||||
|
||||
public EditorConsoleStream(boolean _err) {
|
||||
err = _err;
|
||||
if (err) {
|
||||
system = systemErr;
|
||||
file = stderrFile;
|
||||
} else {
|
||||
system = systemOut;
|
||||
file = stdoutFile;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
public void write(int b) {
|
||||
write(new byte[] { (byte) b });
|
||||
}
|
||||
|
||||
public void write(byte b[]) { // appears never to be used
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void write(byte b[], int offset, int length) {
|
||||
if (currentConsole != null)
|
||||
currentConsole.appendText(new String(b, offset, length), err);
|
||||
|
||||
system.write(b, offset, length);
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
file.write(b, offset, length);
|
||||
file.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
file = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public void setCurrent(EditorConsole console) {
|
||||
currentConsole = console;
|
||||
}
|
||||
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.tools.MenuScroller;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
@ -34,6 +35,7 @@ import javax.swing.*;
|
||||
/**
|
||||
* Sketch tabs at the top of the editor window.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class EditorHeader extends JComponent {
|
||||
static Color backgroundColor;
|
||||
static Color textColor[] = new Color[2];
|
||||
@ -176,7 +178,7 @@ public class EditorHeader extends JComponent {
|
||||
for (int i = 0; i < sketch.getCodeCount(); i++) {
|
||||
SketchCode code = sketch.getCode(i);
|
||||
|
||||
String codeName = sketch.hideExtension(code.getExtension()) ?
|
||||
String codeName = code.isExtension(sketch.getHiddenExtensions()) ?
|
||||
code.getPrettyName() : code.getFileName();
|
||||
|
||||
// if modified, add the li'l glyph next to the name
|
||||
@ -326,30 +328,27 @@ public class EditorHeader extends JComponent {
|
||||
// KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep
|
||||
|
||||
item = new JMenuItem(_("Previous Tab"));
|
||||
KeyStroke ctrlAltLeft =
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
KeyStroke ctrlAltLeft = KeyStroke
|
||||
.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
item.setAccelerator(ctrlAltLeft);
|
||||
// this didn't want to work consistently
|
||||
/*
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.prevCode();
|
||||
}
|
||||
});
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.handlePrevCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem(_("Next Tab"));
|
||||
KeyStroke ctrlAltRight =
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
KeyStroke ctrlAltRight = KeyStroke
|
||||
.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
item.setAccelerator(ctrlAltRight);
|
||||
/*
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.nextCode();
|
||||
}
|
||||
});
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.handleNextCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
Sketch sketch = editor.getSketch();
|
||||
@ -361,7 +360,7 @@ public class EditorHeader extends JComponent {
|
||||
editor.getSketch().setCurrentCode(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
for (SketchCode code : sketch.getCode()) {
|
||||
for (SketchCode code : sketch.getCodes()) {
|
||||
item = new JMenuItem(code.isExtension(sketch.getDefaultExtension()) ?
|
||||
code.getPrettyName() : code.getFileName());
|
||||
item.setActionCommand(code.getFileName());
|
||||
@ -383,7 +382,7 @@ public class EditorHeader extends JComponent {
|
||||
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
return new Dimension(300, Preferences.GRID_SIZE);
|
||||
}
|
||||
return new Dimension(300, Preferences.GRID_SIZE - 1);
|
||||
@ -391,7 +390,7 @@ public class EditorHeader extends JComponent {
|
||||
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
return new Dimension(3000, Preferences.GRID_SIZE);
|
||||
}
|
||||
return new Dimension(3000, Preferences.GRID_SIZE - 1);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.syntax.*;
|
||||
|
||||
import java.awt.*;
|
||||
@ -61,7 +62,7 @@ public class EditorLineStatus extends JComponent {
|
||||
foreground = Theme.getColor("linestatus.color");
|
||||
high = Theme.getInteger("linestatus.height");
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
resize = Base.getThemeImage("resize.gif", this);
|
||||
}
|
||||
//linestatus.bgcolor = #000000
|
||||
@ -118,7 +119,7 @@ public class EditorLineStatus extends JComponent {
|
||||
|
||||
g.drawString(tmp, size.width - (int) bounds.getWidth() -20 , baseline);
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
g.drawImage(resize, size.width - 20, 0, this);
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,13 @@ package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import processing.app.helpers.OSUtils;
|
||||
|
||||
import java.awt.datatransfer.*;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
|
||||
@ -331,7 +335,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ {
|
||||
|
||||
// !@#(* aqua ui #($*(( that turtle-neck wearing #(** (#$@)(
|
||||
// os9 seems to work if bg of component is set, but x still a bastard
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
//yesButton.setBackground(bgcolor[EDIT]);
|
||||
//noButton.setBackground(bgcolor[EDIT]);
|
||||
cancelButton.setBackground(bgcolor[EDIT]);
|
||||
@ -444,7 +448,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ {
|
||||
|
||||
progressBar = new JProgressBar(JScrollBar.HORIZONTAL);
|
||||
progressBar.setIndeterminate(false);
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
//progressBar.setBackground(bgcolor[PROGRESS]);
|
||||
//progressBar.putClientProperty("JProgressBar.style", "circular");
|
||||
}
|
||||
|
@ -26,8 +26,11 @@ import static processing.app.I18n._;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import processing.app.helpers.OSUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Find & Replace window for the Processing editor.
|
||||
@ -47,7 +50,7 @@ import javax.swing.*;
|
||||
@SuppressWarnings("serial")
|
||||
public class FindReplace extends JFrame implements ActionListener {
|
||||
|
||||
static final int EDGE = Base.isMacOS() ? 20 : 13;
|
||||
static final int EDGE = OSUtils.isMacOS() ? 20 : 13;
|
||||
static final int SMALL = 6;
|
||||
static final int BUTTONGAP = 12; // 12 is correct for Mac, other numbers may be required for other platofrms
|
||||
|
||||
@ -143,7 +146,7 @@ public class FindReplace extends JFrame implements ActionListener {
|
||||
buttons.setLayout(new FlowLayout(FlowLayout.CENTER, BUTTONGAP, 0));
|
||||
|
||||
// ordering is different on mac versus pc
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
buttons.add(replaceAllButton = new JButton(_("Replace All")));
|
||||
buttons.add(replaceButton = new JButton(_("Replace")));
|
||||
buttons.add(replaceFindButton = new JButton(_("Replace & Find")));
|
||||
@ -161,7 +164,7 @@ public class FindReplace extends JFrame implements ActionListener {
|
||||
|
||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||
// ugly white border around this object, so turn it off.
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
buttons.setBorder(null);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import javax.swing.undo.CannotUndoException;
|
||||
import javax.swing.undo.UndoManager;
|
||||
import javax.swing.undo.UndoableEdit;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class LastUndoableEditAwareUndoManager extends UndoManager {
|
||||
|
||||
private UndoableEdit lastUndoableEdit;
|
||||
|
@ -28,10 +28,9 @@ public class NetworkMonitor extends AbstractMonitor {
|
||||
private MessageSiphon inputConsumer;
|
||||
private Session session;
|
||||
private Channel channel;
|
||||
private MessageSiphon errorConsumer;
|
||||
private int connectionAttempts;
|
||||
|
||||
public NetworkMonitor(BoardPort port, Base base) {
|
||||
public NetworkMonitor(BoardPort port) {
|
||||
super(port.getLabel());
|
||||
this.port = port;
|
||||
this.ipAddress = port.getAddress();
|
||||
@ -69,7 +68,7 @@ public class NetworkMonitor extends AbstractMonitor {
|
||||
SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
|
||||
session = sshClientSetupChain.setup(port, jSch);
|
||||
|
||||
session.setUserInfo(new NoInteractionUserInfo(Preferences.get(getAuthorizationKey())));
|
||||
session.setUserInfo(new NoInteractionUserInfo(PreferencesData.get(getAuthorizationKey())));
|
||||
session.connect(30000);
|
||||
|
||||
tryConnect();
|
||||
@ -98,7 +97,7 @@ public class NetworkMonitor extends AbstractMonitor {
|
||||
channel.connect();
|
||||
|
||||
inputConsumer = new MessageSiphon(inputStream, this);
|
||||
errorConsumer = new MessageSiphon(errStream, this);
|
||||
new MessageSiphon(errStream, this);
|
||||
|
||||
if (connectionAttempts > 1) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
@ -23,21 +21,39 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.helpers.FileUtils;
|
||||
import processing.app.syntax.SyntaxStyle;
|
||||
import processing.core.PApplet;
|
||||
import processing.core.PConstants;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
import java.awt.SystemColor;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import processing.app.helpers.FileUtils;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesHelper;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
|
||||
/**
|
||||
@ -69,9 +85,7 @@ import static processing.app.I18n._;
|
||||
*/
|
||||
public class Preferences {
|
||||
|
||||
// what to call the feller
|
||||
|
||||
static final String PREFS_FILE = "preferences.txt";
|
||||
static final String PREFS_FILE = PreferencesData.PREFS_FILE;
|
||||
|
||||
class Language {
|
||||
Language(String _name, String _originalName, String _isoCode) {
|
||||
@ -216,85 +230,12 @@ public class Preferences {
|
||||
Editor editor;
|
||||
|
||||
|
||||
// data model
|
||||
|
||||
static Hashtable<String, String> defaults;
|
||||
static Hashtable<String, String> table = new Hashtable<String, String>();
|
||||
static File preferencesFile;
|
||||
static boolean doSave = true;
|
||||
|
||||
|
||||
static protected void init(File file) {
|
||||
if (file != null)
|
||||
preferencesFile = file;
|
||||
else
|
||||
preferencesFile = Base.getSettingsFile(Preferences.PREFS_FILE);
|
||||
|
||||
// start by loading the defaults, in case something
|
||||
// important was deleted from the user prefs
|
||||
try {
|
||||
load(Base.getLibStream("preferences.txt"));
|
||||
} catch (Exception e) {
|
||||
Base.showError(null, _("Could not read default settings.\n" +
|
||||
"You'll need to reinstall Arduino."), e);
|
||||
}
|
||||
|
||||
// set some runtime constants (not saved on preferences file)
|
||||
File hardwareFolder = Base.getHardwareFolder();
|
||||
table.put("runtime.ide.path", hardwareFolder.getParentFile().getAbsolutePath());
|
||||
table.put("runtime.ide.version", "" + Base.REVISION);
|
||||
|
||||
// check for platform-specific properties in the defaults
|
||||
String platformExt = "." + Base.platform.getName();
|
||||
int platformExtLength = platformExt.length();
|
||||
Set<String> keySet = new HashSet<String>(table.keySet());
|
||||
for (String key : keySet) {
|
||||
if (key.endsWith(platformExt)) {
|
||||
// this is a key specific to a particular platform
|
||||
String actualKey = key.substring(0, key.length() - platformExtLength);
|
||||
String value = get(key);
|
||||
table.put(actualKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
// clone the hash table
|
||||
defaults = new Hashtable<String, String>(table);
|
||||
|
||||
if (preferencesFile.exists()) {
|
||||
// load the previous preferences file
|
||||
try {
|
||||
load(new FileInputStream(preferencesFile));
|
||||
} catch (Exception ex) {
|
||||
Base.showError(_("Error reading preferences"),
|
||||
I18n.format(_("Error reading the preferences file. "
|
||||
+ "Please delete (or move)\n"
|
||||
+ "{0} and restart Arduino."),
|
||||
preferencesFile.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
// load the I18n module for internationalization
|
||||
try {
|
||||
I18n.init(Preferences.get("editor.languages.current"));
|
||||
} catch (MissingResourceException e) {
|
||||
I18n.init("en");
|
||||
Preferences.set("editor.languages.current", "en");
|
||||
}
|
||||
|
||||
// set some other runtime constants (not saved on preferences file)
|
||||
table.put("runtime.os", PConstants.platformNames[PApplet.platform]);
|
||||
PreferencesData.init(file);
|
||||
|
||||
// other things that have to be set explicitly for the defaults
|
||||
setColor("run.window.bgcolor", SystemColor.control);
|
||||
|
||||
fixPreferences();
|
||||
}
|
||||
|
||||
private static void fixPreferences() {
|
||||
String baud = get("serial.debug_rate");
|
||||
if ("14400".equals(baud) || "28800".equals(baud) || "38400".equals(baud)) {
|
||||
set("serial.debug_rate", "9600");
|
||||
}
|
||||
PreferencesHelper.putColor(PreferencesData.prefs, "run.window.bgcolor", SystemColor.control);
|
||||
}
|
||||
|
||||
|
||||
@ -371,7 +312,7 @@ public class Preferences {
|
||||
label = new JLabel(_("Editor language: "));
|
||||
box.add(label);
|
||||
comboLanguage = new JComboBox(languages);
|
||||
String currentLanguage = Preferences.get("editor.languages.current");
|
||||
String currentLanguage = PreferencesData.get("editor.languages.current");
|
||||
for (Language language : languages) {
|
||||
if (language.isoCode.equals(currentLanguage))
|
||||
comboLanguage.setSelectedItem(language);
|
||||
@ -465,7 +406,7 @@ public class Preferences {
|
||||
|
||||
// [ ] Automatically associate .pde files with Processing
|
||||
|
||||
if (Base.isWindows()) {
|
||||
if (OSUtils.isWindows()) {
|
||||
autoAssociateBox =
|
||||
new JCheckBox(_("Automatically associate .ino files with Arduino"));
|
||||
pain.add(autoAssociateBox);
|
||||
@ -498,11 +439,11 @@ public class Preferences {
|
||||
right = Math.max(right, left + d.width);
|
||||
top += d.height; // + GUI_SMALL;
|
||||
|
||||
label = new JLabel(preferencesFile.getAbsolutePath());
|
||||
label = new JLabel(PreferencesData.preferencesFile.getAbsolutePath());
|
||||
final JLabel clickable = label;
|
||||
label.addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
Base.openFolder(preferencesFile.getParentFile());
|
||||
Base.openFolder(PreferencesData.preferencesFile.getParentFile());
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
@ -604,11 +545,6 @@ public class Preferences {
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(wide, high);
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
@ -626,34 +562,34 @@ public class Preferences {
|
||||
*/
|
||||
protected void applyFrame() {
|
||||
// put each of the settings into the table
|
||||
setBoolean("build.verbose", verboseCompilationBox.isSelected());
|
||||
setBoolean("upload.verbose", verboseUploadBox.isSelected());
|
||||
setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected());
|
||||
setBoolean("upload.verify", verifyUploadBox.isSelected());
|
||||
setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
|
||||
|
||||
PreferencesData.setBoolean("build.verbose", verboseCompilationBox.isSelected());
|
||||
PreferencesData.setBoolean("upload.verbose", verboseUploadBox.isSelected());
|
||||
PreferencesData.setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected());
|
||||
PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected());
|
||||
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
|
||||
|
||||
// setBoolean("sketchbook.closing_last_window_quits",
|
||||
// closingLastQuitsBox.isSelected());
|
||||
//setBoolean("sketchbook.prompt", sketchPromptBox.isSelected());
|
||||
//setBoolean("sketchbook.auto_clean", sketchCleanBox.isSelected());
|
||||
|
||||
// if the sketchbook path has changed, rebuild the menus
|
||||
String oldPath = get("sketchbook.path");
|
||||
String oldPath = PreferencesData.get("sketchbook.path");
|
||||
String newPath = sketchbookLocationField.getText();
|
||||
if (newPath.isEmpty()) {
|
||||
if (Base.getPortableFolder() == null)
|
||||
newPath = editor.base.getDefaultSketchbookFolder().toString();
|
||||
newPath = editor.base.getDefaultSketchbookFolderOrPromptForIt().toString();
|
||||
else
|
||||
newPath = Base.getPortableSketchbookFolder();
|
||||
}
|
||||
if (!newPath.equals(oldPath)) {
|
||||
editor.base.rebuildSketchbookMenus();
|
||||
set("sketchbook.path", newPath);
|
||||
PreferencesData.set("sketchbook.path", newPath);
|
||||
}
|
||||
|
||||
setBoolean("editor.external", externalEditorBox.isSelected());
|
||||
setBoolean("update.check", checkUpdatesBox.isSelected());
|
||||
setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
|
||||
PreferencesData.setBoolean("editor.external", externalEditorBox.isSelected());
|
||||
PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected());
|
||||
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
|
||||
|
||||
/*
|
||||
// was gonna use this to check memory settings,
|
||||
@ -670,24 +606,24 @@ public class Preferences {
|
||||
String newSizeText = fontSizeField.getText();
|
||||
try {
|
||||
int newSize = Integer.parseInt(newSizeText.trim());
|
||||
String pieces[] = PApplet.split(get("editor.font"), ',');
|
||||
String pieces[] = PApplet.split(PreferencesData.get("editor.font"), ',');
|
||||
pieces[2] = String.valueOf(newSize);
|
||||
set("editor.font", PApplet.join(pieces, ','));
|
||||
PreferencesData.set("editor.font", PApplet.join(pieces, ','));
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println(I18n.format(_("ignoring invalid font size {0}"), newSizeText));
|
||||
}
|
||||
|
||||
if (autoAssociateBox != null) {
|
||||
setBoolean("platform.auto_file_type_associations",
|
||||
PreferencesData.setBoolean("platform.auto_file_type_associations",
|
||||
autoAssociateBox.isSelected());
|
||||
}
|
||||
|
||||
setBoolean("editor.update_extension", updateExtensionBox.isSelected());
|
||||
PreferencesData.setBoolean("editor.update_extension", updateExtensionBox.isSelected());
|
||||
|
||||
// adds the selected language to the preferences file
|
||||
Language newLanguage = (Language) comboLanguage.getSelectedItem();
|
||||
set("editor.languages.current", newLanguage.isoCode);
|
||||
PreferencesData.set("editor.languages.current", newLanguage.isoCode);
|
||||
|
||||
editor.applyPreferences();
|
||||
}
|
||||
@ -697,10 +633,10 @@ public class Preferences {
|
||||
this.editor = editor;
|
||||
|
||||
// set all settings entry boxes to their actual status
|
||||
verboseCompilationBox.setSelected(getBoolean("build.verbose"));
|
||||
verboseUploadBox.setSelected(getBoolean("upload.verbose"));
|
||||
displayLineNumbersBox.setSelected(getBoolean("editor.linenumbers"));
|
||||
verifyUploadBox.setSelected(getBoolean("upload.verify"));
|
||||
verboseCompilationBox.setSelected(PreferencesData.getBoolean("build.verbose"));
|
||||
verboseUploadBox.setSelected(PreferencesData.getBoolean("upload.verbose"));
|
||||
displayLineNumbersBox.setSelected(PreferencesData.getBoolean("editor.linenumbers"));
|
||||
verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify"));
|
||||
|
||||
//closingLastQuitsBox.
|
||||
// setSelected(getBoolean("sketchbook.closing_last_window_quits"));
|
||||
@ -710,294 +646,95 @@ public class Preferences {
|
||||
// setSelected(getBoolean("sketchbook.auto_clean"));
|
||||
|
||||
sketchbookLocationField.
|
||||
setText(get("sketchbook.path"));
|
||||
setText(PreferencesData.get("sketchbook.path"));
|
||||
externalEditorBox.
|
||||
setSelected(getBoolean("editor.external"));
|
||||
setSelected(PreferencesData.getBoolean("editor.external"));
|
||||
checkUpdatesBox.
|
||||
setSelected(getBoolean("update.check"));
|
||||
setSelected(PreferencesData.getBoolean("update.check"));
|
||||
saveVerifyUploadBox.
|
||||
setSelected(getBoolean("editor.save_on_verify"));
|
||||
setSelected(PreferencesData.getBoolean("editor.save_on_verify"));
|
||||
|
||||
if (autoAssociateBox != null) {
|
||||
autoAssociateBox.
|
||||
setSelected(getBoolean("platform.auto_file_type_associations"));
|
||||
setSelected(PreferencesData.getBoolean("platform.auto_file_type_associations"));
|
||||
}
|
||||
|
||||
updateExtensionBox.setSelected(get("editor.update_extension") == null ||
|
||||
getBoolean("editor.update_extension"));
|
||||
updateExtensionBox.setSelected(PreferencesData.get("editor.update_extension") == null ||
|
||||
PreferencesData.getBoolean("editor.update_extension"));
|
||||
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
static protected void load(InputStream input) throws IOException {
|
||||
load(input, table);
|
||||
}
|
||||
|
||||
static public void load(InputStream input, Map<String, String> table) throws IOException {
|
||||
String[] lines = loadStrings(input); // Reads as UTF-8
|
||||
for (String line : lines) {
|
||||
if ((line.length() == 0) ||
|
||||
(line.charAt(0) == '#')) continue;
|
||||
|
||||
// this won't properly handle = signs being in the text
|
||||
int equals = line.indexOf('=');
|
||||
if (equals != -1) {
|
||||
String key = line.substring(0, equals).trim();
|
||||
String value = line.substring(equals + 1).trim();
|
||||
table.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public String[] loadStrings(InputStream input) {
|
||||
try {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
|
||||
String lines[] = new String[100];
|
||||
int lineCount = 0;
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (lineCount == lines.length) {
|
||||
String temp[] = new String[lineCount << 1];
|
||||
System.arraycopy(lines, 0, temp, 0, lineCount);
|
||||
lines = temp;
|
||||
}
|
||||
lines[lineCount++] = line;
|
||||
}
|
||||
reader.close();
|
||||
|
||||
if (lineCount == lines.length) {
|
||||
return lines;
|
||||
}
|
||||
|
||||
// resize array to appropriate amount for these lines
|
||||
String output[] = new String[lineCount];
|
||||
System.arraycopy(lines, 0, output, 0, lineCount);
|
||||
return output;
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
//throw new RuntimeException("Error inside loadStrings()");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
static protected void save() {
|
||||
if (!doSave) return;
|
||||
// try {
|
||||
// on startup, don't worry about it
|
||||
// this is trying to update the prefs for who is open
|
||||
// before Preferences.init() has been called.
|
||||
if (preferencesFile == null) return;
|
||||
|
||||
// Fix for 0163 to properly use Unicode when writing preferences.txt
|
||||
PrintWriter writer = PApplet.createWriter(preferencesFile);
|
||||
|
||||
String[] keys = table.keySet().toArray(new String[0]);
|
||||
Arrays.sort(keys);
|
||||
for (String key: keys) {
|
||||
if (key.startsWith("runtime."))
|
||||
continue;
|
||||
writer.println(key + "=" + table.get(key));
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
// } catch (Exception ex) {
|
||||
// Base.showWarning(null, "Error while saving the settings file", ex);
|
||||
// }
|
||||
PreferencesData.save();
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
|
||||
// all the information from preferences.txt
|
||||
|
||||
//static public String get(String attribute) {
|
||||
//return get(attribute, null);
|
||||
//}
|
||||
|
||||
static public String get(String attribute) {
|
||||
return table.get(attribute);
|
||||
return PreferencesData.get(attribute);
|
||||
}
|
||||
|
||||
static public String get(String attribute, String defaultValue) {
|
||||
String value = get(attribute);
|
||||
|
||||
return (value == null) ? defaultValue : value;
|
||||
return PreferencesData.get(attribute, defaultValue);
|
||||
}
|
||||
|
||||
public static boolean has(String key) {
|
||||
return table.containsKey(key);
|
||||
return PreferencesData.has(key);
|
||||
}
|
||||
|
||||
public static void remove(String key) {
|
||||
table.remove(key);
|
||||
}
|
||||
|
||||
static public String getDefault(String attribute) {
|
||||
return defaults.get(attribute);
|
||||
PreferencesData.remove(key);
|
||||
}
|
||||
|
||||
|
||||
static public void set(String attribute, String value) {
|
||||
table.put(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public void unset(String attribute) {
|
||||
table.remove(attribute);
|
||||
PreferencesData.set(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public boolean getBoolean(String attribute) {
|
||||
String value = get(attribute); //, null);
|
||||
return (new Boolean(value)).booleanValue();
|
||||
|
||||
/*
|
||||
supposedly not needed, because anything besides 'true'
|
||||
(ignoring case) will just be false.. so if malformed -> false
|
||||
if (value == null) return defaultValue;
|
||||
|
||||
try {
|
||||
return (new Boolean(value)).booleanValue();
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("expecting an integer: " + attribute + " = " + value);
|
||||
}
|
||||
return defaultValue;
|
||||
*/
|
||||
return PreferencesData.getBoolean(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void setBoolean(String attribute, boolean value) {
|
||||
set(attribute, value ? "true" : "false");
|
||||
PreferencesData.setBoolean(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public int getInteger(String attribute /*, int defaultValue*/) {
|
||||
return Integer.parseInt(get(attribute));
|
||||
|
||||
/*
|
||||
String value = get(attribute, null);
|
||||
if (value == null) return defaultValue;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
// ignored will just fall through to returning the default
|
||||
System.err.println("expecting an integer: " + attribute + " = " + value);
|
||||
}
|
||||
return defaultValue;
|
||||
//if (value == null) return defaultValue;
|
||||
//return (value == null) ? defaultValue :
|
||||
//Integer.parseInt(value);
|
||||
*/
|
||||
static public int getInteger(String attribute) {
|
||||
return PreferencesData.getInteger(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void setInteger(String key, int value) {
|
||||
set(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
|
||||
static public Color getColor(String name) {
|
||||
Color parsed = Color.GRAY; // set a default
|
||||
String s = get(name);
|
||||
if ((s != null) && (s.indexOf("#") == 0)) {
|
||||
try {
|
||||
parsed = new Color(Integer.parseInt(s.substring(1), 16));
|
||||
} catch (Exception e) { }
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
|
||||
static public void setColor(String attr, Color what) {
|
||||
set(attr, "#" + PApplet.hex(what.getRGB() & 0xffffff, 6));
|
||||
PreferencesData.setInteger(key, value);
|
||||
}
|
||||
|
||||
|
||||
static public Font getFont(String attr) {
|
||||
boolean replace = false;
|
||||
String value = get(attr);
|
||||
if (value == null) {
|
||||
//System.out.println("reset 1");
|
||||
value = getDefault(attr);
|
||||
replace = true;
|
||||
Font font = PreferencesHelper.getFont(PreferencesData.prefs, attr);
|
||||
if (font == null) {
|
||||
String value = PreferencesData.defaults.get(attr);
|
||||
PreferencesData.prefs.put(attr, value);
|
||||
font = PreferencesHelper.getFont(PreferencesData.prefs, attr);
|
||||
}
|
||||
|
||||
String[] pieces = PApplet.split(value, ',');
|
||||
if (pieces.length != 3) {
|
||||
value = getDefault(attr);
|
||||
//System.out.println("reset 2 for " + attr);
|
||||
pieces = PApplet.split(value, ',');
|
||||
//PApplet.println(pieces);
|
||||
replace = true;
|
||||
}
|
||||
|
||||
String name = pieces[0];
|
||||
int style = Font.PLAIN; // equals zero
|
||||
if (pieces[1].indexOf("bold") != -1) {
|
||||
style |= Font.BOLD;
|
||||
}
|
||||
if (pieces[1].indexOf("italic") != -1) {
|
||||
style |= Font.ITALIC;
|
||||
}
|
||||
int size = PApplet.parseInt(pieces[2], 12);
|
||||
Font font = new Font(name, style, size);
|
||||
|
||||
// replace bad font with the default
|
||||
if (replace) {
|
||||
set(attr, value);
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
static public SyntaxStyle getStyle(String what /*, String dflt*/) {
|
||||
String str = get("editor." + what + ".style"); //, dflt);
|
||||
|
||||
StringTokenizer st = new StringTokenizer(str, ",");
|
||||
|
||||
String s = st.nextToken();
|
||||
if (s.indexOf("#") == 0) s = s.substring(1);
|
||||
Color color = Color.DARK_GRAY;
|
||||
try {
|
||||
color = new Color(Integer.parseInt(s, 16));
|
||||
} catch (Exception e) { }
|
||||
|
||||
s = st.nextToken();
|
||||
boolean bold = (s.indexOf("bold") != -1);
|
||||
boolean italic = (s.indexOf("italic") != -1);
|
||||
boolean underlined = (s.indexOf("underlined") != -1);
|
||||
//System.out.println(what + " = " + str + " " + bold + " " + italic);
|
||||
|
||||
return new SyntaxStyle(color, italic, bold, underlined);
|
||||
}
|
||||
|
||||
// get a copy of the Preferences
|
||||
static public PreferencesMap getMap()
|
||||
{
|
||||
return new PreferencesMap(table);
|
||||
return PreferencesData.getMap();
|
||||
}
|
||||
|
||||
// Decide wether changed preferences will be saved. When value is
|
||||
// false, Preferences.save becomes a no-op.
|
||||
static public void setDoSave(boolean value)
|
||||
{
|
||||
doSave = value;
|
||||
PreferencesData.setDoSave(value);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
package processing.app;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -27,6 +27,7 @@ import java.awt.event.ActionListener;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class SerialMonitor extends AbstractMonitor {
|
||||
|
||||
private final String port;
|
||||
|
@ -23,24 +23,17 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.UploaderAndMonitorFactory;
|
||||
|
||||
import cc.arduino.packages.Uploader;
|
||||
import processing.app.debug.*;
|
||||
import processing.app.debug.Compiler;
|
||||
import processing.app.debug.Compiler.ProgressListener;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.forms.PasswordAuthorizationDialog;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.FileUtils;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.packages.Library;
|
||||
import processing.app.packages.LibraryList;
|
||||
import processing.app.preproc.*;
|
||||
import processing.core.*;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@ -53,69 +46,24 @@ public class Sketch {
|
||||
|
||||
private Editor editor;
|
||||
|
||||
/** main pde file for this sketch. */
|
||||
private File primaryFile;
|
||||
|
||||
/**
|
||||
* Name of sketch, which is the name of main file
|
||||
* (without .pde or .java extension)
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/** true if any of the files have been modified. */
|
||||
private boolean modified;
|
||||
|
||||
/** folder that contains this sketch */
|
||||
private File folder;
|
||||
|
||||
/** data folder location for this sketch (may not exist yet) */
|
||||
private File dataFolder;
|
||||
|
||||
/** code folder location for this sketch (may not exist yet) */
|
||||
private File codeFolder;
|
||||
|
||||
private SketchCode current;
|
||||
private SketchCodeDocument current;
|
||||
private int currentIndex;
|
||||
/**
|
||||
* Number of sketchCode objects (tabs) in the current sketch. Note that this
|
||||
* will be the same as code.length, because the getCode() method returns
|
||||
* just the code[] array, rather than a copy of it, or an array that's been
|
||||
* resized to just the relevant files themselves.
|
||||
* http://dev.processing.org/bugs/show_bug.cgi?id=940
|
||||
*/
|
||||
private int codeCount;
|
||||
private SketchCode[] code;
|
||||
|
||||
private SketchData data;
|
||||
|
||||
/** Class name for the PApplet, as determined by the preprocessor. */
|
||||
private String appletClassName;
|
||||
/** Class path determined during build. */
|
||||
private String classPath;
|
||||
|
||||
/**
|
||||
* List of library folders.
|
||||
*/
|
||||
private LibraryList importedLibraries;
|
||||
|
||||
/**
|
||||
* File inside the build directory that contains the build options
|
||||
* used for the last build.
|
||||
*/
|
||||
static final String BUILD_PREFS_FILE = "buildprefs.txt";
|
||||
|
||||
/**
|
||||
* path is location of the main .pde file, because this is also
|
||||
* simplest to use when opening the file from the finder/explorer.
|
||||
*/
|
||||
public Sketch(Editor editor, File file) throws IOException {
|
||||
this.editor = editor;
|
||||
|
||||
primaryFile = file;
|
||||
|
||||
// get the name of the sketch by chopping .pde or .java
|
||||
// off of the main file name
|
||||
String mainFilename = primaryFile.getName();
|
||||
int suffixLength = getDefaultExtension().length() + 1;
|
||||
name = mainFilename.substring(0, mainFilename.length() - suffixLength);
|
||||
public Sketch(Editor _editor, File file) throws IOException {
|
||||
editor = _editor;
|
||||
data = new SketchData(file);
|
||||
|
||||
// lib/build must exist when the application is started
|
||||
// it is added to the CLASSPATH by default, but if it doesn't
|
||||
@ -136,9 +84,6 @@ public class Sketch {
|
||||
tempBuildFolder = Base.getBuildFolder();
|
||||
//Base.addBuildFolderToClassPath();
|
||||
|
||||
folder = new File(file.getParent());
|
||||
//System.out.println("sketch dir is " + folder);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@ -158,69 +103,13 @@ public class Sketch {
|
||||
* in which case the load happens each time "run" is hit.
|
||||
*/
|
||||
protected void load() throws IOException {
|
||||
codeFolder = new File(folder, "code");
|
||||
dataFolder = new File(folder, "data");
|
||||
data.load();
|
||||
|
||||
// get list of files in the sketch folder
|
||||
String list[] = folder.list();
|
||||
|
||||
// reset these because load() may be called after an
|
||||
// external editor event. (fix for 0099)
|
||||
codeCount = 0;
|
||||
|
||||
code = new SketchCode[list.length];
|
||||
|
||||
String[] extensions = getExtensions();
|
||||
|
||||
for (String filename : list) {
|
||||
// Ignoring the dot prefix files is especially important to avoid files
|
||||
// with the ._ prefix on Mac OS X. (You'll see this with Mac files on
|
||||
// non-HFS drives, i.e. a thumb drive formatted FAT32.)
|
||||
if (filename.startsWith(".")) continue;
|
||||
|
||||
// Don't let some wacko name a directory blah.pde or bling.java.
|
||||
if (new File(folder, filename).isDirectory()) continue;
|
||||
|
||||
// figure out the name without any extension
|
||||
String base = filename;
|
||||
// now strip off the .pde and .java extensions
|
||||
for (String extension : extensions) {
|
||||
if (base.toLowerCase().endsWith("." + extension)) {
|
||||
base = base.substring(0, base.length() - (extension.length() + 1));
|
||||
|
||||
// Don't allow people to use files with invalid names, since on load,
|
||||
// it would be otherwise possible to sneak in nasty filenames. [0116]
|
||||
if (Sketch.isSanitaryName(base)) {
|
||||
code[codeCount++] =
|
||||
new SketchCode(new File(folder, filename), extension);
|
||||
} else {
|
||||
editor.console.message(I18n.format("File name {0} is invalid: ignored", filename), true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (code.getMetadata() == null)
|
||||
code.setMetadata(new SketchCodeDocument(code));
|
||||
}
|
||||
|
||||
if (codeCount == 0)
|
||||
throw new IOException(_("No valid code files found"));
|
||||
|
||||
// Remove any code that wasn't proper
|
||||
code = (SketchCode[]) PApplet.subset(code, 0, codeCount);
|
||||
|
||||
// move the main class to the first tab
|
||||
// start at 1, if it's at zero, don't bother
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
//if (code[i].file.getName().equals(mainFilename)) {
|
||||
if (code[i].getFile().equals(primaryFile)) {
|
||||
SketchCode temp = code[0];
|
||||
code[0] = code[i];
|
||||
code[i] = temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sort the entries at the top
|
||||
sortCode();
|
||||
|
||||
// set the main file to be the current tab
|
||||
if (editor != null) {
|
||||
setCurrentCode(0);
|
||||
@ -228,47 +117,6 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
protected void replaceCode(SketchCode newCode) {
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (code[i].getFileName().equals(newCode.getFileName())) {
|
||||
code[i] = newCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void insertCode(SketchCode newCode) {
|
||||
// make sure the user didn't hide the sketch folder
|
||||
ensureExistence();
|
||||
|
||||
// add file to the code/codeCount list, resort the list
|
||||
//if (codeCount == code.length) {
|
||||
code = (SketchCode[]) PApplet.append(code, newCode);
|
||||
codeCount++;
|
||||
//}
|
||||
//code[codeCount++] = newCode;
|
||||
}
|
||||
|
||||
|
||||
protected void sortCode() {
|
||||
// cheap-ass sort of the rest of the files
|
||||
// it's a dumb, slow sort, but there shouldn't be more than ~5 files
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
int who = i;
|
||||
for (int j = i + 1; j < codeCount; j++) {
|
||||
if (code[j].getFileName().compareTo(code[who].getFileName()) < 0) {
|
||||
who = j; // this guy is earlier in the alphabet
|
||||
}
|
||||
}
|
||||
if (who != i) { // swap with someone if changes made
|
||||
SketchCode temp = code[who];
|
||||
code[who] = code[i];
|
||||
code[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean renamingCode;
|
||||
|
||||
/**
|
||||
@ -322,8 +170,8 @@ public class Sketch {
|
||||
renamingCode = true;
|
||||
String prompt = (currentIndex == 0) ?
|
||||
"New name for sketch:" : "New name for file:";
|
||||
String oldName = (current.isExtension("ino")) ?
|
||||
current.getPrettyName() : current.getFileName();
|
||||
String oldName = (current.getCode().isExtension("ino")) ?
|
||||
current.getCode().getPrettyName() : current.getCode().getFileName();
|
||||
editor.status.edit(prompt, oldName);
|
||||
}
|
||||
|
||||
@ -350,7 +198,7 @@ public class Sketch {
|
||||
// (osx is case insensitive but preserving, windows insensitive,
|
||||
// *nix is sensitive and preserving.. argh)
|
||||
if (renamingCode) {
|
||||
if (newName.equalsIgnoreCase(current.getFileName())) {
|
||||
if (newName.equalsIgnoreCase(current.getCode().getFileName())) {
|
||||
// exit quietly for the 'rename' case.
|
||||
// if it's a 'new' then an error will occur down below
|
||||
return;
|
||||
@ -379,7 +227,7 @@ public class Sketch {
|
||||
// Don't let the user create the main tab as a .java file instead of .pde
|
||||
if (!isDefaultExtension(newExtension)) {
|
||||
if (renamingCode) { // If creating a new tab, don't show this error
|
||||
if (current == code[0]) { // If this is the main tab, disallow
|
||||
if (current.getCode() == data.getCode(0)) { // If this is the main tab, disallow
|
||||
Base.showWarning(_("Problem with rename"),
|
||||
_("The main file can't use an extension.\n" +
|
||||
"(It may be time for your to graduate to a\n" +
|
||||
@ -393,7 +241,7 @@ public class Sketch {
|
||||
// make sure the user didn't name things poo.time.pde
|
||||
// or something like that (nothing against poo time)
|
||||
String shortName = newName.substring(0, dot);
|
||||
String sanitaryName = Sketch.sanitizeName(shortName);
|
||||
String sanitaryName = BaseNoGui.sanitizeName(shortName);
|
||||
if (!shortName.equals(sanitaryName)) {
|
||||
newName = sanitaryName + "." + newExtension;
|
||||
}
|
||||
@ -401,13 +249,13 @@ public class Sketch {
|
||||
// In Arduino, we want to allow files with the same name but different
|
||||
// extensions, so compare the full names (including extensions). This
|
||||
// might cause problems: http://dev.processing.org/bugs/show_bug.cgi?id=543
|
||||
for (SketchCode c : code) {
|
||||
for (SketchCode c : data.getCodes()) {
|
||||
if (newName.equalsIgnoreCase(c.getFileName())) {
|
||||
Base.showMessage(_("Nope"),
|
||||
I18n.format(
|
||||
_("A file named \"{0}\" already exists in \"{1}\""),
|
||||
c.getFileName(),
|
||||
folder.getAbsolutePath()
|
||||
data.getFolder().getAbsolutePath()
|
||||
));
|
||||
return;
|
||||
}
|
||||
@ -423,22 +271,20 @@ public class Sketch {
|
||||
}
|
||||
|
||||
if (renamingCode && currentIndex == 0) {
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
if (sanitaryName.equalsIgnoreCase(code[i].getPrettyName()) &&
|
||||
code[i].getExtension().equalsIgnoreCase("cpp")) {
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (sanitaryName.equalsIgnoreCase(code.getPrettyName()) &&
|
||||
code.isExtension("cpp")) {
|
||||
Base.showMessage(_("Nope"),
|
||||
I18n.format(
|
||||
_("You can't rename the sketch to \"{0}\"\n" +
|
||||
"because the sketch already has a .cpp file with that name."),
|
||||
sanitaryName
|
||||
));
|
||||
I18n.format(_("You can't rename the sketch to \"{0}\"\n"
|
||||
+ "because the sketch already has a .cpp file with that name."),
|
||||
sanitaryName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File newFile = new File(folder, newName);
|
||||
File newFile = new File(data.getFolder(), newName);
|
||||
// if (newFile.exists()) { // yay! users will try anything
|
||||
// Base.showMessage("Nope",
|
||||
// "A file named \"" + newFile + "\" already exists\n" +
|
||||
@ -460,7 +306,7 @@ public class Sketch {
|
||||
if (currentIndex == 0) {
|
||||
// get the new folder name/location
|
||||
String folderName = newName.substring(0, newName.indexOf('.'));
|
||||
File newFolder = new File(folder.getParentFile(), folderName);
|
||||
File newFolder = new File(data.getFolder().getParentFile(), folderName);
|
||||
if (newFolder.exists()) {
|
||||
Base.showWarning(_("Cannot Rename"),
|
||||
I18n.format(
|
||||
@ -476,22 +322,22 @@ public class Sketch {
|
||||
// however this *will* first save the sketch, then rename
|
||||
|
||||
// first get the contents of the editor text area
|
||||
if (current.isModified()) {
|
||||
current.setProgram(editor.getText());
|
||||
if (current.getCode().isModified()) {
|
||||
current.getCode().setProgram(editor.getText());
|
||||
try {
|
||||
// save this new SketchCode
|
||||
current.save();
|
||||
current.getCode().save();
|
||||
} catch (Exception e) {
|
||||
Base.showWarning(_("Error"), _("Could not rename the sketch. (0)"), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current.renameTo(newFile, newExtension)) {
|
||||
if (!current.getCode().renameTo(newFile)) {
|
||||
Base.showWarning(_("Error"),
|
||||
I18n.format(
|
||||
_("Could not rename \"{0}\" to \"{1}\""),
|
||||
current.getFileName(),
|
||||
current.getCode().getFileName(),
|
||||
newFile.getName()
|
||||
), null);
|
||||
return;
|
||||
@ -499,8 +345,8 @@ public class Sketch {
|
||||
|
||||
// save each of the other tabs because this is gonna be re-opened
|
||||
try {
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
code[i].save();
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
code.save();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Base.showWarning(_("Error"), _("Could not rename the sketch. (1)"), e);
|
||||
@ -508,7 +354,7 @@ public class Sketch {
|
||||
}
|
||||
|
||||
// now rename the sketch folder and re-open
|
||||
boolean success = folder.renameTo(newFolder);
|
||||
boolean success = data.getFolder().renameTo(newFolder);
|
||||
if (!success) {
|
||||
Base.showWarning(_("Error"), _("Could not rename the sketch. (2)"), null);
|
||||
return;
|
||||
@ -531,11 +377,11 @@ public class Sketch {
|
||||
editor.base.rebuildSketchbookMenus();
|
||||
|
||||
} else { // else if something besides code[0]
|
||||
if (!current.renameTo(newFile, newExtension)) {
|
||||
if (!current.getCode().renameTo(newFile)) {
|
||||
Base.showWarning(_("Error"),
|
||||
I18n.format(
|
||||
_("Could not rename \"{0}\" to \"{1}\""),
|
||||
current.getFileName(),
|
||||
current.getCode().getFileName(),
|
||||
newFile.getName()
|
||||
), null);
|
||||
return;
|
||||
@ -553,17 +399,16 @@ public class Sketch {
|
||||
I18n.format(
|
||||
"Could not create the file \"{0}\" in \"{1}\"",
|
||||
newFile,
|
||||
folder.getAbsolutePath()
|
||||
data.getFolder().getAbsolutePath()
|
||||
), e);
|
||||
return;
|
||||
}
|
||||
SketchCode newCode = new SketchCode(newFile, newExtension);
|
||||
//System.out.println("new code is named " + newCode.getPrettyName() + " " + newCode.getFile());
|
||||
insertCode(newCode);
|
||||
ensureExistence();
|
||||
data.addCode((new SketchCodeDocument(newFile)).getCode());
|
||||
}
|
||||
|
||||
// sort the entries
|
||||
sortCode();
|
||||
data.sortCode();
|
||||
|
||||
// set the new guy as current
|
||||
setCurrentCode(newName);
|
||||
@ -594,7 +439,7 @@ public class Sketch {
|
||||
Object[] options = { _("OK"), _("Cancel") };
|
||||
String prompt = (currentIndex == 0) ?
|
||||
_("Are you sure you want to delete this sketch?") :
|
||||
I18n.format(_("Are you sure you want to delete \"{0}\"?"), current.getPrettyName());
|
||||
I18n.format(_("Are you sure you want to delete \"{0}\"?"), current.getCode().getPrettyName());
|
||||
int result = JOptionPane.showOptionDialog(editor,
|
||||
prompt,
|
||||
_("Delete"),
|
||||
@ -609,7 +454,7 @@ public class Sketch {
|
||||
// to do a save on the handleNew()
|
||||
|
||||
// delete the entire sketch
|
||||
Base.removeDir(folder);
|
||||
Base.removeDir(data.getFolder());
|
||||
|
||||
// get the changes into the sketchbook menu
|
||||
//sketchbook.rebuildMenus();
|
||||
@ -621,14 +466,14 @@ public class Sketch {
|
||||
|
||||
} else {
|
||||
// delete the file
|
||||
if (!current.deleteFile(tempBuildFolder)) {
|
||||
if (!current.getCode().deleteFile(tempBuildFolder)) {
|
||||
Base.showMessage(_("Couldn't do it"),
|
||||
I18n.format(_("Could not delete \"{0}\"."), current.getFileName()));
|
||||
I18n.format(_("Could not delete \"{0}\"."), current.getCode().getFileName()));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove code from the list
|
||||
removeCode(current);
|
||||
data.removeCode(current.getCode());
|
||||
|
||||
// just set current tab to the main tab
|
||||
setCurrentCode(0);
|
||||
@ -640,29 +485,12 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
protected void removeCode(SketchCode which) {
|
||||
// remove it from the internal list of files
|
||||
// resort internal list of files
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (code[i] == which) {
|
||||
for (int j = i; j < codeCount-1; j++) {
|
||||
code[j] = code[j+1];
|
||||
}
|
||||
codeCount--;
|
||||
code = (SketchCode[]) PApplet.shorten(code);
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.err.println(_("removeCode: internal error.. could not find code"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move to the previous tab.
|
||||
*/
|
||||
public void handlePrevCode() {
|
||||
int prev = currentIndex - 1;
|
||||
if (prev < 0) prev = codeCount-1;
|
||||
if (prev < 0) prev = data.getCodeCount()-1;
|
||||
setCurrentCode(prev);
|
||||
}
|
||||
|
||||
@ -671,7 +499,7 @@ public class Sketch {
|
||||
* Move to the next tab.
|
||||
*/
|
||||
public void handleNextCode() {
|
||||
setCurrentCode((currentIndex + 1) % codeCount);
|
||||
setCurrentCode((currentIndex + 1) % data.getCodeCount());
|
||||
}
|
||||
|
||||
|
||||
@ -681,22 +509,22 @@ public class Sketch {
|
||||
public void setModified(boolean state) {
|
||||
//System.out.println("setting modified to " + state);
|
||||
//new Exception().printStackTrace();
|
||||
current.setModified(state);
|
||||
current.getCode().setModified(state);
|
||||
calcModified();
|
||||
}
|
||||
|
||||
|
||||
protected void calcModified() {
|
||||
modified = false;
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (code[i].isModified()) {
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (code.isModified()) {
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
editor.header.repaint();
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
// http://developer.apple.com/qa/qa2001/qa1146.html
|
||||
Object modifiedParam = modified ? Boolean.TRUE : Boolean.FALSE;
|
||||
editor.getRootPane().putClientProperty("windowModified", modifiedParam);
|
||||
@ -717,8 +545,8 @@ public class Sketch {
|
||||
ensureExistence();
|
||||
|
||||
// first get the contents of the editor text area
|
||||
if (current.isModified()) {
|
||||
current.setProgram(editor.getText());
|
||||
if (current.getCode().isModified()) {
|
||||
current.getCode().setProgram(editor.getText());
|
||||
}
|
||||
|
||||
// don't do anything if not actually modified
|
||||
@ -772,23 +600,20 @@ public class Sketch {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (code[i].isModified())
|
||||
code[i].save();
|
||||
}
|
||||
data.save();
|
||||
calcModified();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected boolean renameCodeToInoExtension(File pdeFile) {
|
||||
for (SketchCode c : code) {
|
||||
for (SketchCode c : data.getCodes()) {
|
||||
if (!c.getFile().equals(pdeFile))
|
||||
continue;
|
||||
|
||||
String pdeName = pdeFile.getPath();
|
||||
pdeName = pdeName.substring(0, pdeName.length() - 4) + ".ino";
|
||||
return c.renameTo(new File(pdeName), "ino");
|
||||
return c.renameTo(new File(pdeName));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -812,10 +637,10 @@ public class Sketch {
|
||||
|
||||
if (isReadOnly() || isUntitled()) {
|
||||
// default to the sketchbook folder
|
||||
fd.setSelectedFile(new File(Base.getSketchbookFolder().getAbsolutePath(), folder.getName()));
|
||||
fd.setSelectedFile(new File(Base.getSketchbookFolder().getAbsolutePath(), data.getFolder().getName()));
|
||||
} else {
|
||||
// default to the parent folder of where this was
|
||||
fd.setSelectedFile(folder);
|
||||
fd.setSelectedFile(data.getFolder());
|
||||
}
|
||||
|
||||
int returnVal = fd.showSaveDialog(editor);
|
||||
@ -833,9 +658,9 @@ public class Sketch {
|
||||
// make sure there doesn't exist a .cpp file with that name already
|
||||
// but ignore this situation for the first tab, since it's probably being
|
||||
// resaved (with the same name) to another location/folder.
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
if (newName.equalsIgnoreCase(code[i].getPrettyName()) &&
|
||||
code[i].getExtension().equalsIgnoreCase("cpp")) {
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (newName.equalsIgnoreCase(code.getPrettyName()) &&
|
||||
code.isExtension("cpp")) {
|
||||
Base.showMessage(_("Nope"),
|
||||
I18n.format(
|
||||
_("You can't save the sketch as \"{0}\"\n" +
|
||||
@ -847,7 +672,7 @@ public class Sketch {
|
||||
}
|
||||
|
||||
// check if the paths are identical
|
||||
if (newFolder.equals(folder)) {
|
||||
if (newFolder.equals(data.getFolder())) {
|
||||
// just use "save" here instead, because the user will have received a
|
||||
// message (from the operating system) about "do you want to replace?"
|
||||
return save();
|
||||
@ -856,7 +681,7 @@ public class Sketch {
|
||||
// check to see if the user is trying to save this sketch inside itself
|
||||
try {
|
||||
String newPath = newFolder.getCanonicalPath() + File.separator;
|
||||
String oldPath = folder.getCanonicalPath() + File.separator;
|
||||
String oldPath = data.getFolder().getCanonicalPath() + File.separator;
|
||||
|
||||
if (newPath.indexOf(oldPath) == 0) {
|
||||
Base.showWarning(_("How very Borges of you"),
|
||||
@ -880,31 +705,32 @@ public class Sketch {
|
||||
|
||||
// grab the contents of the current tab before saving
|
||||
// first get the contents of the editor text area
|
||||
if (current.isModified()) {
|
||||
current.setProgram(editor.getText());
|
||||
if (current.getCode().isModified()) {
|
||||
current.getCode().setProgram(editor.getText());
|
||||
}
|
||||
|
||||
// save the other tabs to their new location
|
||||
for (int i = 1; i < codeCount; i++) {
|
||||
File newFile = new File(newFolder, code[i].getFileName());
|
||||
code[i].saveAs(newFile);
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (data.indexOfCode(code) == 0) continue;
|
||||
File newFile = new File(newFolder, code.getFileName());
|
||||
code.saveAs(newFile);
|
||||
}
|
||||
|
||||
// re-copy the data folder (this may take a while.. add progress bar?)
|
||||
if (dataFolder.exists()) {
|
||||
if (data.getDataFolder().exists()) {
|
||||
File newDataFolder = new File(newFolder, "data");
|
||||
Base.copyDir(dataFolder, newDataFolder);
|
||||
Base.copyDir(data.getDataFolder(), newDataFolder);
|
||||
}
|
||||
|
||||
// re-copy the code folder
|
||||
if (codeFolder.exists()) {
|
||||
if (data.getCodeFolder().exists()) {
|
||||
File newCodeFolder = new File(newFolder, "code");
|
||||
Base.copyDir(codeFolder, newCodeFolder);
|
||||
Base.copyDir(data.getCodeFolder(), newCodeFolder);
|
||||
}
|
||||
|
||||
// copy custom applet.html file if one exists
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=485
|
||||
File customHtml = new File(folder, "applet.html");
|
||||
File customHtml = new File(data.getFolder(), "applet.html");
|
||||
if (customHtml.exists()) {
|
||||
File newHtml = new File(newFolder, "applet.html");
|
||||
Base.copyFile(customHtml, newHtml);
|
||||
@ -912,7 +738,7 @@ public class Sketch {
|
||||
|
||||
// save the main tab with its new name
|
||||
File newFile = new File(newFolder, newName + ".ino");
|
||||
code[0].saveAs(newFile);
|
||||
data.getCode(0).saveAs(newFile);
|
||||
|
||||
editor.handleOpenUnchecked(newFile,
|
||||
currentIndex,
|
||||
@ -1003,19 +829,19 @@ public class Sketch {
|
||||
|
||||
//if (!codeFolder.exists()) codeFolder.mkdirs();
|
||||
prepareCodeFolder();
|
||||
destFile = new File(codeFolder, filename);
|
||||
destFile = new File(data.getCodeFolder(), filename);
|
||||
|
||||
} else {
|
||||
for (String extension : getExtensions()) {
|
||||
for (String extension : data.getExtensions()) {
|
||||
String lower = filename.toLowerCase();
|
||||
if (lower.endsWith("." + extension)) {
|
||||
destFile = new File(this.folder, filename);
|
||||
destFile = new File(data.getFolder(), filename);
|
||||
codeExtension = extension;
|
||||
}
|
||||
}
|
||||
if (codeExtension == null) {
|
||||
prepareDataFolder();
|
||||
destFile = new File(dataFolder, filename);
|
||||
destFile = new File(data.getDataFolder(), filename);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1075,27 +901,28 @@ public class Sketch {
|
||||
}
|
||||
|
||||
if (codeExtension != null) {
|
||||
SketchCode newCode = new SketchCode(destFile, codeExtension);
|
||||
SketchCode newCode = (new SketchCodeDocument(destFile)).getCode();
|
||||
|
||||
if (replacement) {
|
||||
replaceCode(newCode);
|
||||
data.replaceCode(newCode);
|
||||
|
||||
} else {
|
||||
insertCode(newCode);
|
||||
sortCode();
|
||||
ensureExistence();
|
||||
data.addCode(newCode);
|
||||
data.sortCode();
|
||||
}
|
||||
setCurrentCode(filename);
|
||||
editor.header.repaint();
|
||||
if (editor.untitled) { // TODO probably not necessary? problematic?
|
||||
// Mark the new code as modified so that the sketch is saved
|
||||
current.setModified(true);
|
||||
current.getCode().setModified(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (editor.untitled) { // TODO probably not necessary? problematic?
|
||||
// If a file has been added, mark the main code as modified so
|
||||
// that the sketch is properly saved.
|
||||
code[0].setModified(true);
|
||||
data.getCode(0).setModified(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -1119,7 +946,7 @@ public class Sketch {
|
||||
// import statements into the main sketch file (code[0])
|
||||
// if the current code is a .java file, insert into current
|
||||
//if (current.flavor == PDE) {
|
||||
if (hasDefaultExtension(current)) {
|
||||
if (hasDefaultExtension(current.getCode())) {
|
||||
setCurrentCode(0);
|
||||
}
|
||||
// could also scan the text in the file to see if each import
|
||||
@ -1155,16 +982,17 @@ public class Sketch {
|
||||
|
||||
// get the text currently being edited
|
||||
if (current != null) {
|
||||
current.setState(editor.getText(),
|
||||
editor.getSelectionStart(),
|
||||
editor.getSelectionStop(),
|
||||
editor.getScrollPosition());
|
||||
current.getCode().setProgram(editor.getText());
|
||||
current.setSelectionStart(editor.getSelectionStart());
|
||||
current.setSelectionStop(editor.getSelectionStop());
|
||||
current.setScrollPosition(editor.getScrollPosition());
|
||||
}
|
||||
|
||||
current = code[which];
|
||||
current = (SketchCodeDocument) data.getCode(which).getMetadata();
|
||||
currentIndex = which;
|
||||
|
||||
editor.setCode(current);
|
||||
|
||||
editor.header.rebuild();
|
||||
}
|
||||
|
||||
@ -1174,58 +1002,16 @@ public class Sketch {
|
||||
* @param findName the file name (not pretty name) to be shown
|
||||
*/
|
||||
protected void setCurrentCode(String findName) {
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (findName.equals(code[i].getFileName()) ||
|
||||
findName.equals(code[i].getPrettyName())) {
|
||||
setCurrentCode(i);
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (findName.equals(code.getFileName()) ||
|
||||
findName.equals(code.getPrettyName())) {
|
||||
setCurrentCode(data.indexOfCode(code));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup temporary files used during a build/run.
|
||||
*/
|
||||
protected void cleanup(boolean force) {
|
||||
// if the java runtime is holding onto any files in the build dir, we
|
||||
// won't be able to delete them, so we need to force a gc here
|
||||
System.gc();
|
||||
|
||||
if (force) {
|
||||
// delete the entire directory and all contents
|
||||
// when we know something changed and all objects
|
||||
// need to be recompiled, or if the board does not
|
||||
// use setting build.dependency
|
||||
//Base.removeDir(tempBuildFolder);
|
||||
|
||||
// note that we can't remove the builddir itself, otherwise
|
||||
// the next time we start up, internal runs using Runner won't
|
||||
// work because the build dir won't exist at startup, so the classloader
|
||||
// will ignore the fact that that dir is in the CLASSPATH in run.sh
|
||||
Base.removeDescendants(tempBuildFolder);
|
||||
} else {
|
||||
// delete only stale source files, from the previously
|
||||
// compiled sketch. This allows multiple windows to be
|
||||
// used. Keep everything else, which might be reusable
|
||||
if (tempBuildFolder.exists()) {
|
||||
String files[] = tempBuildFolder.list();
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".s")) {
|
||||
File deleteMe = new File(tempBuildFolder, file);
|
||||
if (!deleteMe.delete()) {
|
||||
System.err.println("Could not delete " + deleteMe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a fresh applet folder (needed before preproc is run below)
|
||||
//tempBuildFolder.mkdirs();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Preprocess, Compile, and Run the current code.
|
||||
* <P>
|
||||
@ -1262,7 +1048,7 @@ public class Sketch {
|
||||
// make sure the user didn't hide the sketch folder
|
||||
ensureExistence();
|
||||
|
||||
current.setProgram(editor.getText());
|
||||
current.getCode().setProgram(editor.getText());
|
||||
|
||||
// TODO record history here
|
||||
//current.history.record(program, SketchHistory.RUN);
|
||||
@ -1287,142 +1073,6 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build all the code for this sketch.
|
||||
*
|
||||
* In an advanced program, the returned class name could be different,
|
||||
* which is why the className is set based on the return value.
|
||||
* A compilation error will burp up a RunnerException.
|
||||
*
|
||||
* Setting purty to 'true' will cause exception line numbers to be incorrect.
|
||||
* Unless you know the code compiles, you should first run the preprocessor
|
||||
* with purty set to false to make sure there are no errors, then once
|
||||
* successful, re-export with purty set to true.
|
||||
*
|
||||
* @param buildPath Location to copy all the .java files
|
||||
* @return null if compilation failed, main class name if not
|
||||
*/
|
||||
public void preprocess(String buildPath) throws RunnerException {
|
||||
preprocess(buildPath, new PdePreprocessor());
|
||||
}
|
||||
|
||||
public void preprocess(String buildPath, PdePreprocessor preprocessor) throws RunnerException {
|
||||
// make sure the user didn't hide the sketch folder
|
||||
ensureExistence();
|
||||
|
||||
classPath = buildPath;
|
||||
|
||||
// // figure out the contents of the code folder to see if there
|
||||
// // are files that need to be added to the imports
|
||||
// if (codeFolder.exists()) {
|
||||
// libraryPath = codeFolder.getAbsolutePath();
|
||||
//
|
||||
// // get a list of .jar files in the "code" folder
|
||||
// // (class files in subfolders should also be picked up)
|
||||
// String codeFolderClassPath =
|
||||
// Compiler.contentsToClassPath(codeFolder);
|
||||
// // append the jar files in the code folder to the class path
|
||||
// classPath += File.pathSeparator + codeFolderClassPath;
|
||||
// // get list of packages found in those jars
|
||||
// codeFolderPackages =
|
||||
// Compiler.packageListFromClassPath(codeFolderClassPath);
|
||||
//
|
||||
// } else {
|
||||
// libraryPath = "";
|
||||
// }
|
||||
|
||||
// 1. concatenate all .pde files to the 'main' pde
|
||||
// store line number for starting point of each code bit
|
||||
|
||||
StringBuffer bigCode = new StringBuffer();
|
||||
int bigCount = 0;
|
||||
for (SketchCode sc : code) {
|
||||
if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||
sc.setPreprocOffset(bigCount);
|
||||
// These #line directives help the compiler report errors with
|
||||
// correct the filename and line number (issue 281 & 907)
|
||||
bigCode.append("#line 1 \"" + sc.getFileName() + "\"\n");
|
||||
bigCode.append(sc.getProgram());
|
||||
bigCode.append('\n');
|
||||
bigCount += sc.getLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
try {
|
||||
headerOffset = preprocessor.writePrefix(bigCode.toString());
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = _("Build folder disappeared or could not be written");
|
||||
throw new RunnerException(msg);
|
||||
}
|
||||
|
||||
// 2. run preproc on that code using the sugg class name
|
||||
// to create a single .java file and write to buildpath
|
||||
|
||||
try {
|
||||
// Output file
|
||||
File streamFile = new File(buildPath, name + ".cpp");
|
||||
FileOutputStream outputStream = new FileOutputStream(streamFile);
|
||||
preprocessor.write(outputStream);
|
||||
outputStream.close();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = _("Build folder disappeared or could not be written");
|
||||
throw new RunnerException(msg);
|
||||
} catch (RunnerException pe) {
|
||||
// RunnerExceptions are caught here and re-thrown, so that they don't
|
||||
// get lost in the more general "Exception" handler below.
|
||||
throw pe;
|
||||
|
||||
} catch (Exception ex) {
|
||||
// TODO better method for handling this?
|
||||
System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass()));
|
||||
ex.printStackTrace();
|
||||
throw new RunnerException(ex.toString());
|
||||
}
|
||||
|
||||
// grab the imports from the code just preproc'd
|
||||
|
||||
importedLibraries = new LibraryList();
|
||||
for (String item : preprocessor.getExtraImports()) {
|
||||
Library lib = Base.importToLibraryTable.get(item);
|
||||
if (lib != null && !importedLibraries.contains(lib)) {
|
||||
importedLibraries.add(lib);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. then loop over the code[] and save each .java file
|
||||
|
||||
for (SketchCode sc : code) {
|
||||
if (sc.isExtension("c") || sc.isExtension("cpp") || sc.isExtension("h")) {
|
||||
// no pre-processing services necessary for java files
|
||||
// just write the the contents of 'program' to a .java file
|
||||
// into the build directory. uses byte stream and reader/writer
|
||||
// shtuff so that unicode bunk is properly handled
|
||||
String filename = sc.getFileName(); //code[i].name + ".java";
|
||||
try {
|
||||
Base.saveFile(sc.getProgram(), new File(buildPath, filename));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RunnerException(I18n.format(_("Problem moving {0} to the build folder"), filename));
|
||||
}
|
||||
// sc.setPreprocName(filename);
|
||||
|
||||
} else if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||
// The compiler and runner will need this to have a proper offset
|
||||
sc.addPreprocOffset(headerOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LibraryList getImportedLibraries() {
|
||||
return importedLibraries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map an error from a set of processed .java files back to its location
|
||||
@ -1474,31 +1124,6 @@ public class Sketch {
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Map an error from a set of processed .java files back to its location
|
||||
* in the actual sketch.
|
||||
* @param message The error message.
|
||||
* @param dotJavaFilename The .java file where the exception was found.
|
||||
* @param dotJavaLine 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) {
|
||||
// Placing errors is simple, because we inserted #line directives
|
||||
// into the preprocessed source. The compiler gives us correct
|
||||
// the file name and line number. :-)
|
||||
for (int codeIndex = 0; codeIndex < getCodeCount(); codeIndex++) {
|
||||
SketchCode code = getCode(codeIndex);
|
||||
if (dotJavaFilename.equals(code.getFileName())) {
|
||||
return new RunnerException(message, codeIndex, dotJavaLine);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the build inside the temporary build folder.
|
||||
* @return null if compilation failed, main class name if not
|
||||
@ -1508,47 +1133,6 @@ public class Sketch {
|
||||
return build(tempBuildFolder.getAbsolutePath(), verbose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the build preferences used on the previous build in
|
||||
* buildPath match the ones given.
|
||||
*/
|
||||
protected boolean buildPreferencesChanged(File buildPrefsFile, String newBuildPrefs) {
|
||||
// No previous build, so no match
|
||||
if (!buildPrefsFile.exists())
|
||||
return true;
|
||||
|
||||
String previousPrefs;
|
||||
try {
|
||||
previousPrefs = FileUtils.readFileToString(buildPrefsFile);
|
||||
} catch (IOException e) {
|
||||
System.err.println(_("Could not read prevous build preferences file, rebuilding all"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!previousPrefs.equals(newBuildPrefs)) {
|
||||
System.out.println(_("Build options changed, rebuilding all"));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the build preferences of the given compiler as a string.
|
||||
* Only includes build-specific preferences, to make sure unrelated
|
||||
* preferences don't cause a rebuild (in particular preferences that
|
||||
* change on every start, like last.ide.xxx.daterun). */
|
||||
protected String buildPrefsString(Compiler compiler) {
|
||||
PreferencesMap buildPrefs = compiler.getBuildPreferences();
|
||||
String res = "";
|
||||
SortedSet<String> treeSet = new TreeSet<String>(buildPrefs.keySet());
|
||||
for (String k : treeSet) {
|
||||
if (k.startsWith("build.") || k.startsWith("compiler.") || k.startsWith("recipes."))
|
||||
res += k + " = " + buildPrefs.get(k) + "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess and compile all the code for this sketch.
|
||||
*
|
||||
@ -1559,37 +1143,19 @@ public class Sketch {
|
||||
* @return null if compilation failed, main class name if not
|
||||
*/
|
||||
public String build(String buildPath, boolean verbose) throws RunnerException {
|
||||
String primaryClassName = name + ".cpp";
|
||||
Compiler compiler = new Compiler(this, buildPath, primaryClassName);
|
||||
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
|
||||
String newBuildPrefs = buildPrefsString(compiler);
|
||||
|
||||
// Do a forced cleanup (throw everything away) if the previous
|
||||
// build settings do not match the previous ones
|
||||
boolean prefsChanged = buildPreferencesChanged(buildPrefsFile, newBuildPrefs);
|
||||
cleanup(prefsChanged);
|
||||
|
||||
if (prefsChanged) {
|
||||
try {
|
||||
PrintWriter out = new PrintWriter(buildPrefsFile);
|
||||
out.print(newBuildPrefs);
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println(_("Could not write build preferences file"));
|
||||
}
|
||||
}
|
||||
|
||||
// run the preprocessor
|
||||
editor.status.progressUpdate(20);
|
||||
preprocess(buildPath);
|
||||
|
||||
// compile the program. errors will happen as a RunnerException
|
||||
// that will bubble up to whomever called build().
|
||||
if (compiler.compile(verbose)) {
|
||||
size(compiler.getBuildPreferences());
|
||||
return primaryClassName;
|
||||
}
|
||||
return null;
|
||||
ensureExistence();
|
||||
|
||||
ProgressListener pl = new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int percent) {
|
||||
editor.status.progressUpdate(percent);
|
||||
}
|
||||
};
|
||||
|
||||
return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose);
|
||||
}
|
||||
|
||||
protected boolean exportApplet(boolean usingProgrammer) throws Exception {
|
||||
@ -1627,71 +1193,9 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
public void setCompilingProgress(int percent) {
|
||||
editor.status.progressUpdate(percent);
|
||||
}
|
||||
|
||||
|
||||
protected void size(PreferencesMap prefs) throws RunnerException {
|
||||
String maxTextSizeString = prefs.get("upload.maximum_size");
|
||||
String maxDataSizeString = prefs.get("upload.maximum_data_size");
|
||||
if (maxTextSizeString == null)
|
||||
return;
|
||||
long maxTextSize = Integer.parseInt(maxTextSizeString);
|
||||
long maxDataSize = -1;
|
||||
if (maxDataSizeString != null)
|
||||
maxDataSize = Integer.parseInt(maxDataSizeString);
|
||||
Sizer sizer = new Sizer(prefs);
|
||||
long[] sizes;
|
||||
try {
|
||||
sizes = sizer.computeSize();
|
||||
} catch (RunnerException e) {
|
||||
System.err.println(I18n.format(_("Couldn't determine program size: {0}"),
|
||||
e.getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
long textSize = sizes[0];
|
||||
long dataSize = sizes[1];
|
||||
System.out.println();
|
||||
System.out.println(I18n
|
||||
.format(_("Sketch uses {0} bytes ({2}%%) of program storage space. Maximum is {1} bytes."),
|
||||
textSize, maxTextSize, textSize * 100 / maxTextSize));
|
||||
if (dataSize >= 0) {
|
||||
if (maxDataSize > 0) {
|
||||
System.out
|
||||
.println(I18n
|
||||
.format(
|
||||
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
|
||||
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
|
||||
maxDataSize - dataSize));
|
||||
} else {
|
||||
System.out.println(I18n
|
||||
.format(_("Global variables use {0} bytes of dynamic memory."), dataSize));
|
||||
}
|
||||
}
|
||||
|
||||
if (textSize > maxTextSize)
|
||||
throw new RunnerException(
|
||||
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
|
||||
|
||||
if (maxDataSize > 0 && dataSize > maxDataSize)
|
||||
throw new RunnerException(
|
||||
_("Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint."));
|
||||
|
||||
int warnDataPercentage = Integer.parseInt(prefs.get("build.warn_data_percentage"));
|
||||
if (maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100)
|
||||
System.err.println(_("Low memory available, stability problems may occur."));
|
||||
}
|
||||
|
||||
protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception {
|
||||
|
||||
TargetPlatform target = Base.getTargetPlatform();
|
||||
String board = Preferences.get("board");
|
||||
|
||||
BoardPort boardPort = Base.getDiscoveryManager().find(Preferences.get("serial.port"));
|
||||
|
||||
Uploader uploader = new UploaderAndMonitorFactory().newUploader(target.getBoards().get(board), boardPort);
|
||||
Uploader uploader = Compiler.getUploaderByPreferences(false);
|
||||
|
||||
boolean success = false;
|
||||
do {
|
||||
@ -1710,7 +1214,7 @@ public class Sketch {
|
||||
|
||||
List<String> warningsAccumulator = new LinkedList<String>();
|
||||
try {
|
||||
success = uploader.uploadUsingPreferences(getFolder(), buildPath, suggestedClassName, usingProgrammer, warningsAccumulator);
|
||||
success = Compiler.upload(data, uploader, buildPath, suggestedClassName, usingProgrammer, false, warningsAccumulator);
|
||||
} finally {
|
||||
if (uploader.requiresAuthorization() && !success) {
|
||||
Preferences.remove(uploader.getAuthorizationKey());
|
||||
@ -1758,18 +1262,18 @@ public class Sketch {
|
||||
* but not its contents.
|
||||
*/
|
||||
protected void ensureExistence() {
|
||||
if (folder.exists()) return;
|
||||
if (data.getFolder().exists()) return;
|
||||
|
||||
Base.showWarning(_("Sketch Disappeared"),
|
||||
_("The sketch folder has disappeared.\n " +
|
||||
"Will attempt to re-save in the same location,\n" +
|
||||
"but anything besides the code will be lost."), null);
|
||||
try {
|
||||
folder.mkdirs();
|
||||
data.getFolder().mkdirs();
|
||||
modified = true;
|
||||
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
code[i].save(); // this will force a save
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
code.save(); // this will force a save
|
||||
}
|
||||
calcModified();
|
||||
|
||||
@ -1789,7 +1293,7 @@ public class Sketch {
|
||||
* volumes or folders without appropriate permissions.
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
String apath = folder.getAbsolutePath();
|
||||
String apath = data.getFolder().getAbsolutePath();
|
||||
for (File folder : Base.getLibrariesPath()) {
|
||||
if (apath.startsWith(folder.getAbsolutePath()))
|
||||
return true;
|
||||
@ -1803,9 +1307,8 @@ public class Sketch {
|
||||
// } else if (!folder.canWrite()) {
|
||||
|
||||
// check to see if each modified code file can be written to
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (code[i].isModified() && code[i].fileReadOnly() &&
|
||||
code[i].fileExists()) {
|
||||
for (SketchCode code : data.getCodes()) {
|
||||
if (code.isModified() && code.fileReadOnly() && code.fileExists()) {
|
||||
// System.err.println("found a read-only file " + code[i].file);
|
||||
return true;
|
||||
}
|
||||
@ -1818,21 +1321,11 @@ public class Sketch {
|
||||
// Breaking out extension types in order to clean up the code, and make it
|
||||
// easier for other environments (like Arduino) to incorporate changes.
|
||||
|
||||
|
||||
/**
|
||||
* True if the specified extension should be hidden when shown on a tab.
|
||||
* For Processing, this is true for .pde files. (Broken out for subclasses.)
|
||||
*/
|
||||
public boolean hideExtension(String what) {
|
||||
return getHiddenExtensions().contains(what);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* True if the specified code has the default file extension.
|
||||
*/
|
||||
public boolean hasDefaultExtension(SketchCode code) {
|
||||
return code.getExtension().equals(getDefaultExtension());
|
||||
return code.isExtension(getDefaultExtension());
|
||||
}
|
||||
|
||||
|
||||
@ -1849,11 +1342,7 @@ public class Sketch {
|
||||
* extensions.
|
||||
*/
|
||||
public boolean validExtension(String what) {
|
||||
String[] ext = getExtensions();
|
||||
for (int i = 0; i < ext.length; i++) {
|
||||
if (ext[i].equals(what)) return true;
|
||||
}
|
||||
return false;
|
||||
return data.getExtensions().contains(what);
|
||||
}
|
||||
|
||||
|
||||
@ -1861,7 +1350,7 @@ public class Sketch {
|
||||
* Returns the default extension for this editor setup.
|
||||
*/
|
||||
public String getDefaultExtension() {
|
||||
return "ino";
|
||||
return data.getDefaultExtension();
|
||||
}
|
||||
|
||||
static private List<String> hiddenExtensions = Arrays.asList("ino", "pde");
|
||||
@ -1870,13 +1359,6 @@ public class Sketch {
|
||||
return hiddenExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String[] array of proper extensions.
|
||||
*/
|
||||
public String[] getExtensions() {
|
||||
return new String[] { "ino", "pde", "c", "cpp", "h" };
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
@ -1888,15 +1370,7 @@ public class Sketch {
|
||||
* Returns the name of this sketch. (The pretty name of the main tab.)
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a file object for the primary .pde of this sketch.
|
||||
*/
|
||||
public File getPrimaryFile() {
|
||||
return primaryFile;
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
|
||||
@ -1904,8 +1378,7 @@ public class Sketch {
|
||||
* Returns path to the main .pde file for this sketch.
|
||||
*/
|
||||
public String getMainFilePath() {
|
||||
return primaryFile.getAbsolutePath();
|
||||
//return code[0].file.getAbsolutePath();
|
||||
return data.getMainFilePath();
|
||||
}
|
||||
|
||||
|
||||
@ -1913,15 +1386,7 @@ public class Sketch {
|
||||
* Returns the sketch folder.
|
||||
*/
|
||||
public File getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the location of the sketch's data folder. (It may not exist yet.)
|
||||
*/
|
||||
public File getDataFolder() {
|
||||
return dataFolder;
|
||||
return data.getFolder();
|
||||
}
|
||||
|
||||
|
||||
@ -1930,18 +1395,10 @@ public class Sketch {
|
||||
* it also returns the data folder, since it's likely about to be used.
|
||||
*/
|
||||
public File prepareDataFolder() {
|
||||
if (!dataFolder.exists()) {
|
||||
dataFolder.mkdirs();
|
||||
if (!data.getDataFolder().exists()) {
|
||||
data.getDataFolder().mkdirs();
|
||||
}
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the location of the sketch's code folder. (It may not exist yet.)
|
||||
*/
|
||||
public File getCodeFolder() {
|
||||
return codeFolder;
|
||||
return data.getDataFolder();
|
||||
}
|
||||
|
||||
|
||||
@ -1950,45 +1407,35 @@ public class Sketch {
|
||||
* it also returns the code folder, since it's likely about to be used.
|
||||
*/
|
||||
public File prepareCodeFolder() {
|
||||
if (!codeFolder.exists()) {
|
||||
codeFolder.mkdirs();
|
||||
if (!data.getCodeFolder().exists()) {
|
||||
data.getCodeFolder().mkdirs();
|
||||
}
|
||||
return codeFolder;
|
||||
return data.getCodeFolder();
|
||||
}
|
||||
|
||||
|
||||
public String getClassPath() {
|
||||
return classPath;
|
||||
}
|
||||
|
||||
|
||||
public SketchCode[] getCode() {
|
||||
return code;
|
||||
public SketchCode[] getCodes() {
|
||||
return data.getCodes();
|
||||
}
|
||||
|
||||
|
||||
public int getCodeCount() {
|
||||
return codeCount;
|
||||
return data.getCodeCount();
|
||||
}
|
||||
|
||||
|
||||
public SketchCode getCode(int index) {
|
||||
return code[index];
|
||||
return data.getCode(index);
|
||||
}
|
||||
|
||||
|
||||
public int getCodeIndex(SketchCode who) {
|
||||
for (int i = 0; i < codeCount; i++) {
|
||||
if (who == code[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return data.indexOfCode(who);
|
||||
}
|
||||
|
||||
|
||||
public SketchCode getCurrentCode() {
|
||||
return current;
|
||||
return current.getCode();
|
||||
}
|
||||
|
||||
|
||||
@ -2015,7 +1462,7 @@ public class Sketch {
|
||||
* if changes were made.
|
||||
*/
|
||||
static public String checkName(String origName) {
|
||||
String newName = sanitizeName(origName);
|
||||
String newName = BaseNoGui.sanitizeName(origName);
|
||||
|
||||
if (!newName.equals(origName)) {
|
||||
String msg =
|
||||
@ -2028,55 +1475,4 @@ public class Sketch {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the name is valid for a Processing sketch.
|
||||
*/
|
||||
static public boolean isSanitaryName(String name) {
|
||||
return sanitizeName(name).equals(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produce a sanitized name that fits our standards for likely to work.
|
||||
* <p/>
|
||||
* Java classes have a wider range of names that are technically allowed
|
||||
* (supposedly any Unicode name) than what we support. The reason for
|
||||
* going more narrow is to avoid situations with text encodings and
|
||||
* converting during the process of moving files between operating
|
||||
* systems, i.e. uploading from a Windows machine to a Linux server,
|
||||
* or reading a FAT32 partition in OS X and using a thumb drive.
|
||||
* <p/>
|
||||
* This helper function replaces everything but A-Z, a-z, and 0-9 with
|
||||
* underscores. Also disallows starting the sketch name with a digit.
|
||||
*/
|
||||
static public String sanitizeName(String origName) {
|
||||
char c[] = origName.toCharArray();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
// can't lead with a digit, so start with an underscore
|
||||
if ((c[0] >= '0') && (c[0] <= '9')) {
|
||||
buffer.append('_');
|
||||
}
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if (((c[i] >= '0') && (c[i] <= '9')) ||
|
||||
((c[i] >= 'a') && (c[i] <= 'z')) ||
|
||||
((c[i] >= 'A') && (c[i] <= 'Z')) ||
|
||||
((i > 0) && (c[i] == '-')) ||
|
||||
((i > 0) && (c[i] == '.'))) {
|
||||
buffer.append(c[i]);
|
||||
} else {
|
||||
buffer.append('_');
|
||||
}
|
||||
}
|
||||
// let's not be ridiculous about the length of filenames.
|
||||
// in fact, Mac OS 9 can handle 255 chars, though it can't really
|
||||
// deal with filenames longer than 31 chars in the Finder.
|
||||
// but limiting to that for sketches would mean setting the
|
||||
// upper-bound on the character limit here to 25 characters
|
||||
// (to handle the base name + ".class")
|
||||
if (buffer.length() > 63) {
|
||||
buffer.setLength(63);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
79
app/src/processing/app/SketchCodeDocument.java
Normal file
79
app/src/processing/app/SketchCodeDocument.java
Normal file
@ -0,0 +1,79 @@
|
||||
package processing.app;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.text.Document;
|
||||
|
||||
public class SketchCodeDocument{
|
||||
|
||||
private SketchCode code;
|
||||
private Document document;
|
||||
|
||||
// Undo Manager for this tab, each tab keeps track of their own Editor.undo
|
||||
// will be set to this object when this code is the tab that's currently the
|
||||
// front.
|
||||
private LastUndoableEditAwareUndoManager undo = new LastUndoableEditAwareUndoManager();
|
||||
|
||||
// saved positions from last time this tab was used
|
||||
private int selectionStart;
|
||||
private int selectionStop;
|
||||
private int scrollPosition;
|
||||
|
||||
public SketchCodeDocument(SketchCode code) {
|
||||
this.code = code;
|
||||
this.code.setMetadata(this);
|
||||
}
|
||||
|
||||
public SketchCodeDocument(File file) {
|
||||
this.code = new SketchCode(file, this);
|
||||
}
|
||||
|
||||
public LastUndoableEditAwareUndoManager getUndo() {
|
||||
return undo;
|
||||
}
|
||||
|
||||
public void setUndo(LastUndoableEditAwareUndoManager undo) {
|
||||
this.undo = undo;
|
||||
}
|
||||
|
||||
public int getSelectionStart() {
|
||||
return selectionStart;
|
||||
}
|
||||
|
||||
public void setSelectionStart(int selectionStart) {
|
||||
this.selectionStart = selectionStart;
|
||||
}
|
||||
|
||||
public int getSelectionStop() {
|
||||
return selectionStop;
|
||||
}
|
||||
|
||||
public void setSelectionStop(int selectionStop) {
|
||||
this.selectionStop = selectionStop;
|
||||
}
|
||||
|
||||
public int getScrollPosition() {
|
||||
return scrollPosition;
|
||||
}
|
||||
|
||||
public void setScrollPosition(int scrollPosition) {
|
||||
this.scrollPosition = scrollPosition;
|
||||
}
|
||||
|
||||
public SketchCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(SketchCode code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
public void setDocument(Document document) {
|
||||
this.document = document;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
@ -23,14 +21,15 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import processing.app.syntax.*;
|
||||
import processing.core.*;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.SystemColor;
|
||||
|
||||
import processing.app.helpers.PreferencesHelper;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.syntax.SyntaxStyle;
|
||||
|
||||
/**
|
||||
* Storage class for theme settings. This was separated from the Preferences
|
||||
@ -40,164 +39,80 @@ import static processing.app.I18n._;
|
||||
public class Theme {
|
||||
|
||||
/** Copy of the defaults in case the user mangles a preference. */
|
||||
static HashMap<String,String> defaults;
|
||||
static PreferencesMap defaults;
|
||||
/** Table of attributes/values for the theme. */
|
||||
static HashMap<String,String> table = new HashMap<String,String>();;
|
||||
|
||||
static PreferencesMap table = new PreferencesMap();
|
||||
|
||||
static protected void init() {
|
||||
try {
|
||||
load(Base.getLibStream("theme/theme.txt"));
|
||||
table.load(Base.getLibStream("theme/theme.txt"));
|
||||
} catch (Exception te) {
|
||||
Base.showError(null, _("Could not read color theme settings.\n" +
|
||||
"You'll need to reinstall Arduino."), te);
|
||||
}
|
||||
|
||||
// check for platform-specific properties in the defaults
|
||||
String platformExt = "." + Base.getPlatformName();
|
||||
int platformExtLength = platformExt.length();
|
||||
for (String key : table.keySet()) {
|
||||
if (key.endsWith(platformExt)) {
|
||||
// this is a key specific to a particular platform
|
||||
String actualKey = key.substring(0, key.length() - platformExtLength);
|
||||
String value = get(key);
|
||||
table.put(actualKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
// other things that have to be set explicitly for the defaults
|
||||
setColor("run.window.bgcolor", SystemColor.control);
|
||||
|
||||
// clone the hash table
|
||||
defaults = (HashMap<String, String>) table.clone();
|
||||
defaults = new PreferencesMap(table);
|
||||
}
|
||||
|
||||
|
||||
static protected void load(InputStream input) throws IOException {
|
||||
String[] lines = PApplet.loadStrings(input);
|
||||
for (String line : lines) {
|
||||
if ((line.length() == 0) ||
|
||||
(line.charAt(0) == '#')) continue;
|
||||
|
||||
// this won't properly handle = signs being in the text
|
||||
int equals = line.indexOf('=');
|
||||
if (equals != -1) {
|
||||
String key = line.substring(0, equals).trim();
|
||||
String value = line.substring(equals + 1).trim();
|
||||
table.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public String get(String attribute) {
|
||||
return (String) table.get(attribute);
|
||||
return table.get(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public String getDefault(String attribute) {
|
||||
return (String) defaults.get(attribute);
|
||||
return defaults.get(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void set(String attribute, String value) {
|
||||
table.put(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public boolean getBoolean(String attribute) {
|
||||
String value = get(attribute);
|
||||
return (new Boolean(value)).booleanValue();
|
||||
return table.getBoolean(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void setBoolean(String attribute, boolean value) {
|
||||
set(attribute, value ? "true" : "false");
|
||||
table.putBoolean(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public int getInteger(String attribute) {
|
||||
return Integer.parseInt(get(attribute));
|
||||
}
|
||||
|
||||
|
||||
static public void setInteger(String key, int value) {
|
||||
set(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
|
||||
static public Color getColor(String name) {
|
||||
Color parsed = null;
|
||||
String s = get(name);
|
||||
if ((s != null) && (s.indexOf("#") == 0)) {
|
||||
try {
|
||||
int v = Integer.parseInt(s.substring(1), 16);
|
||||
parsed = new Color(v);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
return PreferencesHelper.parseColor(get(name));
|
||||
}
|
||||
|
||||
|
||||
static public void setColor(String attr, Color what) {
|
||||
set(attr, "#" + PApplet.hex(what.getRGB() & 0xffffff, 6));
|
||||
static public void setColor(String attr, Color color) {
|
||||
PreferencesHelper.putColor(table, attr, color);
|
||||
}
|
||||
|
||||
|
||||
static public Font getFont(String attr) {
|
||||
boolean replace = false;
|
||||
String value = get(attr);
|
||||
if (value == null) {
|
||||
//System.out.println("reset 1");
|
||||
value = getDefault(attr);
|
||||
replace = true;
|
||||
}
|
||||
|
||||
String[] pieces = PApplet.split(value, ',');
|
||||
if (pieces.length != 3) {
|
||||
value = getDefault(attr);
|
||||
//System.out.println("reset 2 for " + attr);
|
||||
pieces = PApplet.split(value, ',');
|
||||
//PApplet.println(pieces);
|
||||
replace = true;
|
||||
}
|
||||
|
||||
String name = pieces[0];
|
||||
int style = Font.PLAIN; // equals zero
|
||||
if (pieces[1].indexOf("bold") != -1) {
|
||||
style |= Font.BOLD;
|
||||
}
|
||||
if (pieces[1].indexOf("italic") != -1) {
|
||||
style |= Font.ITALIC;
|
||||
}
|
||||
int size = PApplet.parseInt(pieces[2], 12);
|
||||
Font font = new Font(name, style, size);
|
||||
|
||||
// replace bad font with the default
|
||||
if (replace) {
|
||||
//System.out.println(attr + " > " + value);
|
||||
//setString(attr, font.getName() + ",plain," + font.getSize());
|
||||
Font font = PreferencesHelper.getFont(table, attr);
|
||||
if (font == null) {
|
||||
String value = getDefault(attr);
|
||||
set(attr, value);
|
||||
font = PreferencesHelper.getFont(table, attr);
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
static public SyntaxStyle getStyle(String what) {
|
||||
String str = get("editor." + what + ".style");
|
||||
String split[] = get("editor." + what + ".style").split(",");
|
||||
|
||||
StringTokenizer st = new StringTokenizer(str, ",");
|
||||
Color color = PreferencesHelper.parseColor(split[0]);
|
||||
|
||||
String s = st.nextToken();
|
||||
if (s.indexOf("#") == 0) s = s.substring(1);
|
||||
Color color = new Color(Integer.parseInt(s, 16));
|
||||
|
||||
s = st.nextToken();
|
||||
boolean bold = (s.indexOf("bold") != -1);
|
||||
boolean italic = (s.indexOf("italic") != -1);
|
||||
boolean underlined = (s.indexOf("underlined") != -1);
|
||||
String style = split[1];
|
||||
boolean bold = style.contains("bold");
|
||||
boolean italic = style.contains("italic");
|
||||
boolean underlined = style.contains("underlined");
|
||||
|
||||
return new SyntaxStyle(color, italic, bold, underlined);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import java.util.Random;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
|
||||
|
49
app/src/processing/app/helpers/GUIUserNotifier.java
Normal file
49
app/src/processing/app/helpers/GUIUserNotifier.java
Normal file
@ -0,0 +1,49 @@
|
||||
package processing.app.helpers;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.awt.Frame;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
public class GUIUserNotifier extends UserNotifier {
|
||||
|
||||
/**
|
||||
* Show an error message that's actually fatal to the program.
|
||||
* This is an error that can't be recovered. Use showWarning()
|
||||
* for errors that allow P5 to continue running.
|
||||
*/
|
||||
public void showError(String title, String message, Throwable e, int exit_code) {
|
||||
if (title == null) title = _("Error");
|
||||
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
if (e != null) e.printStackTrace();
|
||||
System.exit(exit_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* "No cookie for you" type messages. Nothing fatal or all that
|
||||
* much of a bummer, but something to notify the user about.
|
||||
*/
|
||||
public void showMessage(String title, String message) {
|
||||
if (title == null) title = _("Message");
|
||||
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-fatal error message with optional stack trace side dish.
|
||||
*/
|
||||
public void showWarning(String title, String message, Exception e) {
|
||||
if (title == null) title = _("Warning");
|
||||
|
||||
JOptionPane.showMessageDialog(new Frame(), message, title,
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
|
||||
if (e != null) e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
@ -50,7 +50,7 @@ public class ThinkDifferent implements ApplicationListener {
|
||||
private Base base;
|
||||
|
||||
|
||||
static protected void init(Base base) {
|
||||
static public void init(Base base) {
|
||||
if (application == null) {
|
||||
//application = new com.apple.eawt.Application();
|
||||
application = com.apple.eawt.Application.getApplication();
|
||||
|
@ -25,6 +25,7 @@
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.legacy.PApplet;
|
||||
import processing.app.packages.Library;
|
||||
|
||||
import java.io.*;
|
||||
@ -84,7 +85,7 @@ public class PdeKeywords extends CTokenMarker {
|
||||
// in case there's any garbage on the line
|
||||
//if (line.trim().length() == 0) continue;
|
||||
|
||||
String pieces[] = processing.core.PApplet.split(line, '\t');
|
||||
String pieces[] = PApplet.split(line, '\t');
|
||||
if (pieces.length >= 2) {
|
||||
//int tab = line.indexOf('\t');
|
||||
// any line with no tab is ignored
|
||||
|
@ -25,6 +25,7 @@
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.helpers.OSUtils;
|
||||
|
||||
|
||||
public class PdeTextAreaDefaults extends TextAreaDefaults {
|
||||
@ -35,7 +36,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
|
||||
//inputHandler.addDefaultKeyBindings(); // 0122
|
||||
|
||||
// use option on mac for text edit controls that are ctrl on windows/linux
|
||||
String mod = Base.isMacOS() ? "A" : "C";
|
||||
String mod = OSUtils.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)
|
||||
@ -94,7 +95,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
|
||||
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_DOC_END);
|
||||
}
|
||||
|
||||
if (Base.isMacOS()) {
|
||||
if (OSUtils.isMacOS()) {
|
||||
inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
|
||||
inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
|
||||
inputHandler.addKeyBinding("MS+LEFT", InputHandler.SELECT_HOME); // 0122
|
||||
|
@ -25,7 +25,7 @@
|
||||
package processing.app.tools;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.*;
|
||||
|
@ -1,609 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2006-08 Ben Fry and Casey Reas
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.tools;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
|
||||
/**
|
||||
* Color selector tool for the Tools menu.
|
||||
* <p/>
|
||||
* Using the keyboard shortcuts, you can copy/paste the values for the
|
||||
* colors and paste them into your program. We didn't do any sort of
|
||||
* auto-insert of colorMode() or fill() or stroke() code cuz we couldn't
|
||||
* decide on a good way to do this.. your contributions welcome).
|
||||
*/
|
||||
public class ColorSelector implements Tool, DocumentListener {
|
||||
|
||||
Editor editor;
|
||||
JFrame frame;
|
||||
|
||||
int hue, saturation, brightness; // range 360, 100, 100
|
||||
int red, green, blue; // range 256, 256, 256
|
||||
|
||||
ColorRange range;
|
||||
ColorSlider slider;
|
||||
|
||||
JTextField hueField, saturationField, brightnessField;
|
||||
JTextField redField, greenField, blueField;
|
||||
|
||||
JTextField hexField;
|
||||
|
||||
JPanel colorPanel;
|
||||
|
||||
|
||||
public String getMenuTitle() {
|
||||
return "Color Selector";
|
||||
}
|
||||
|
||||
|
||||
public void init(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
frame = new JFrame("Color Selector");
|
||||
frame.getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
Box box = Box.createHorizontalBox();
|
||||
box.setBorder(new EmptyBorder(12, 12, 12, 12));
|
||||
|
||||
range = new ColorRange();
|
||||
range.init();
|
||||
Box rangeBox = new Box(BoxLayout.Y_AXIS);
|
||||
rangeBox.setAlignmentY(0);
|
||||
rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
|
||||
rangeBox.add(range);
|
||||
box.add(rangeBox);
|
||||
box.add(Box.createHorizontalStrut(10));
|
||||
|
||||
slider = new ColorSlider();
|
||||
slider.init();
|
||||
Box sliderBox = new Box(BoxLayout.Y_AXIS);
|
||||
sliderBox.setAlignmentY(0);
|
||||
sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
|
||||
sliderBox.add(slider);
|
||||
box.add(sliderBox);
|
||||
box.add(Box.createHorizontalStrut(10));
|
||||
|
||||
box.add(createColorFields());
|
||||
box.add(Box.createHorizontalStrut(10));
|
||||
|
||||
frame.getContentPane().add(box, BorderLayout.CENTER);
|
||||
frame.pack();
|
||||
frame.setResizable(false);
|
||||
|
||||
// these don't help either.. they fix the component size but
|
||||
// leave a gap where the component is located
|
||||
//range.setSize(256, 256);
|
||||
//slider.setSize(256, 20);
|
||||
|
||||
Dimension size = frame.getSize();
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
frame.setLocation((screen.width - size.width) / 2,
|
||||
(screen.height - size.height) / 2);
|
||||
|
||||
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
frame.setVisible(false);
|
||||
}
|
||||
});
|
||||
Base.registerWindowCloseKeys(frame.getRootPane(), new ActionListener() {
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
frame.setVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
Base.setIcon(frame);
|
||||
|
||||
hueField.getDocument().addDocumentListener(this);
|
||||
saturationField.getDocument().addDocumentListener(this);
|
||||
brightnessField.getDocument().addDocumentListener(this);
|
||||
redField.getDocument().addDocumentListener(this);
|
||||
greenField.getDocument().addDocumentListener(this);
|
||||
blueField.getDocument().addDocumentListener(this);
|
||||
hexField.getDocument().addDocumentListener(this);
|
||||
|
||||
hexField.setText("FFFFFF");
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
// You've got to be f--ing kidding me.. why did the following line
|
||||
// get deprecated for the pile of s-- that follows it?
|
||||
//frame.setCursor(Cursor.CROSSHAIR_CURSOR);
|
||||
frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
|
||||
}
|
||||
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
//System.out.println("changed");
|
||||
}
|
||||
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
//System.out.println("remove");
|
||||
}
|
||||
|
||||
|
||||
boolean updating;
|
||||
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
if (updating) return; // don't update forever recursively
|
||||
updating = true;
|
||||
|
||||
Document doc = e.getDocument();
|
||||
if (doc == hueField.getDocument()) {
|
||||
hue = bounded(hue, hueField, 359);
|
||||
updateRGB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == saturationField.getDocument()) {
|
||||
saturation = bounded(saturation, saturationField, 99);
|
||||
updateRGB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == brightnessField.getDocument()) {
|
||||
brightness = bounded(brightness, brightnessField, 99);
|
||||
updateRGB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == redField.getDocument()) {
|
||||
red = bounded(red, redField, 255);
|
||||
updateHSB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == greenField.getDocument()) {
|
||||
green = bounded(green, greenField, 255);
|
||||
updateHSB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == blueField.getDocument()) {
|
||||
blue = bounded(blue, blueField, 255);
|
||||
updateHSB();
|
||||
updateHex();
|
||||
|
||||
} else if (doc == hexField.getDocument()) {
|
||||
String str = hexField.getText();
|
||||
while (str.length() < 6) {
|
||||
str += "0";
|
||||
}
|
||||
if (str.length() > 6) {
|
||||
str = str.substring(0, 6);
|
||||
}
|
||||
updateRGB2(Integer.parseInt(str, 16));
|
||||
updateHSB();
|
||||
}
|
||||
range.redraw();
|
||||
slider.redraw();
|
||||
colorPanel.repaint();
|
||||
updating = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the RGB values based on the current HSB values.
|
||||
*/
|
||||
protected void updateRGB() {
|
||||
int rgb = Color.HSBtoRGB((float)hue / 359f,
|
||||
(float)saturation / 99f,
|
||||
(float)brightness / 99f);
|
||||
updateRGB2(rgb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the RGB values based on a calculated ARGB int.
|
||||
* Used by both updateRGB() to set the color from the HSB values,
|
||||
* and by updateHex(), to unpack the hex colors and assign them.
|
||||
*/
|
||||
protected void updateRGB2(int rgb) {
|
||||
red = (rgb >> 16) & 0xff;
|
||||
green = (rgb >> 8) & 0xff;
|
||||
blue = rgb & 0xff;
|
||||
|
||||
redField.setText(String.valueOf(red));
|
||||
greenField.setText(String.valueOf(green));
|
||||
blueField.setText(String.valueOf(blue));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the HSB values based on the current RGB values.
|
||||
*/
|
||||
protected void updateHSB() {
|
||||
float hsb[] = new float[3];
|
||||
Color.RGBtoHSB(red, green, blue, hsb);
|
||||
|
||||
hue = (int) (hsb[0] * 359.0f);
|
||||
saturation = (int) (hsb[1] * 99.0f);
|
||||
brightness = (int) (hsb[2] * 99.0f);
|
||||
|
||||
hueField.setText(String.valueOf(hue));
|
||||
saturationField.setText(String.valueOf(saturation));
|
||||
brightnessField.setText(String.valueOf(brightness));
|
||||
}
|
||||
|
||||
|
||||
protected void updateHex() {
|
||||
hexField.setText(PApplet.hex(red, 2) +
|
||||
PApplet.hex(green, 2) +
|
||||
PApplet.hex(blue, 2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the bounded value for a specific range. If the value is outside
|
||||
* the max, you can't edit right away, so just act as if it's already
|
||||
* been bounded and return the bounded value, then fire an event to set
|
||||
* it to the value that was just returned.
|
||||
*/
|
||||
protected int bounded(int current, final JTextField field, final int max) {
|
||||
String text = field.getText();
|
||||
if (text.length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
int value = Integer.parseInt(text);
|
||||
if (value > max) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
field.setText(String.valueOf(max));
|
||||
}
|
||||
});
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
return current; // should not be reachable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Container createColorFields() {
|
||||
Box box = Box.createVerticalBox();
|
||||
box.setAlignmentY(0);
|
||||
|
||||
colorPanel = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
g.setColor(new Color(red, green, blue));
|
||||
Dimension size = getSize();
|
||||
g.fillRect(0, 0, size.width, size.height);
|
||||
}
|
||||
};
|
||||
colorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
|
||||
Dimension dim = new Dimension(60, 40);
|
||||
colorPanel.setMinimumSize(dim);
|
||||
//colorPanel.setMaximumSize(dim);
|
||||
//colorPanel.setPreferredSize(dim);
|
||||
box.add(colorPanel);
|
||||
box.add(Box.createVerticalStrut(10));
|
||||
|
||||
Box row;
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("H:"));
|
||||
row.add(hueField = new NumberField(4, false));
|
||||
row.add(new JLabel(" \u00B0")); // degree symbol
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(5));
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("S:"));
|
||||
row.add(saturationField = new NumberField(4, false));
|
||||
row.add(new JLabel(" %"));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(5));
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("B:"));
|
||||
row.add(brightnessField = new NumberField(4, false));
|
||||
row.add(new JLabel(" %"));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(10));
|
||||
|
||||
//
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("R:"));
|
||||
row.add(redField = new NumberField(4, false));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(5));
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("G:"));
|
||||
row.add(greenField = new NumberField(4, false));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(5));
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("B:"));
|
||||
row.add(blueField = new NumberField(4, false));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(10));
|
||||
|
||||
//
|
||||
|
||||
row = Box.createHorizontalBox();
|
||||
row.add(createFixedLabel("#"));
|
||||
row.add(hexField = new NumberField(5, true));
|
||||
row.add(Box.createHorizontalGlue());
|
||||
box.add(row);
|
||||
box.add(Box.createVerticalStrut(10));
|
||||
|
||||
box.add(Box.createVerticalGlue());
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
int labelH;
|
||||
|
||||
/**
|
||||
* return a label of a fixed width
|
||||
*/
|
||||
protected JLabel createFixedLabel(String title) {
|
||||
JLabel label = new JLabel(title);
|
||||
if (labelH == 0) {
|
||||
labelH = label.getPreferredSize().height;
|
||||
}
|
||||
Dimension dim = new Dimension(20, labelH);
|
||||
label.setPreferredSize(dim);
|
||||
label.setMinimumSize(dim);
|
||||
label.setMaximumSize(dim);
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
public class ColorRange extends PApplet {
|
||||
|
||||
static final int WIDE = 256;
|
||||
static final int HIGH = 256;
|
||||
|
||||
int lastX, lastY;
|
||||
|
||||
|
||||
public void setup() {
|
||||
size(WIDE, HIGH, P3D);
|
||||
noLoop();
|
||||
|
||||
colorMode(HSB, 360, 256, 256);
|
||||
noFill();
|
||||
rectMode(CENTER);
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
if ((g == null) || (g.pixels == null)) return;
|
||||
if ((width != WIDE) || (height < HIGH)) {
|
||||
//System.out.println("bad size " + width + " " + height);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (int j = 0; j < 256; j++) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
g.pixels[index++] = color(hue, i, 255 - j);
|
||||
}
|
||||
}
|
||||
|
||||
stroke((brightness > 50) ? 0 : 255);
|
||||
rect(lastX, lastY, 9, 9);
|
||||
}
|
||||
|
||||
public void mousePressed() {
|
||||
updateMouse();
|
||||
}
|
||||
|
||||
public void mouseDragged() {
|
||||
updateMouse();
|
||||
}
|
||||
|
||||
public void updateMouse() {
|
||||
if ((mouseX >= 0) && (mouseX < 256) &&
|
||||
(mouseY >= 0) && (mouseY < 256)) {
|
||||
int nsaturation = (int) (100 * (mouseX / 255.0f));
|
||||
int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f)));
|
||||
saturationField.setText(String.valueOf(nsaturation));
|
||||
brightnessField.setText(String.valueOf(nbrightness));
|
||||
|
||||
lastX = mouseX;
|
||||
lastY = mouseY;
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(WIDE, HIGH);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(WIDE, HIGH);
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ColorSlider extends PApplet {
|
||||
|
||||
static final int WIDE = 20;
|
||||
static final int HIGH = 256;
|
||||
|
||||
public void setup() {
|
||||
size(WIDE, HIGH, P3D);
|
||||
colorMode(HSB, 255, 100, 100);
|
||||
noLoop();
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
if ((g == null) || (g.pixels == null)) return;
|
||||
if ((width != WIDE) || (height < HIGH)) {
|
||||
//System.out.println("bad size " + width + " " + height);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
int sel = 255 - (int) (255 * (hue / 359f));
|
||||
for (int j = 0; j < 256; j++) {
|
||||
int c = color(255 - j, 100, 100);
|
||||
if (j == sel) c = 0xFF000000;
|
||||
for (int i = 0; i < WIDE; i++) {
|
||||
g.pixels[index++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mousePressed() {
|
||||
updateMouse();
|
||||
}
|
||||
|
||||
public void mouseDragged() {
|
||||
updateMouse();
|
||||
}
|
||||
|
||||
public void updateMouse() {
|
||||
if ((mouseX >= 0) && (mouseX < 256) &&
|
||||
(mouseY >= 0) && (mouseY < 256)) {
|
||||
int nhue = 359 - (int) (359 * (mouseY / 255.0f));
|
||||
hueField.setText(String.valueOf(nhue));
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(WIDE, HIGH);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(WIDE, HIGH);
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of JTextField that only allows numbers
|
||||
*/
|
||||
class NumberField extends JTextField {
|
||||
|
||||
public boolean allowHex;
|
||||
|
||||
public NumberField(int cols, boolean allowHex) {
|
||||
super(cols);
|
||||
this.allowHex = allowHex;
|
||||
}
|
||||
|
||||
protected Document createDefaultModel() {
|
||||
return new NumberDocument(this);
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
if (!allowHex) {
|
||||
return new Dimension(45, super.getPreferredSize().height);
|
||||
}
|
||||
return super.getPreferredSize();
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Document model to go with JTextField that only allows numbers.
|
||||
*/
|
||||
class NumberDocument extends PlainDocument {
|
||||
|
||||
NumberField parentField;
|
||||
|
||||
public NumberDocument(NumberField parentField) {
|
||||
this.parentField = parentField;
|
||||
//System.out.println("setting parent to " + parentSelector);
|
||||
}
|
||||
|
||||
public void insertString(int offs, String str, AttributeSet a)
|
||||
throws BadLocationException {
|
||||
|
||||
if (str == null) return;
|
||||
|
||||
char chars[] = str.toCharArray();
|
||||
int charCount = 0;
|
||||
// remove any non-digit chars
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
boolean ok = Character.isDigit(chars[i]);
|
||||
if (parentField.allowHex) {
|
||||
if ((chars[i] >= 'A') && (chars[i] <= 'F')) ok = true;
|
||||
if ((chars[i] >= 'a') && (chars[i] <= 'f')) ok = true;
|
||||
}
|
||||
if (ok) {
|
||||
if (charCount != i) { // shift if necessary
|
||||
chars[charCount] = chars[i];
|
||||
}
|
||||
charCount++;
|
||||
}
|
||||
}
|
||||
super.insertString(offs, new String(chars, 0, charCount), a);
|
||||
// can't call any sort of methods on the enclosing class here
|
||||
// seems to have something to do with how Document objects are set up
|
||||
}
|
||||
}
|
||||
}
|
@ -1,813 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.tools;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.core.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
|
||||
/**
|
||||
* GUI tool for font creation heaven/hell.
|
||||
*/
|
||||
public class CreateFont extends JFrame implements Tool {
|
||||
Editor editor;
|
||||
//Sketch sketch;
|
||||
|
||||
Dimension windowSize;
|
||||
|
||||
JList fontSelector;
|
||||
JTextField sizeSelector;
|
||||
JButton charsetButton;
|
||||
JCheckBox smoothBox;
|
||||
JComponent sample;
|
||||
JButton okButton;
|
||||
JTextField filenameField;
|
||||
|
||||
HashMap<String,Font> table;
|
||||
boolean smooth = true;
|
||||
|
||||
Font font;
|
||||
|
||||
String[] list;
|
||||
int selection = -1;
|
||||
|
||||
CharacterSelector charSelector;
|
||||
|
||||
|
||||
public CreateFont() {
|
||||
super("Create Font");
|
||||
}
|
||||
|
||||
|
||||
public String getMenuTitle() {
|
||||
return "Create Font...";
|
||||
}
|
||||
|
||||
|
||||
public void init(Editor editor) {
|
||||
this.editor = editor;
|
||||
|
||||
Container paine = getContentPane();
|
||||
paine.setLayout(new BorderLayout()); //10, 10));
|
||||
|
||||
JPanel pain = new JPanel();
|
||||
pain.setBorder(new EmptyBorder(13, 13, 13, 13));
|
||||
paine.add(pain, BorderLayout.CENTER);
|
||||
|
||||
pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS));
|
||||
|
||||
String labelText =
|
||||
"Use this tool to create bitmap fonts for your program.\n" +
|
||||
"Select a font and size, and click 'OK' to generate the font.\n" +
|
||||
"It will be added to the data folder of the current sketch.";
|
||||
|
||||
JTextArea textarea = new JTextArea(labelText);
|
||||
textarea.setBorder(new EmptyBorder(10, 10, 20, 10));
|
||||
textarea.setBackground(null);
|
||||
textarea.setEditable(false);
|
||||
textarea.setHighlighter(null);
|
||||
textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
|
||||
pain.add(textarea);
|
||||
|
||||
// don't care about families starting with . or #
|
||||
// also ignore dialog, dialoginput, monospaced, serif, sansserif
|
||||
|
||||
// getFontList is deprecated in 1.4, so this has to be used
|
||||
GraphicsEnvironment ge =
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
|
||||
Font fonts[] = ge.getAllFonts();
|
||||
|
||||
String flist[] = new String[fonts.length];
|
||||
table = new HashMap<String,Font>();
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < fonts.length; i++) {
|
||||
//String psname = fonts[i].getPSName();
|
||||
//if (psname == null) System.err.println("ps name is null");
|
||||
|
||||
flist[index++] = fonts[i].getPSName();
|
||||
table.put(fonts[i].getPSName(), fonts[i]);
|
||||
}
|
||||
|
||||
list = new String[index];
|
||||
System.arraycopy(flist, 0, list, 0, index);
|
||||
|
||||
fontSelector = new JList(list);
|
||||
fontSelector.addListSelectionListener(new ListSelectionListener() {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (e.getValueIsAdjusting() == false) {
|
||||
selection = fontSelector.getSelectedIndex();
|
||||
okButton.setEnabled(true);
|
||||
update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fontSelector.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
fontSelector.setVisibleRowCount(12);
|
||||
JScrollPane fontScroller = new JScrollPane(fontSelector);
|
||||
pain.add(fontScroller);
|
||||
|
||||
Dimension d1 = new Dimension(13, 13);
|
||||
pain.add(new Box.Filler(d1, d1, d1));
|
||||
|
||||
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));
|
||||
|
||||
pain.add(sample);
|
||||
|
||||
Dimension d2 = new Dimension(6, 6);
|
||||
pain.add(new Box.Filler(d2, d2, d2));
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
panel.add(new JLabel("Size:"));
|
||||
sizeSelector = new JTextField(" 48 ");
|
||||
sizeSelector.getDocument().addDocumentListener(new DocumentListener() {
|
||||
public void insertUpdate(DocumentEvent e) { update(); }
|
||||
public void removeUpdate(DocumentEvent e) { update(); }
|
||||
public void changedUpdate(DocumentEvent e) { }
|
||||
});
|
||||
panel.add(sizeSelector);
|
||||
|
||||
smoothBox = new JCheckBox("Smooth");
|
||||
smoothBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
smooth = smoothBox.isSelected();
|
||||
update();
|
||||
}
|
||||
});
|
||||
smoothBox.setSelected(smooth);
|
||||
panel.add(smoothBox);
|
||||
|
||||
// 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) {
|
||||
//showCharacterList();
|
||||
charSelector.setVisible(true);
|
||||
}
|
||||
});
|
||||
panel.add(charsetButton);
|
||||
|
||||
pain.add(panel);
|
||||
|
||||
JPanel filestuff = new JPanel();
|
||||
filestuff.add(new JLabel("Filename:"));
|
||||
filestuff.add(filenameField = new JTextField(20));
|
||||
filestuff.add(new JLabel(".vlw"));
|
||||
pain.add(filestuff);
|
||||
|
||||
JPanel buttons = new JPanel();
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
okButton = new JButton("OK");
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
build();
|
||||
}
|
||||
});
|
||||
okButton.setEnabled(false);
|
||||
|
||||
buttons.add(cancelButton);
|
||||
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);
|
||||
|
||||
setResizable(false);
|
||||
pack();
|
||||
|
||||
// do this after pack so it doesn't affect layout
|
||||
sample.setFont(new Font(list[0], Font.PLAIN, 48));
|
||||
|
||||
fontSelector.setSelectedIndex(0);
|
||||
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
windowSize = getSize();
|
||||
|
||||
setLocation((screen.width - windowSize.width) / 2,
|
||||
(screen.height - windowSize.height) / 2);
|
||||
|
||||
// create this behind the scenes
|
||||
charSelector = new CharacterSelector();
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
public void update() {
|
||||
int fontsize = 0;
|
||||
try {
|
||||
fontsize = Integer.parseInt(sizeSelector.getText().trim());
|
||||
//System.out.println("'" + sizeSelector.getText() + "'");
|
||||
} catch (NumberFormatException e2) { }
|
||||
|
||||
// if a deselect occurred, selection will be -1
|
||||
if ((fontsize > 0) && (fontsize < 256) && (selection != -1)) {
|
||||
//font = new Font(list[selection], Font.PLAIN, fontsize);
|
||||
Font instance = (Font) table.get(list[selection]);
|
||||
font = instance.deriveFont(Font.PLAIN, fontsize);
|
||||
//System.out.println("setting font to " + font);
|
||||
sample.setFont(font);
|
||||
|
||||
String filenameSuggestion = list[selection].replace(' ', '_');
|
||||
filenameSuggestion += "-" + fontsize;
|
||||
filenameField.setText(filenameSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void build() {
|
||||
int fontsize = 0;
|
||||
try {
|
||||
fontsize = Integer.parseInt(sizeSelector.getText().trim());
|
||||
} catch (NumberFormatException e) { }
|
||||
|
||||
if (fontsize <= 0) {
|
||||
JOptionPane.showMessageDialog(this, "Bad font size, try again.",
|
||||
"Badness", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
String filename = filenameField.getText().trim();
|
||||
if (filename.length() == 0) {
|
||||
JOptionPane.showMessageDialog(this, "Enter a file name for the font.",
|
||||
"Lameness", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (!filename.endsWith(".vlw")) {
|
||||
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.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(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ import javax.swing.text.Segment;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.syntax.*;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
/**
|
||||
* Format for Discourse Tool
|
||||
|
@ -21,7 +21,7 @@ public abstract class AbstractGUITest {
|
||||
Preferences.init(null);
|
||||
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
|
||||
Theme.init();
|
||||
Base.platform.setLookAndFeel();
|
||||
Base.getPlatform().setLookAndFeel();
|
||||
Base.untitledFolder = Base.createTempFolder("untitled");
|
||||
Base.untitledFolder.deleteOnExit();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package processing.app;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
@ -40,7 +41,12 @@ public class I18NTest {
|
||||
return properties;
|
||||
}
|
||||
|
||||
// XXX: I18NTest.class.getResource(".").getFile() no longer works, because
|
||||
// the class is now into the arudino-core package. This test should be refactored
|
||||
// in order to use ResourceBundles to load translations to be checked.
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void ensureEveryTranslationIsComplete() throws Exception {
|
||||
Set<String> keys = loadReferenceI18NKeys();
|
||||
|
||||
|
@ -2,7 +2,7 @@ package processing.app.debug;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Uploader;
|
||||
import cc.arduino.packages.UploaderAndMonitorFactory;
|
||||
import cc.arduino.packages.UploaderFactory;
|
||||
import cc.arduino.packages.uploaders.SSHUploader;
|
||||
import cc.arduino.packages.uploaders.SerialUploader;
|
||||
import org.junit.Before;
|
||||
@ -29,7 +29,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
|
||||
boardPort.setBoardName("yun");
|
||||
boardPort.setAddress("192.168.0.1");
|
||||
boardPort.setProtocol("network");
|
||||
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
|
||||
Uploader uploader = new UploaderFactory().newUploader(board, boardPort, false);
|
||||
|
||||
assertTrue(uploader instanceof SSHUploader);
|
||||
}
|
||||
@ -41,7 +41,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
|
||||
boardPort.setBoardName("myyun");
|
||||
boardPort.setAddress("192.168.0.1");
|
||||
boardPort.setProtocol("network");
|
||||
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
|
||||
Uploader uploader = new UploaderFactory().newUploader(board, boardPort, false);
|
||||
|
||||
assertTrue(uploader instanceof SerialUploader);
|
||||
}
|
||||
@ -53,7 +53,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
|
||||
boardPort.setBoardName("Arduino Leonardo");
|
||||
boardPort.setAddress("/dev/ttyACM0");
|
||||
boardPort.setProtocol("serial");
|
||||
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
|
||||
Uploader uploader = new UploaderFactory().newUploader(board, boardPort, false);
|
||||
|
||||
assertTrue(uploader instanceof SerialUploader);
|
||||
}
|
||||
|
8
arduino-builder/.classpath
Normal file
8
arduino-builder/.classpath
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/arduino-core"/>
|
||||
<classpathentry kind="lib" path="/arduino-core/arduino-core.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>processing-core</name>
|
||||
<name>arduino-builder</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
11
arduino-builder/.settings/org.eclipse.jdt.core.prefs
Normal file
11
arduino-builder/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,11 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
BIN
arduino-builder/bin/cc/arduino/builder/ArduinoBuilder.class
Normal file
BIN
arduino-builder/bin/cc/arduino/builder/ArduinoBuilder.class
Normal file
Binary file not shown.
11
arduino-builder/src/cc/arduino/builder/ArduinoBuilder.java
Normal file
11
arduino-builder/src/cc/arduino/builder/ArduinoBuilder.java
Normal file
@ -0,0 +1,11 @@
|
||||
package cc.arduino.builder;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
|
||||
public class ArduinoBuilder {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
BaseNoGui.main(args);
|
||||
}
|
||||
|
||||
}
|
13
arduino-core/.classpath
Normal file
13
arduino-core/.classpath
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="lib/jna.jar"/>
|
||||
<classpathentry kind="lib" path="lib/apple.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-logging-1.0.4.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmdns-3.4.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jssc-2.8.0.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jsch-0.1.50.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-exec-1.1.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
1
arduino-core/.gitignore
vendored
Normal file
1
arduino-core/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/bin/
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>preproc</name>
|
||||
<name>arduino-core</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
52
arduino-core/build.xml
Normal file
52
arduino-core/build.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Arduino IDE Core" default="build">
|
||||
|
||||
<path id="class.path">
|
||||
<fileset dir="lib">
|
||||
<include name="*.jar"/>
|
||||
</fileset>
|
||||
<pathelement path="${env.JAVA_HOME}/lib/tools.jar"/>
|
||||
</path>
|
||||
|
||||
<target name="clean" description="Clean out the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="arduino-core.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile">
|
||||
<!--
|
||||
<taskdef name="methods"
|
||||
classname="PAppletMethods"
|
||||
classpath="methods/methods.jar" />
|
||||
<methods dir="${basedir}/src/processing/core" />
|
||||
-->
|
||||
<mkdir dir="bin" />
|
||||
|
||||
<!-- ant seems to nuke ${java.home} for some reason, pointing at the JRE
|
||||
subfolder instead of the actual JDK found at JAVA_HOME.
|
||||
To avoid this, we grab the actual JAVA_HOME environment variable
|
||||
and use that to specify the location of tools.jar. -->
|
||||
|
||||
<!-- if someone is better with ant please help clean this up -->
|
||||
<property environment="env" />
|
||||
<property name="java_home" value="${env.JAVA_HOME}" />
|
||||
|
||||
<javac source="1.6"
|
||||
target="1.6"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
srcdir="src"
|
||||
classpathref="class.path"
|
||||
destdir="bin">
|
||||
</javac>
|
||||
|
||||
<copy todir="bin" overwrite="true" verbose="true">
|
||||
<fileset dir="src" includes="**/*.properties" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build core library">
|
||||
<jar basedir="bin" destfile="arduino-core.jar" />
|
||||
</target>
|
||||
|
||||
</project>
|
1
arduino-core/lib/apple.LICENSE.BSD-like.txt
Normal file
1
arduino-core/lib/apple.LICENSE.BSD-like.txt
Normal file
@ -0,0 +1 @@
|
||||
http://developer.apple.com/library/mac/#/legacy/library/samplecode/AppleJavaExtensions/Listings/README_txt.html#//apple_ref/doc/uid/DTS10000677-README_txt-DontLinkElementID_3
|
BIN
arduino-core/lib/apple.jar
Normal file
BIN
arduino-core/lib/apple.jar
Normal file
Binary file not shown.
BIN
arduino-core/lib/commons-exec-1.1.jar
Normal file
BIN
arduino-core/lib/commons-exec-1.1.jar
Normal file
Binary file not shown.
202
arduino-core/lib/commons-exec.LICENSE.ASL-2.0.txt
Normal file
202
arduino-core/lib/commons-exec.LICENSE.ASL-2.0.txt
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
arduino-core/lib/commons-logging-1.0.4.jar
Normal file
BIN
arduino-core/lib/commons-logging-1.0.4.jar
Normal file
Binary file not shown.
202
arduino-core/lib/commons-logging.LICENSE.ASL-2.0.txt
Normal file
202
arduino-core/lib/commons-logging.LICENSE.ASL-2.0.txt
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
arduino-core/lib/jmdns-3.4.1.jar
Normal file
BIN
arduino-core/lib/jmdns-3.4.1.jar
Normal file
Binary file not shown.
2
arduino-core/lib/jmdns.LICENSE.ASL-2.0-LGPL-2.1.txt
Normal file
2
arduino-core/lib/jmdns.LICENSE.ASL-2.0-LGPL-2.1.txt
Normal file
@ -0,0 +1,2 @@
|
||||
https://jmdns.svn.sourceforge.net/svnroot/jmdns/tags/jmdns-3.4.1/LICENSE-LGPL.txt
|
||||
https://jmdns.svn.sourceforge.net/svnroot/jmdns/tags/jmdns-3.4.1/LICENSE
|
1
arduino-core/lib/jna.LICENSE.LGPL-2.1.txt
Normal file
1
arduino-core/lib/jna.LICENSE.LGPL-2.1.txt
Normal file
@ -0,0 +1 @@
|
||||
https://github.com/twall/jna/blob/master/LICENSE
|
BIN
arduino-core/lib/jna.jar
Normal file
BIN
arduino-core/lib/jna.jar
Normal file
Binary file not shown.
BIN
arduino-core/lib/jsch-0.1.50.jar
Normal file
BIN
arduino-core/lib/jsch-0.1.50.jar
Normal file
Binary file not shown.
1
arduino-core/lib/jsch.LICENSE.BSD.txt
Normal file
1
arduino-core/lib/jsch.LICENSE.BSD.txt
Normal file
@ -0,0 +1 @@
|
||||
http://www.jcraft.com/jsch/LICENSE.txt
|
BIN
arduino-core/lib/jssc-2.8.0.jar
Normal file
BIN
arduino-core/lib/jssc-2.8.0.jar
Normal file
Binary file not shown.
674
arduino-core/lib/jssc.LICENSE.GPL.txt
Normal file
674
arduino-core/lib/jssc.LICENSE.GPL.txt
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
165
arduino-core/lib/jssc.LICENSE.LGPL.txt
Normal file
165
arduino-core/lib/jssc.LICENSE.LGPL.txt
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
@ -25,7 +25,7 @@
|
||||
package cc.arduino.packages;
|
||||
|
||||
import processing.app.I18n;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.MessageConsumer;
|
||||
import processing.app.debug.MessageSiphon;
|
||||
import processing.app.debug.RunnerException;
|
||||
@ -64,11 +64,22 @@ public abstract class Uploader implements MessageConsumer {
|
||||
|
||||
private String error;
|
||||
protected boolean notFoundError;
|
||||
protected boolean noUploadPort;
|
||||
|
||||
protected Uploader() {
|
||||
this.verbose = PreferencesData.getBoolean("upload.verbose");
|
||||
init(false);
|
||||
}
|
||||
|
||||
protected Uploader(boolean nup) {
|
||||
this.verbose = PreferencesData.getBoolean("upload.verbose");
|
||||
init(nup);
|
||||
}
|
||||
|
||||
private void init(boolean nup) {
|
||||
this.error = null;
|
||||
this.verbose = Preferences.getBoolean("upload.verbose");
|
||||
this.notFoundError = false;
|
||||
this.noUploadPort = nup;
|
||||
}
|
||||
|
||||
public abstract boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws Exception;
|
@ -31,15 +31,14 @@ package cc.arduino.packages;
|
||||
|
||||
import cc.arduino.packages.uploaders.SSHUploader;
|
||||
import cc.arduino.packages.uploaders.SerialUploader;
|
||||
import processing.app.AbstractMonitor;
|
||||
import processing.app.Base;
|
||||
import processing.app.NetworkMonitor;
|
||||
import processing.app.SerialMonitor;
|
||||
import processing.app.debug.TargetBoard;
|
||||
|
||||
public class UploaderAndMonitorFactory {
|
||||
public class UploaderFactory {
|
||||
|
||||
public Uploader newUploader(TargetBoard board, BoardPort port, boolean noUploadPort) {
|
||||
if (noUploadPort)
|
||||
return new SerialUploader(noUploadPort);
|
||||
|
||||
public Uploader newUploader(TargetBoard board, BoardPort port) {
|
||||
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && port != null && "network".equals(port.getProtocol())) {
|
||||
return new SSHUploader(port);
|
||||
}
|
||||
@ -47,12 +46,4 @@ public class UploaderAndMonitorFactory {
|
||||
return new SerialUploader();
|
||||
}
|
||||
|
||||
public AbstractMonitor newMonitor(BoardPort port, Base base) {
|
||||
if ("network".equals(port.getProtocol())) {
|
||||
return new NetworkMonitor(port, base);
|
||||
}
|
||||
|
||||
return new SerialMonitor(port);
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ package cc.arduino.packages.discoverers;
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Discovery;
|
||||
import cc.arduino.packages.discoverers.network.*;
|
||||
import processing.app.Base;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.helpers.NetUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter;
|
||||
@ -140,7 +140,7 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
|
||||
|
||||
String label = name + " at " + address;
|
||||
if (board != null) {
|
||||
String boardName = Base.getPlatform().resolveDeviceByBoardID(Base.packages, board);
|
||||
String boardName = BaseNoGui.getPlatform().resolveDeviceByBoardID(BaseNoGui.packages, board);
|
||||
label += " (" + boardName + ")";
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ package cc.arduino.packages.discoverers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.Platform;
|
||||
import processing.app.Serial;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
@ -43,7 +43,7 @@ public class SerialDiscovery implements Discovery {
|
||||
|
||||
@Override
|
||||
public List<BoardPort> discovery() {
|
||||
Platform os = Base.getPlatform();
|
||||
Platform os = BaseNoGui.getPlatform();
|
||||
String devicesListOutput = os.preListAllCandidateDevices();
|
||||
|
||||
List<BoardPort> res = new ArrayList<BoardPort>();
|
||||
@ -51,7 +51,7 @@ public class SerialDiscovery implements Discovery {
|
||||
List<String> ports = Serial.list();
|
||||
|
||||
for (String port : ports) {
|
||||
String boardName = os.resolveDeviceAttachedTo(port, Base.packages, devicesListOutput);
|
||||
String boardName = os.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput);
|
||||
String label = port;
|
||||
if (boardName != null)
|
||||
label += " (" + boardName + ")";
|
@ -4,7 +4,7 @@ import cc.arduino.packages.BoardPort;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.PreferencesData;
|
||||
|
||||
public class SSHPwdSetup implements SSHClientSetupChainRing {
|
||||
|
||||
@ -13,7 +13,7 @@ public class SSHPwdSetup implements SSHClientSetupChainRing {
|
||||
String ipAddress = port.getAddress();
|
||||
|
||||
Session session = jSch.getSession("root", ipAddress, 22);
|
||||
session.setPassword(Preferences.get("runtime.pwd." + ipAddress));
|
||||
session.setPassword(PreferencesData.get("runtime.pwd." + ipAddress));
|
||||
|
||||
return session;
|
||||
}
|
@ -35,9 +35,9 @@ import cc.arduino.packages.ssh.*;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import processing.app.Base;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
@ -82,7 +82,7 @@ public class SSHUploader extends Uploader {
|
||||
SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
|
||||
session = sshClientSetupChain.setup(port, jSch);
|
||||
|
||||
session.setUserInfo(new NoInteractionUserInfo(Preferences.get("runtime.pwd." + port.getAddress())));
|
||||
session.setUserInfo(new NoInteractionUserInfo(PreferencesData.get("runtime.pwd." + port.getAddress())));
|
||||
session.connect(30000);
|
||||
|
||||
scp = new SCP(session);
|
||||
@ -117,9 +117,9 @@ public class SSHUploader extends Uploader {
|
||||
}
|
||||
|
||||
private boolean runAVRDude(SSH ssh) throws IOException, JSchException {
|
||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||
PreferencesMap prefs = Preferences.getMap();
|
||||
prefs.putAll(Base.getBoardPreferences());
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
|
||||
|
||||
String additionalParams = verbose ? prefs.get("upload.params.verbose") : prefs.get("upload.params.quiet");
|
@ -32,28 +32,39 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.Serial;
|
||||
import processing.app.SerialException;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.StringReplacer;
|
||||
import cc.arduino.packages.Uploader;
|
||||
|
||||
public class SerialUploader extends Uploader {
|
||||
|
||||
public SerialUploader()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SerialUploader(boolean noUploadPort)
|
||||
{
|
||||
super(noUploadPort);
|
||||
}
|
||||
|
||||
public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws Exception {
|
||||
// FIXME: Preferences should be reorganized
|
||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||
PreferencesMap prefs = Preferences.getMap();
|
||||
prefs.putAll(Base.getBoardPreferences());
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
String tool = prefs.getOrExcept("upload.tool");
|
||||
if (tool.contains(":")) {
|
||||
String[] split = tool.split(":", 2);
|
||||
targetPlatform = Base.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
targetPlatform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
tool = split[1];
|
||||
}
|
||||
prefs.putAll(targetPlatform.getTool(tool));
|
||||
@ -64,6 +75,26 @@ public class SerialUploader extends Uploader {
|
||||
return uploadUsingProgrammer(buildPath, className);
|
||||
}
|
||||
|
||||
if (noUploadPort)
|
||||
{
|
||||
prefs.put("build.path", buildPath);
|
||||
prefs.put("build.project_name", className);
|
||||
if (verbose)
|
||||
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.verbose"));
|
||||
else
|
||||
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.quiet"));
|
||||
|
||||
boolean uploadResult;
|
||||
try {
|
||||
String pattern = prefs.getOrExcept("upload.pattern");
|
||||
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
uploadResult = executeUploadCommand(cmd);
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
return uploadResult;
|
||||
}
|
||||
|
||||
// need to do a little dance for Leonardo and derivatives:
|
||||
// open then close the port at the magic baudrate (usually 1200 bps) first
|
||||
// to signal to the sketch that it should reset into bootloader. after doing
|
||||
@ -131,7 +162,7 @@ public class SerialUploader extends Uploader {
|
||||
|
||||
try {
|
||||
if (uploadResult && doTouch) {
|
||||
String uploadPort = Preferences.get("serial.port");
|
||||
String uploadPort = PreferencesData.get("serial.port");
|
||||
if (waitForUploadPort) {
|
||||
// For Due/Leonardo wait until the bootloader serial port disconnects and the
|
||||
// sketch serial port reconnects (or timeout after a few seconds if the
|
||||
@ -188,7 +219,7 @@ public class SerialUploader extends Uploader {
|
||||
// come back, so use a longer time out before assuming that the
|
||||
// selected
|
||||
// port is the bootloader (not the sketch).
|
||||
if (((!Base.isWindows() && elapsed >= 500) || elapsed >= 5000) && now.contains(uploadPort)) {
|
||||
if (((!OSUtils.isWindows() && elapsed >= 500) || elapsed >= 5000) && now.contains(uploadPort)) {
|
||||
if (verbose)
|
||||
System.out.println("Uploading using selected port: " + uploadPort);
|
||||
return uploadPort;
|
||||
@ -201,16 +232,16 @@ public class SerialUploader extends Uploader {
|
||||
|
||||
public boolean uploadUsingProgrammer(String buildPath, String className) throws Exception {
|
||||
|
||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||
String programmer = Preferences.get("programmer");
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
String programmer = PreferencesData.get("programmer");
|
||||
if (programmer.contains(":")) {
|
||||
String[] split = programmer.split(":", 2);
|
||||
targetPlatform = Base.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
targetPlatform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
programmer = split[1];
|
||||
}
|
||||
|
||||
PreferencesMap prefs = Preferences.getMap();
|
||||
prefs.putAll(Base.getBoardPreferences());
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
PreferencesMap programmerPrefs = targetPlatform.getProgrammer(programmer);
|
||||
if (programmerPrefs == null)
|
||||
throw new RunnerException(
|
||||
@ -244,14 +275,14 @@ public class SerialUploader extends Uploader {
|
||||
}
|
||||
|
||||
public boolean burnBootloader() throws Exception {
|
||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
|
||||
// Find preferences for the selected programmer
|
||||
PreferencesMap programmerPrefs;
|
||||
String programmer = Preferences.get("programmer");
|
||||
String programmer = PreferencesData.get("programmer");
|
||||
if (programmer.contains(":")) {
|
||||
String[] split = programmer.split(":", 2);
|
||||
TargetPlatform platform = Base.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
TargetPlatform platform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
programmer = split[1];
|
||||
programmerPrefs = platform.getProgrammer(programmer);
|
||||
} else {
|
||||
@ -262,8 +293,8 @@ public class SerialUploader extends Uploader {
|
||||
_("Please select a programmer from Tools->Programmer menu"));
|
||||
|
||||
// Build configuration for the current programmer
|
||||
PreferencesMap prefs = Preferences.getMap();
|
||||
prefs.putAll(Base.getBoardPreferences());
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
prefs.putAll(programmerPrefs);
|
||||
|
||||
// Create configuration for bootloader tool
|
||||
@ -271,7 +302,7 @@ public class SerialUploader extends Uploader {
|
||||
String tool = prefs.getOrExcept("bootloader.tool");
|
||||
if (tool.contains(":")) {
|
||||
String[] split = tool.split(":", 2);
|
||||
TargetPlatform platform = Base.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
TargetPlatform platform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
tool = split[1];
|
||||
toolPrefs.putAll(platform.getTool(tool));
|
||||
if (toolPrefs.size() == 0)
|
977
arduino-core/src/processing/app/BaseNoGui.java
Normal file
977
arduino-core/src/processing/app/BaseNoGui.java
Normal file
@ -0,0 +1,977 @@
|
||||
package processing.app;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.logging.impl.LogFactoryImpl;
|
||||
import org.apache.commons.logging.impl.NoOpLog;
|
||||
|
||||
import cc.arduino.packages.DiscoveryManager;
|
||||
import cc.arduino.packages.Uploader;
|
||||
|
||||
import processing.app.debug.Compiler;
|
||||
import processing.app.debug.TargetBoard;
|
||||
import processing.app.debug.TargetPackage;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.debug.TargetPlatformException;
|
||||
import processing.app.helpers.BasicUserNotifier;
|
||||
import processing.app.helpers.CommandlineParser;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.UserNotifier;
|
||||
import processing.app.helpers.filefilters.OnlyDirs;
|
||||
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
|
||||
import processing.app.legacy.PApplet;
|
||||
import processing.app.packages.Library;
|
||||
import processing.app.packages.LibraryList;
|
||||
|
||||
public class BaseNoGui {
|
||||
|
||||
public static final int REVISION = 158;
|
||||
/** This might be replaced by main() if there's a lib/version.txt file. */
|
||||
static String VERSION_NAME = "0158";
|
||||
/** Set true if this a proper release rather than a numbered revision. */
|
||||
static public boolean RELEASE = false;
|
||||
|
||||
static File buildFolder;
|
||||
|
||||
// Current directory to use for relative paths specified on the
|
||||
// commandline
|
||||
static String currentDirectory = System.getProperty("user.dir");
|
||||
|
||||
private static DiscoveryManager discoveryManager = new DiscoveryManager();
|
||||
|
||||
// these are static because they're used by Sketch
|
||||
static private File examplesFolder;
|
||||
static private File toolsFolder;
|
||||
|
||||
// maps #included files to their library folder
|
||||
public static Map<String, Library> importToLibraryTable;
|
||||
|
||||
// maps library name to their library folder
|
||||
static private LibraryList libraries;
|
||||
|
||||
static private List<File> librariesFolders;
|
||||
|
||||
static UserNotifier notifier = new BasicUserNotifier();
|
||||
|
||||
static public Map<String, TargetPackage> packages;
|
||||
|
||||
static Platform platform;
|
||||
|
||||
static File portableFolder = null;
|
||||
|
||||
static final String portableSketchbookFolder = "sketchbook";
|
||||
|
||||
// Returns a File object for the given pathname. If the pathname
|
||||
// is not absolute, it is interpreted relative to the current
|
||||
// directory when starting the IDE (which is not the same as the
|
||||
// current working directory!).
|
||||
static public File absoluteFile(String path) {
|
||||
if (path == null) return null;
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.isAbsolute()) {
|
||||
file = new File(currentDirectory, path);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of lines in a file by counting the number of newline
|
||||
* characters inside a String (and adding 1).
|
||||
*/
|
||||
static public int countLines(String what) {
|
||||
int count = 1;
|
||||
for (char c : what.toCharArray()) {
|
||||
if (c == '\n') count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the platform's temporary folder, by creating
|
||||
* a temporary temporary file and getting its parent folder.
|
||||
* <br/>
|
||||
* Modified for revision 0094 to actually make the folder randomized
|
||||
* to avoid conflicts in multi-user environments. (Bug 177)
|
||||
*/
|
||||
static public File createTempFolder(String name) {
|
||||
try {
|
||||
File folder = File.createTempFile(name, null);
|
||||
//String tempPath = ignored.getParent();
|
||||
//return new File(tempPath);
|
||||
folder.delete();
|
||||
folder.mkdirs();
|
||||
return folder;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public String getAvrBasePath() {
|
||||
String path = getHardwarePath() + File.separator + "tools" +
|
||||
File.separator + "avr" + File.separator + "bin" + File.separator;
|
||||
if (OSUtils.isLinux() && !(new File(path)).exists()) {
|
||||
return ""; // use distribution provided avr tools if bundled tools missing
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static public File getBuildFolder() {
|
||||
if (buildFolder == null) {
|
||||
String buildPath = PreferencesData.get("build.path");
|
||||
if (buildPath != null) {
|
||||
buildFolder = absoluteFile(buildPath);
|
||||
if (!buildFolder.exists())
|
||||
buildFolder.mkdirs();
|
||||
} else {
|
||||
//File folder = new File(getTempFolder(), "build");
|
||||
//if (!folder.exists()) folder.mkdirs();
|
||||
buildFolder = createTempFolder("build");
|
||||
buildFolder.deleteOnExit();
|
||||
}
|
||||
}
|
||||
return buildFolder;
|
||||
}
|
||||
|
||||
static public PreferencesMap getBoardPreferences() {
|
||||
TargetBoard board = getTargetBoard();
|
||||
|
||||
PreferencesMap prefs = new PreferencesMap(board.getPreferences());
|
||||
for (String menuId : board.getMenuIds()) {
|
||||
String entry = PreferencesData.get("custom_" + menuId);
|
||||
if (board.hasMenu(menuId) && entry != null &&
|
||||
entry.startsWith(board.getId())) {
|
||||
String selectionId = entry.substring(entry.indexOf("_") + 1);
|
||||
prefs.putAll(board.getMenuPreferences(menuId, selectionId));
|
||||
prefs.put("name", prefs.get("name") + ", " +
|
||||
board.getMenuLabel(menuId, selectionId));
|
||||
}
|
||||
}
|
||||
return prefs;
|
||||
}
|
||||
|
||||
static public File getContentFile(String name) {
|
||||
String path = System.getProperty("user.dir");
|
||||
|
||||
// Get a path to somewhere inside the .app folder
|
||||
if (OSUtils.isMacOS()) {
|
||||
// <key>javaroot</key>
|
||||
// <string>$JAVAROOT</string>
|
||||
String javaroot = System.getProperty("javaroot");
|
||||
if (javaroot != null) {
|
||||
path = javaroot;
|
||||
}
|
||||
}
|
||||
File working = new File(path);
|
||||
return new File(working, name);
|
||||
}
|
||||
|
||||
static public TargetPlatform getCurrentTargetPlatformFromPackage(String pack) {
|
||||
return getTargetPlatform(pack, PreferencesData.get("target_platform"));
|
||||
}
|
||||
|
||||
static public File getDefaultSketchbookFolder() {
|
||||
if (getPortableFolder() != null)
|
||||
return new File(getPortableFolder(), getPortableSketchbookFolder());
|
||||
|
||||
File sketchbookFolder = null;
|
||||
try {
|
||||
sketchbookFolder = getPlatform().getDefaultSketchbookFolder();
|
||||
} catch (Exception e) { }
|
||||
|
||||
return sketchbookFolder;
|
||||
}
|
||||
|
||||
public static DiscoveryManager getDiscoveryManager() {
|
||||
return discoveryManager;
|
||||
}
|
||||
|
||||
static public File getExamplesFolder() {
|
||||
return examplesFolder;
|
||||
}
|
||||
|
||||
static public String getExamplesPath() {
|
||||
return examplesFolder.getAbsolutePath();
|
||||
}
|
||||
|
||||
static public File getHardwareFolder() {
|
||||
// calculate on the fly because it's needed by Preferences.init() to find
|
||||
// the boards.txt and programmers.txt preferences files (which happens
|
||||
// before the other folders / paths get cached).
|
||||
return getContentFile("hardware");
|
||||
}
|
||||
|
||||
static public String getHardwarePath() {
|
||||
return getHardwareFolder().getAbsolutePath();
|
||||
}
|
||||
|
||||
static public LibraryList getLibraries() {
|
||||
return libraries;
|
||||
}
|
||||
|
||||
static public List<File> getLibrariesPath() {
|
||||
return librariesFolders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an InputStream for a file inside the Processing lib folder.
|
||||
*/
|
||||
static public InputStream getLibStream(String filename) throws IOException {
|
||||
return new FileInputStream(new File(getContentFile("lib"), filename));
|
||||
}
|
||||
|
||||
static public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
static public File getPortableFolder() {
|
||||
return portableFolder;
|
||||
}
|
||||
|
||||
static public String getPortableSketchbookFolder() {
|
||||
return portableSketchbookFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a File object for the specified filename inside
|
||||
* the settings folder.
|
||||
* For now, only used by Preferences to get the preferences.txt file.
|
||||
* @param filename A file inside the settings folder.
|
||||
* @return filename wrapped as a File object inside the settings folder
|
||||
*/
|
||||
static public File getSettingsFile(String filename) {
|
||||
return new File(getSettingsFolder(), filename);
|
||||
}
|
||||
|
||||
static public File getSettingsFolder() {
|
||||
if (getPortableFolder() != null)
|
||||
return getPortableFolder();
|
||||
|
||||
File settingsFolder = null;
|
||||
|
||||
String preferencesPath = PreferencesData.get("settings.path");
|
||||
if (preferencesPath != null) {
|
||||
settingsFolder = absoluteFile(preferencesPath);
|
||||
|
||||
} else {
|
||||
try {
|
||||
settingsFolder = getPlatform().getSettingsFolder();
|
||||
} catch (Exception e) {
|
||||
showError(_("Problem getting data folder"),
|
||||
_("Error getting the Arduino data folder."), e);
|
||||
}
|
||||
}
|
||||
|
||||
// create the folder if it doesn't exist already
|
||||
if (!settingsFolder.exists()) {
|
||||
if (!settingsFolder.mkdirs()) {
|
||||
showError(_("Settings issues"),
|
||||
_("Arduino cannot run because it could not\n" +
|
||||
"create a folder to store your settings."), null);
|
||||
}
|
||||
}
|
||||
return settingsFolder;
|
||||
}
|
||||
|
||||
static public File getSketchbookFolder() {
|
||||
if (portableFolder != null)
|
||||
return new File(portableFolder, PreferencesData.get("sketchbook.path"));
|
||||
return absoluteFile(PreferencesData.get("sketchbook.path"));
|
||||
}
|
||||
|
||||
static public File getSketchbookHardwareFolder() {
|
||||
return new File(getSketchbookFolder(), "hardware");
|
||||
}
|
||||
|
||||
static public File getSketchbookLibrariesFolder() {
|
||||
File libdir = new File(getSketchbookFolder(), "libraries");
|
||||
if (!libdir.exists()) {
|
||||
try {
|
||||
libdir.mkdirs();
|
||||
File readme = new File(libdir, "readme.txt");
|
||||
FileWriter freadme = new FileWriter(readme);
|
||||
freadme.write(_("For information on installing libraries, see: " +
|
||||
"http://arduino.cc/en/Guide/Libraries\n"));
|
||||
freadme.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return libdir;
|
||||
}
|
||||
|
||||
static public String getSketchbookPath() {
|
||||
// Get the sketchbook path, and make sure it's set properly
|
||||
String sketchbookPath = PreferencesData.get("sketchbook.path");
|
||||
|
||||
// If a value is at least set, first check to see if the folder exists.
|
||||
// If it doesn't, warn the user that the sketchbook folder is being reset.
|
||||
if (sketchbookPath != null) {
|
||||
File sketchbookFolder;
|
||||
if (getPortableFolder() != null)
|
||||
sketchbookFolder = new File(getPortableFolder(), sketchbookPath);
|
||||
else
|
||||
sketchbookFolder = absoluteFile(sketchbookPath);
|
||||
if (!sketchbookFolder.exists()) {
|
||||
showWarning(_("Sketchbook folder disappeared"),
|
||||
_("The sketchbook folder no longer exists.\n" +
|
||||
"Arduino will switch to the default sketchbook\n" +
|
||||
"location, and create a new sketchbook folder if\n" +
|
||||
"necessary. Arduino will then stop talking about\n" +
|
||||
"himself in the third person."), null);
|
||||
sketchbookPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
return sketchbookPath;
|
||||
}
|
||||
|
||||
public static TargetBoard getTargetBoard() {
|
||||
String boardId = PreferencesData.get("board");
|
||||
return getTargetPlatform().getBoard(boardId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific TargetPackage
|
||||
*
|
||||
* @param packageName
|
||||
* @return
|
||||
*/
|
||||
static public TargetPackage getTargetPackage(String packageName) {
|
||||
return packages.get(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected TargetPlatform.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static public TargetPlatform getTargetPlatform() {
|
||||
String packageName = PreferencesData.get("target_package");
|
||||
String platformName = PreferencesData.get("target_platform");
|
||||
return getTargetPlatform(packageName, platformName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific TargetPlatform searching Package/Platform
|
||||
*
|
||||
* @param packageName
|
||||
* @param platformName
|
||||
* @return
|
||||
*/
|
||||
static public TargetPlatform getTargetPlatform(String packageName,
|
||||
String platformName) {
|
||||
TargetPackage p = packages.get(packageName);
|
||||
if (p == null)
|
||||
return null;
|
||||
return p.get(platformName);
|
||||
}
|
||||
|
||||
static public File getToolsFolder() {
|
||||
return toolsFolder;
|
||||
}
|
||||
|
||||
static public String getToolsPath() {
|
||||
return toolsFolder.getAbsolutePath();
|
||||
}
|
||||
|
||||
static public LibraryList getUserLibs() {
|
||||
if (libraries == null)
|
||||
return new LibraryList();
|
||||
return libraries.filterLibrariesInSubfolder(getSketchbookFolder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a folder, return a list of the header files in that folder (but not
|
||||
* the header files in its sub-folders, as those should be included from
|
||||
* within the header files at the top-level).
|
||||
*/
|
||||
static public String[] headerListFromIncludePath(File path) throws IOException {
|
||||
String[] list = path.list(new OnlyFilesWithExtension(".h"));
|
||||
if (list == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static public void init(String[] args) {
|
||||
getPlatform().init();
|
||||
|
||||
String sketchbookPath = getSketchbookPath();
|
||||
|
||||
// If no path is set, get the default sketchbook folder for this platform
|
||||
if (sketchbookPath == null) {
|
||||
if (BaseNoGui.getPortableFolder() != null)
|
||||
PreferencesData.set("sketchbook.path", getPortableSketchbookFolder());
|
||||
else
|
||||
showError(_("No sketchbook"), _("Sketchbook path not defined"), null);
|
||||
}
|
||||
|
||||
BaseNoGui.initPackages();
|
||||
|
||||
// Setup board-dependent variables.
|
||||
onBoardOrPortChange();
|
||||
|
||||
CommandlineParser parser = CommandlineParser.newCommandlineParser(args);
|
||||
|
||||
for (String path: parser.getFilenames()) {
|
||||
// Correctly resolve relative paths
|
||||
File file = absoluteFile(path);
|
||||
|
||||
// Fix a problem with systems that use a non-ASCII languages. Paths are
|
||||
// being passed in with 8.3 syntax, which makes the sketch loader code
|
||||
// unhappy, since the sketch folder naming doesn't match up correctly.
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=1089
|
||||
if (OSUtils.isWindows()) {
|
||||
try {
|
||||
file = file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!parser.isVerifyOrUploadMode() && !parser.isGetPrefMode())
|
||||
showError(_("Mode not supported"), _("Only --verify, --upload or --get-pref are supported"), null);
|
||||
|
||||
if (!parser.isForceSavePrefs())
|
||||
PreferencesData.setDoSave(false);
|
||||
if (!file.exists()) {
|
||||
String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path);
|
||||
// Open failure is fatal in upload/verify mode
|
||||
showError(null, mess, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the preferences. For GUI mode, this happens in the quit
|
||||
// handler, but for other modes we should also make sure to save
|
||||
// them.
|
||||
PreferencesData.save();
|
||||
|
||||
if (parser.isVerifyOrUploadMode()) {
|
||||
// Set verbosity for command line build
|
||||
PreferencesData.set("build.verbose", "" + parser.isDoVerboseBuild());
|
||||
PreferencesData.set("upload.verbose", "" + parser.isDoVerboseUpload());
|
||||
|
||||
// Make sure these verbosity preferences are only for the
|
||||
// current session
|
||||
PreferencesData.setDoSave(false);
|
||||
|
||||
if (parser.isUploadMode()) {
|
||||
|
||||
if (parser.getFilenames().size() != 1)
|
||||
{
|
||||
showError(_("Multiple files not supported"), _("The --upload option supports only one file at a time"), null);
|
||||
}
|
||||
|
||||
List<String> warningsAccumulator = new LinkedList<String>();
|
||||
boolean success = false;
|
||||
try {
|
||||
// costruttore di Editor carica lo sketch usando handleOpenInternal() che fa
|
||||
// la new di Sketch che chiama load() nel suo costruttore
|
||||
// In questo punto questo si traduce in:
|
||||
// SketchData data = new SketchData(file);
|
||||
// File tempBuildFolder = getBuildFolder();
|
||||
// data.load();
|
||||
SketchData data = new SketchData(absoluteFile(parser.getFilenames().get(0)));
|
||||
File tempBuildFolder = getBuildFolder();
|
||||
data.load();
|
||||
|
||||
// Sketch.exportApplet()
|
||||
// - chiama Sketch.prepare() che chiama Sketch.ensureExistence()
|
||||
// - chiama Sketch.build(verbose=false) che chiama Sketch.ensureExistence(), imposta il progressListener e chiama Compiler.build()
|
||||
// - chiama Sketch.upload() (cfr. dopo...)
|
||||
if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null);
|
||||
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild());
|
||||
if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null);
|
||||
showMessage(_("Done compiling"), _("Done compiling"));
|
||||
|
||||
// - chiama Sketch.upload() ... to be continued ...
|
||||
Uploader uploader = Compiler.getUploaderByPreferences(parser.isNoUploadPort());
|
||||
if (uploader.requiresAuthorization() && !PreferencesData.has(uploader.getAuthorizationKey())) showError(_("..."), _("..."), null);
|
||||
try {
|
||||
success = Compiler.upload(data, uploader, tempBuildFolder.getAbsolutePath(), suggestedClassName, parser.isDoUseProgrammer(), parser.isNoUploadPort(), warningsAccumulator);
|
||||
showMessage(_("Done uploading"), _("Done uploading"));
|
||||
} finally {
|
||||
if (uploader.requiresAuthorization() && !success) {
|
||||
PreferencesData.remove(uploader.getAuthorizationKey());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
showError(_("Error while verifying/uploading"), _("An error occurred while verifying/uploading the sketch"), e);
|
||||
}
|
||||
for (String warning : warningsAccumulator) {
|
||||
System.out.print(_("Warning"));
|
||||
System.out.print(": ");
|
||||
System.out.println(warning);
|
||||
}
|
||||
if (!success) showError(_("Error while uploading"), _("An error occurred while uploading the sketch"), null);
|
||||
} else {
|
||||
|
||||
for (String path : parser.getFilenames())
|
||||
{
|
||||
try {
|
||||
// costruttore di Editor carica lo sketch usando handleOpenInternal() che fa
|
||||
// la new di Sketch che chiama load() nel suo costruttore
|
||||
// In questo punto questo si traduce in:
|
||||
// SketchData data = new SketchData(file);
|
||||
// File tempBuildFolder = getBuildFolder();
|
||||
// data.load();
|
||||
SketchData data = new SketchData(absoluteFile(path));
|
||||
File tempBuildFolder = getBuildFolder();
|
||||
data.load();
|
||||
|
||||
// metodo Sketch.prepare() chiama Sketch.ensureExistence()
|
||||
// Sketch.build(verbose) chiama Sketch.ensureExistence() e poi imposta il progressListener e, finalmente, chiama Compiler.build()
|
||||
// In questo punto questo si traduce in:
|
||||
// if (!data.getFolder().exists()) showError(...);
|
||||
// String ... = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, verbose);
|
||||
if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null);
|
||||
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild());
|
||||
if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null);
|
||||
showMessage(_("Done compiling"), _("Done compiling"));
|
||||
} catch (Exception e) {
|
||||
showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// No errors exit gracefully
|
||||
System.exit(0);
|
||||
}
|
||||
else if (parser.isGetPrefMode()) {
|
||||
String value = PreferencesData.get(parser.getGetPref(), null);
|
||||
if (value != null) {
|
||||
System.out.println(value);
|
||||
System.exit(0);
|
||||
} else {
|
||||
System.exit(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public void initLogger() {
|
||||
System.setProperty(LogFactoryImpl.LOG_PROPERTY, NoOpLog.class.getCanonicalName());
|
||||
Logger.getLogger("javax.jmdns").setLevel(Level.OFF);
|
||||
}
|
||||
|
||||
static public void initPackages() {
|
||||
packages = new HashMap<String, TargetPackage>();
|
||||
loadHardware(getHardwareFolder());
|
||||
loadHardware(getSketchbookHardwareFolder());
|
||||
if (packages.size() == 0) {
|
||||
System.out.println(_("No valid configured cores found! Exiting..."));
|
||||
System.exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
static protected void initPlatform() {
|
||||
try {
|
||||
Class<?> platformClass = Class.forName("processing.app.Platform");
|
||||
if (OSUtils.isMacOS()) {
|
||||
platformClass = Class.forName("processing.app.macosx.Platform");
|
||||
} else if (OSUtils.isWindows()) {
|
||||
platformClass = Class.forName("processing.app.windows.Platform");
|
||||
} else if (OSUtils.isLinux()) {
|
||||
platformClass = Class.forName("processing.app.linux.Platform");
|
||||
}
|
||||
platform = (Platform) platformClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
showError(_("Problem Setting the Platform"),
|
||||
_("An unknown error occurred while trying to load\n" +
|
||||
"platform-specific code for your machine."), e);
|
||||
}
|
||||
}
|
||||
|
||||
static public void initPortableFolder() {
|
||||
// Portable folder
|
||||
portableFolder = getContentFile("portable");
|
||||
if (!portableFolder.exists())
|
||||
portableFolder = null;
|
||||
}
|
||||
|
||||
static public void initVersion() {
|
||||
try {
|
||||
File versionFile = getContentFile("lib/version.txt");
|
||||
if (versionFile.exists()) {
|
||||
String version = PApplet.loadStrings(versionFile)[0];
|
||||
if (!version.equals(VERSION_NAME) && !version.equals("${version}")) {
|
||||
VERSION_NAME = version;
|
||||
RELEASE = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// help 3rd party installers find the correct hardware path
|
||||
PreferencesData.set("last.ide." + VERSION_NAME + ".hardwarepath", getHardwarePath());
|
||||
PreferencesData.set("last.ide." + VERSION_NAME + ".daterun", "" + (new Date()).getTime() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the name is valid for a Processing sketch.
|
||||
*/
|
||||
static public boolean isSanitaryName(String name) {
|
||||
return sanitizeName(name).equals(name);
|
||||
}
|
||||
|
||||
static protected void loadHardware(File folder) {
|
||||
if (!folder.isDirectory()) return;
|
||||
|
||||
String list[] = folder.list(new OnlyDirs());
|
||||
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null) return;
|
||||
|
||||
// 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);
|
||||
|
||||
for (String target : list) {
|
||||
// Skip reserved 'tools' folder.
|
||||
if (target.equals("tools"))
|
||||
continue;
|
||||
File subfolder = new File(folder, target);
|
||||
|
||||
try {
|
||||
packages.put(target, new TargetPackage(target, subfolder));
|
||||
} catch (TargetPlatformException e) {
|
||||
System.out.println("WARNING: Error loading hardware folder " + target);
|
||||
System.out.println(" " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab the contents of a file as a string.
|
||||
*/
|
||||
static public String loadFile(File file) throws IOException {
|
||||
String[] contents = PApplet.loadStrings(file);
|
||||
if (contents == null) return null;
|
||||
return PApplet.join(contents, "\n");
|
||||
}
|
||||
|
||||
static public void main(String args[]) throws Exception {
|
||||
if (args.length == 0)
|
||||
showError(_("No parameters"), _("No command line parameters found"), null);
|
||||
|
||||
initPlatform();
|
||||
|
||||
initPortableFolder();
|
||||
|
||||
initParameters(args);
|
||||
|
||||
init(args);
|
||||
}
|
||||
|
||||
static public void onBoardOrPortChange() {
|
||||
TargetPlatform targetPlatform = getTargetPlatform();
|
||||
if (targetPlatform == null)
|
||||
return;
|
||||
|
||||
// Calculate paths for libraries and examples
|
||||
examplesFolder = getContentFile("examples");
|
||||
toolsFolder = getContentFile("tools");
|
||||
|
||||
File platformFolder = targetPlatform.getFolder();
|
||||
librariesFolders = new ArrayList<File>();
|
||||
librariesFolders.add(getContentFile("libraries"));
|
||||
String core = getBoardPreferences().get("build.core");
|
||||
if (core.contains(":")) {
|
||||
String referencedCore = core.split(":")[0];
|
||||
TargetPlatform referencedPlatform = getTargetPlatform(referencedCore, targetPlatform.getId());
|
||||
if (referencedPlatform != null) {
|
||||
File referencedPlatformFolder = referencedPlatform.getFolder();
|
||||
librariesFolders.add(new File(referencedPlatformFolder, "libraries"));
|
||||
}
|
||||
}
|
||||
librariesFolders.add(new File(platformFolder, "libraries"));
|
||||
librariesFolders.add(getSketchbookLibrariesFolder());
|
||||
|
||||
// Scan for libraries in each library folder.
|
||||
// Libraries located in the latest folders on the list can override
|
||||
// other libraries with the same name.
|
||||
try {
|
||||
scanAndUpdateLibraries(librariesFolders);
|
||||
} catch (IOException e) {
|
||||
showWarning(_("Error"), _("Error loading libraries"), e);
|
||||
}
|
||||
|
||||
populateImportToLibraryTable();
|
||||
}
|
||||
|
||||
static public void populateImportToLibraryTable() {
|
||||
// Populate importToLibraryTable
|
||||
importToLibraryTable = new HashMap<String, Library>();
|
||||
for (Library lib : getLibraries()) {
|
||||
try {
|
||||
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
|
||||
for (String header : headers) {
|
||||
Library old = importToLibraryTable.get(header);
|
||||
if (old != null) {
|
||||
// If a library was already found with this header, keep
|
||||
// it if the library's name matches the header name.
|
||||
String name = header.substring(0, header.length() - 2);
|
||||
if (old.getFolder().getPath().endsWith(name))
|
||||
continue;
|
||||
}
|
||||
importToLibraryTable.put(header, lib);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
showWarning(_("Error"), I18n
|
||||
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public void initParameters(String args[]) {
|
||||
String preferencesFile = null;
|
||||
|
||||
// Do a first pass over the commandline arguments, the rest of them
|
||||
// will be processed by the Base constructor. Note that this loop
|
||||
// does not look at the last element of args, to prevent crashing
|
||||
// when no parameter was specified to an option. Later, Base() will
|
||||
// then show an error for these.
|
||||
for (int i = 0; i < args.length - 1; i++) {
|
||||
if (args[i].equals("--preferences-file")) {
|
||||
++i;
|
||||
preferencesFile = args[i];
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--curdir")) {
|
||||
i++;
|
||||
currentDirectory = args[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// run static initialization that grabs all the prefs
|
||||
PreferencesData.init(absoluteFile(preferencesFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively remove all files within a directory,
|
||||
* used with removeDir(), or when the contents of a dir
|
||||
* should be removed, but not the directory itself.
|
||||
* (i.e. when cleaning temp files from lib/build)
|
||||
*/
|
||||
static public void removeDescendants(File dir) {
|
||||
if (!dir.exists()) return;
|
||||
|
||||
String files[] = dir.list();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].equals(".") || files[i].equals("..")) continue;
|
||||
File dead = new File(dir, files[i]);
|
||||
if (!dead.isDirectory()) {
|
||||
if (!PreferencesData.getBoolean("compiler.save_build_files")) {
|
||||
if (!dead.delete()) {
|
||||
// temporarily disabled
|
||||
System.err.println(I18n.format(_("Could not delete {0}"), dead));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
removeDir(dead);
|
||||
//dead.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all files in a directory and the directory itself.
|
||||
*/
|
||||
static public void removeDir(File dir) {
|
||||
if (dir.exists()) {
|
||||
removeDescendants(dir);
|
||||
if (!dir.delete()) {
|
||||
System.err.println(I18n.format(_("Could not delete {0}"), dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a sanitized name that fits our standards for likely to work.
|
||||
* <p/>
|
||||
* Java classes have a wider range of names that are technically allowed
|
||||
* (supposedly any Unicode name) than what we support. The reason for
|
||||
* going more narrow is to avoid situations with text encodings and
|
||||
* converting during the process of moving files between operating
|
||||
* systems, i.e. uploading from a Windows machine to a Linux server,
|
||||
* or reading a FAT32 partition in OS X and using a thumb drive.
|
||||
* <p/>
|
||||
* This helper function replaces everything but A-Z, a-z, and 0-9 with
|
||||
* underscores. Also disallows starting the sketch name with a digit.
|
||||
*/
|
||||
static public String sanitizeName(String origName) {
|
||||
char c[] = origName.toCharArray();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
// can't lead with a digit, so start with an underscore
|
||||
if ((c[0] >= '0') && (c[0] <= '9')) {
|
||||
buffer.append('_');
|
||||
}
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if (((c[i] >= '0') && (c[i] <= '9')) ||
|
||||
((c[i] >= 'a') && (c[i] <= 'z')) ||
|
||||
((c[i] >= 'A') && (c[i] <= 'Z')) ||
|
||||
((i > 0) && (c[i] == '-')) ||
|
||||
((i > 0) && (c[i] == '.'))) {
|
||||
buffer.append(c[i]);
|
||||
} else {
|
||||
buffer.append('_');
|
||||
}
|
||||
}
|
||||
// let's not be ridiculous about the length of filenames.
|
||||
// in fact, Mac OS 9 can handle 255 chars, though it can't really
|
||||
// deal with filenames longer than 31 chars in the Finder.
|
||||
// but limiting to that for sketches would mean setting the
|
||||
// upper-bound on the character limit here to 25 characters
|
||||
// (to handle the base name + ".class")
|
||||
if (buffer.length() > 63) {
|
||||
buffer.setLength(63);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spew the contents of a String object out to a file.
|
||||
*/
|
||||
static public void saveFile(String str, File file) throws IOException {
|
||||
File temp = File.createTempFile(file.getName(), null, file.getParentFile());
|
||||
PApplet.saveStrings(temp, new String[] { str });
|
||||
if (file.exists()) {
|
||||
boolean result = file.delete();
|
||||
if (!result) {
|
||||
throw new IOException(
|
||||
I18n.format(
|
||||
_("Could not remove old version of {0}"),
|
||||
file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
boolean result = temp.renameTo(file);
|
||||
if (!result) {
|
||||
throw new IOException(
|
||||
I18n.format(
|
||||
_("Could not replace {0}"),
|
||||
file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
|
||||
static public void scanAndUpdateLibraries(List<File> folders) throws IOException {
|
||||
libraries = scanLibraries(folders);
|
||||
}
|
||||
|
||||
static public LibraryList scanLibraries(List<File> folders) throws IOException {
|
||||
LibraryList res = new LibraryList();
|
||||
for (File folder : folders)
|
||||
res.addOrReplaceAll(scanLibraries(folder));
|
||||
return res;
|
||||
}
|
||||
|
||||
static public LibraryList scanLibraries(File folder) throws IOException {
|
||||
LibraryList res = new LibraryList();
|
||||
|
||||
String list[] = folder.list(new OnlyDirs());
|
||||
// if a bad folder or something like that, this might come back null
|
||||
if (list == null)
|
||||
return res;
|
||||
|
||||
for (String libName : list) {
|
||||
File subfolder = new File(folder, libName);
|
||||
if (!isSanitaryName(libName)) {
|
||||
String mess = I18n.format(_("The library \"{0}\" 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)"),
|
||||
libName);
|
||||
showMessage(_("Ignoring bad library name"), mess);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Library lib = Library.create(subfolder);
|
||||
// (also replace previously found libs with the same name)
|
||||
if (lib != null)
|
||||
res.addOrReplace(lib);
|
||||
} catch (IOException e) {
|
||||
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"),
|
||||
subfolder, e.getMessage()));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static public void selectBoard(TargetBoard targetBoard) {
|
||||
TargetPlatform targetPlatform = targetBoard.getContainerPlatform();
|
||||
TargetPackage targetPackage = targetPlatform.getContainerPackage();
|
||||
|
||||
PreferencesData.set("target_package", targetPackage.getId());
|
||||
PreferencesData.set("target_platform", targetPlatform.getId());
|
||||
PreferencesData.set("board", targetBoard.getId());
|
||||
|
||||
File platformFolder = targetPlatform.getFolder();
|
||||
PreferencesData.set("runtime.platform.path", platformFolder.getAbsolutePath());
|
||||
PreferencesData.set("runtime.hardware.path", platformFolder.getParentFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
public static void selectSerialPort(String port) {
|
||||
PreferencesData.set("serial.port", port);
|
||||
if (port.startsWith("/dev/"))
|
||||
PreferencesData.set("serial.port.file", port.substring(5));
|
||||
else
|
||||
PreferencesData.set("serial.port.file", port);
|
||||
}
|
||||
|
||||
public static void setBuildFolder(File newBuildFolder) {
|
||||
buildFolder = newBuildFolder;
|
||||
}
|
||||
|
||||
static public void showError(String title, String message, int exit_code) {
|
||||
showError(title, message, null, exit_code);
|
||||
}
|
||||
|
||||
static public void showError(String title, String message, Throwable e) {
|
||||
notifier.showError(title, message, e, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an error message that's actually fatal to the program.
|
||||
* This is an error that can't be recovered. Use showWarning()
|
||||
* for errors that allow P5 to continue running.
|
||||
*/
|
||||
static public void showError(String title, String message, Throwable e, int exit_code) {
|
||||
notifier.showError(title, message, e, exit_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* "No cookie for you" type messages. Nothing fatal or all that
|
||||
* much of a bummer, but something to notify the user about.
|
||||
*/
|
||||
static public void showMessage(String title, String message) {
|
||||
notifier.showMessage(title, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-fatal error message with optional stack trace side dish.
|
||||
*/
|
||||
static public void showWarning(String title, String message, Exception e) {
|
||||
notifier.showWarning(title, message, e);
|
||||
}
|
||||
|
||||
}
|
@ -35,7 +35,7 @@ import com.sun.jna.Native;
|
||||
import processing.app.debug.TargetBoard;
|
||||
import processing.app.debug.TargetPackage;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.core.PConstants;
|
||||
import processing.app.legacy.PConstants;
|
||||
|
||||
|
||||
/**
|
||||
@ -54,7 +54,6 @@ import processing.core.PConstants;
|
||||
* know if name is proper Java package syntax.)
|
||||
*/
|
||||
public class Platform {
|
||||
Base base;
|
||||
|
||||
|
||||
/**
|
||||
@ -74,8 +73,7 @@ public class Platform {
|
||||
}
|
||||
|
||||
|
||||
public void init(Base base) {
|
||||
this.base = base;
|
||||
public void init() {
|
||||
}
|
||||
|
||||
|
||||
@ -112,7 +110,7 @@ public class Platform {
|
||||
|
||||
|
||||
public void openURL(String url) throws Exception {
|
||||
String launcher = Preferences.get("launcher");
|
||||
String launcher = PreferencesData.get("launcher");
|
||||
if (launcher != null) {
|
||||
Runtime.getRuntime().exec(new String[] { launcher, url });
|
||||
} else {
|
||||
@ -122,12 +120,12 @@ public class Platform {
|
||||
|
||||
|
||||
public boolean openFolderAvailable() {
|
||||
return Preferences.get("launcher") != null;
|
||||
return PreferencesData.get("launcher") != null;
|
||||
}
|
||||
|
||||
|
||||
public void openFolder(File file) throws Exception {
|
||||
String launcher = Preferences.get("launcher");
|
||||
String launcher = PreferencesData.get("launcher");
|
||||
if (launcher != null) {
|
||||
String folder = file.getAbsolutePath();
|
||||
Runtime.getRuntime().exec(new String[] { launcher, folder });
|
||||
@ -215,8 +213,8 @@ public class Platform {
|
||||
|
||||
|
||||
protected void showLauncherWarning() {
|
||||
Base.showWarning(_("No launcher available"),
|
||||
_("Unspecified platform, no launcher available.\nTo enable opening URLs or folders, add a \n\"launcher=/path/to/app\" line to preferences.txt"),
|
||||
null);
|
||||
BaseNoGui.showWarning(_("No launcher available"),
|
||||
_("Unspecified platform, no launcher available.\nTo enable opening URLs or folders, add a \n\"launcher=/path/to/app\" line to preferences.txt"),
|
||||
null);
|
||||
}
|
||||
}
|
214
arduino-core/src/processing/app/PreferencesData.java
Normal file
214
arduino-core/src/processing/app/PreferencesData.java
Normal file
@ -0,0 +1,214 @@
|
||||
package processing.app;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.legacy.PApplet;
|
||||
import processing.app.legacy.PConstants;
|
||||
|
||||
|
||||
public class PreferencesData {
|
||||
|
||||
static final String PREFS_FILE = "preferences.txt";
|
||||
|
||||
// data model
|
||||
|
||||
static PreferencesMap defaults;
|
||||
static PreferencesMap prefs = new PreferencesMap();
|
||||
static File preferencesFile;
|
||||
static boolean doSave = true;
|
||||
|
||||
|
||||
static public void init(File file) {
|
||||
if (file != null)
|
||||
preferencesFile = file;
|
||||
else
|
||||
preferencesFile = BaseNoGui.getSettingsFile(PREFS_FILE);
|
||||
|
||||
// start by loading the defaults, in case something
|
||||
// important was deleted from the user prefs
|
||||
try {
|
||||
prefs.load(BaseNoGui.getLibStream("preferences.txt"));
|
||||
} catch (IOException e) {
|
||||
BaseNoGui.showError(null, _("Could not read default settings.\n" +
|
||||
"You'll need to reinstall Arduino."), e);
|
||||
}
|
||||
|
||||
// set some runtime constants (not saved on preferences file)
|
||||
File hardwareFolder = BaseNoGui.getHardwareFolder();
|
||||
prefs.put("runtime.ide.path", hardwareFolder.getParentFile().getAbsolutePath());
|
||||
prefs.put("runtime.ide.version", "" + BaseNoGui.REVISION);
|
||||
|
||||
// clone the hash table
|
||||
defaults = new PreferencesMap(prefs);
|
||||
|
||||
if (preferencesFile.exists()) {
|
||||
// load the previous preferences file
|
||||
try {
|
||||
prefs.load(preferencesFile);
|
||||
} catch (IOException ex) {
|
||||
BaseNoGui.showError(_("Error reading preferences"),
|
||||
I18n.format(_("Error reading the preferences file. "
|
||||
+ "Please delete (or move)\n"
|
||||
+ "{0} and restart Arduino."),
|
||||
preferencesFile.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
// load the I18n module for internationalization
|
||||
try {
|
||||
I18n.init(get("editor.languages.current"));
|
||||
} catch (MissingResourceException e) {
|
||||
I18n.init("en");
|
||||
set("editor.languages.current", "en");
|
||||
}
|
||||
|
||||
// set some other runtime constants (not saved on preferences file)
|
||||
set("runtime.os", PConstants.platformNames[PApplet.platform]);
|
||||
|
||||
fixPreferences();
|
||||
}
|
||||
|
||||
private static void fixPreferences() {
|
||||
String baud = get("serial.debug_rate");
|
||||
if ("14400".equals(baud) || "28800".equals(baud) || "38400".equals(baud)) {
|
||||
set("serial.debug_rate", "9600");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public String[] loadStrings(InputStream input) {
|
||||
try {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||
|
||||
String lines[] = new String[100];
|
||||
int lineCount = 0;
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (lineCount == lines.length) {
|
||||
String temp[] = new String[lineCount << 1];
|
||||
System.arraycopy(lines, 0, temp, 0, lineCount);
|
||||
lines = temp;
|
||||
}
|
||||
lines[lineCount++] = line;
|
||||
}
|
||||
reader.close();
|
||||
|
||||
if (lineCount == lines.length) {
|
||||
return lines;
|
||||
}
|
||||
|
||||
// resize array to appropriate amount for these lines
|
||||
String output[] = new String[lineCount];
|
||||
System.arraycopy(lines, 0, output, 0, lineCount);
|
||||
return output;
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
//throw new RuntimeException("Error inside loadStrings()");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static protected void save() {
|
||||
if (!doSave)
|
||||
return;
|
||||
|
||||
// on startup, don't worry about it
|
||||
// this is trying to update the prefs for who is open
|
||||
// before Preferences.init() has been called.
|
||||
if (preferencesFile == null) return;
|
||||
|
||||
// Fix for 0163 to properly use Unicode when writing preferences.txt
|
||||
PrintWriter writer = PApplet.createWriter(preferencesFile);
|
||||
|
||||
String[] keys = prefs.keySet().toArray(new String[0]);
|
||||
Arrays.sort(keys);
|
||||
for (String key: keys) {
|
||||
if (key.startsWith("runtime."))
|
||||
continue;
|
||||
writer.println(key + "=" + prefs.get(key));
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
|
||||
// .................................................................
|
||||
|
||||
static public String get(String attribute) {
|
||||
return prefs.get(attribute);
|
||||
}
|
||||
|
||||
static public String get(String attribute, String defaultValue) {
|
||||
String value = get(attribute);
|
||||
return (value == null) ? defaultValue : value;
|
||||
}
|
||||
|
||||
public static boolean has(String key) {
|
||||
return prefs.containsKey(key);
|
||||
}
|
||||
|
||||
public static void remove(String key) {
|
||||
prefs.remove(key);
|
||||
}
|
||||
|
||||
static public String getDefault(String attribute) {
|
||||
return defaults.get(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void set(String attribute, String value) {
|
||||
prefs.put(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public void unset(String attribute) {
|
||||
prefs.remove(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public boolean getBoolean(String attribute) {
|
||||
return prefs.getBoolean(attribute);
|
||||
}
|
||||
|
||||
|
||||
static public void setBoolean(String attribute, boolean value) {
|
||||
prefs.putBoolean(attribute, value);
|
||||
}
|
||||
|
||||
|
||||
static public int getInteger(String attribute) {
|
||||
return Integer.parseInt(get(attribute));
|
||||
}
|
||||
|
||||
|
||||
static public void setInteger(String key, int value) {
|
||||
set(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
// get a copy of the Preferences
|
||||
static public PreferencesMap getMap()
|
||||
{
|
||||
return new PreferencesMap(prefs);
|
||||
}
|
||||
|
||||
// Decide wether changed preferences will be saved. When value is
|
||||
// false, Preferences.save becomes a no-op.
|
||||
static public void setDoSave(boolean value)
|
||||
{
|
||||
doSave = value;
|
||||
}
|
||||
}
|
@ -63,40 +63,40 @@ public class Serial implements SerialPortEventListener {
|
||||
MessageConsumer consumer;
|
||||
|
||||
public Serial(boolean monitor) throws SerialException {
|
||||
this(Preferences.get("serial.port"),
|
||||
Preferences.getInteger("serial.debug_rate"),
|
||||
Preferences.get("serial.parity").charAt(0),
|
||||
Preferences.getInteger("serial.databits"),
|
||||
new Float(Preferences.get("serial.stopbits")).floatValue());
|
||||
this(PreferencesData.get("serial.port"),
|
||||
PreferencesData.getInteger("serial.debug_rate"),
|
||||
PreferencesData.get("serial.parity").charAt(0),
|
||||
PreferencesData.getInteger("serial.databits"),
|
||||
new Float(PreferencesData.get("serial.stopbits")).floatValue());
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
public Serial() throws SerialException {
|
||||
this(Preferences.get("serial.port"),
|
||||
Preferences.getInteger("serial.debug_rate"),
|
||||
Preferences.get("serial.parity").charAt(0),
|
||||
Preferences.getInteger("serial.databits"),
|
||||
new Float(Preferences.get("serial.stopbits")).floatValue());
|
||||
this(PreferencesData.get("serial.port"),
|
||||
PreferencesData.getInteger("serial.debug_rate"),
|
||||
PreferencesData.get("serial.parity").charAt(0),
|
||||
PreferencesData.getInteger("serial.databits"),
|
||||
new Float(PreferencesData.get("serial.stopbits")).floatValue());
|
||||
}
|
||||
|
||||
public Serial(int irate) throws SerialException {
|
||||
this(Preferences.get("serial.port"), irate,
|
||||
Preferences.get("serial.parity").charAt(0),
|
||||
Preferences.getInteger("serial.databits"),
|
||||
new Float(Preferences.get("serial.stopbits")).floatValue());
|
||||
this(PreferencesData.get("serial.port"), irate,
|
||||
PreferencesData.get("serial.parity").charAt(0),
|
||||
PreferencesData.getInteger("serial.databits"),
|
||||
new Float(PreferencesData.get("serial.stopbits")).floatValue());
|
||||
}
|
||||
|
||||
public Serial(String iname, int irate) throws SerialException {
|
||||
this(iname, irate, Preferences.get("serial.parity").charAt(0),
|
||||
Preferences.getInteger("serial.databits"),
|
||||
new Float(Preferences.get("serial.stopbits")).floatValue());
|
||||
this(iname, irate, PreferencesData.get("serial.parity").charAt(0),
|
||||
PreferencesData.getInteger("serial.databits"),
|
||||
new Float(PreferencesData.get("serial.stopbits")).floatValue());
|
||||
}
|
||||
|
||||
public Serial(String iname) throws SerialException {
|
||||
this(iname, Preferences.getInteger("serial.debug_rate"),
|
||||
Preferences.get("serial.parity").charAt(0),
|
||||
Preferences.getInteger("serial.databits"),
|
||||
new Float(Preferences.get("serial.stopbits")).floatValue());
|
||||
this(iname, PreferencesData.getInteger("serial.debug_rate"),
|
||||
PreferencesData.get("serial.parity").charAt(0),
|
||||
PreferencesData.getInteger("serial.databits"),
|
||||
new Float(PreferencesData.get("serial.stopbits")).floatValue());
|
||||
}
|
||||
|
||||
public static boolean touchPort(String iname, int irate) throws SerialException {
|
@ -22,6 +22,7 @@ package processing.app;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class SerialException extends IOException {
|
||||
public SerialException() {
|
||||
super();
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
@ -20,6 +18,7 @@
|
||||
|
||||
package processing.app;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class SerialNotFoundException extends SerialException {
|
||||
public SerialNotFoundException() {
|
||||
super();
|
@ -1,5 +1,3 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
SketchCode - data class for a single file inside a sketch
|
||||
Part of the Processing project - http://processing.org
|
||||
@ -25,54 +23,44 @@
|
||||
package processing.app;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import javax.swing.text.Document;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import processing.app.helpers.FileUtils;
|
||||
|
||||
/**
|
||||
* Represents a single tab of a sketch.
|
||||
*/
|
||||
public class SketchCode {
|
||||
|
||||
/** Pretty name (no extension), not the full file name */
|
||||
private String prettyName;
|
||||
|
||||
/** File object for where this code is located */
|
||||
private File file;
|
||||
|
||||
/** Extension for this file (no dots, and in lowercase). */
|
||||
private String extension;
|
||||
|
||||
/** Text of the program text for this tab */
|
||||
private String program;
|
||||
|
||||
/** Document object for this tab. Currently this is a SyntaxDocument. */
|
||||
private Document document;
|
||||
|
||||
/**
|
||||
* Undo Manager for this tab, each tab keeps track of their own
|
||||
* Editor.undo will be set to this object when this code is the tab
|
||||
* that's currently the front.
|
||||
*/
|
||||
private LastUndoableEditAwareUndoManager undo = new LastUndoableEditAwareUndoManager();
|
||||
|
||||
// saved positions from last time this tab was used
|
||||
private int selectionStart;
|
||||
private int selectionStop;
|
||||
private int scrollPosition;
|
||||
|
||||
private boolean modified;
|
||||
|
||||
/** name of .java file after preproc */
|
||||
// private String preprocName;
|
||||
/** where this code starts relative to the concat'd code */
|
||||
private int preprocOffset;
|
||||
|
||||
private Object metadata;
|
||||
|
||||
public SketchCode(File file, String extension) {
|
||||
public SketchCode(File file) {
|
||||
init(file, null);
|
||||
}
|
||||
|
||||
public SketchCode(File file, Object metadata) {
|
||||
init(file, metadata);
|
||||
}
|
||||
|
||||
private void init(File file, Object metadata) {
|
||||
this.file = file;
|
||||
this.extension = extension;
|
||||
this.metadata = metadata;
|
||||
|
||||
makePrettyName();
|
||||
|
||||
@ -125,11 +113,10 @@ public class SketchCode {
|
||||
}
|
||||
|
||||
|
||||
protected boolean renameTo(File what, String ext) {
|
||||
protected boolean renameTo(File what) {
|
||||
boolean success = file.renameTo(what);
|
||||
if (success) {
|
||||
file = what;
|
||||
extension = ext;
|
||||
makePrettyName();
|
||||
}
|
||||
return success;
|
||||
@ -137,7 +124,7 @@ public class SketchCode {
|
||||
|
||||
|
||||
protected void copyTo(File dest) throws IOException {
|
||||
Base.saveFile(program, dest);
|
||||
BaseNoGui.saveFile(program, dest);
|
||||
}
|
||||
|
||||
|
||||
@ -151,13 +138,12 @@ public class SketchCode {
|
||||
}
|
||||
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
public boolean isExtension(String... extensions) {
|
||||
return isExtension(Arrays.asList(extensions));
|
||||
}
|
||||
|
||||
|
||||
public boolean isExtension(String what) {
|
||||
return extension.equals(what);
|
||||
|
||||
public boolean isExtension(List<String> extensions) {
|
||||
return FileUtils.hasExtension(file, extensions);
|
||||
}
|
||||
|
||||
|
||||
@ -172,7 +158,7 @@ public class SketchCode {
|
||||
|
||||
|
||||
public int getLineCount() {
|
||||
return Base.countLines(program);
|
||||
return BaseNoGui.countLines(program);
|
||||
}
|
||||
|
||||
|
||||
@ -186,16 +172,6 @@ public class SketchCode {
|
||||
}
|
||||
|
||||
|
||||
// public void setPreprocName(String preprocName) {
|
||||
// this.preprocName = preprocName;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public String getPreprocName() {
|
||||
// return preprocName;
|
||||
// }
|
||||
|
||||
|
||||
public void setPreprocOffset(int preprocOffset) {
|
||||
this.preprocOffset = preprocOffset;
|
||||
}
|
||||
@ -211,51 +187,6 @@ public class SketchCode {
|
||||
}
|
||||
|
||||
|
||||
public Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
|
||||
public void setDocument(Document d) {
|
||||
document = d;
|
||||
}
|
||||
|
||||
|
||||
public LastUndoableEditAwareUndoManager getUndo() {
|
||||
return undo;
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// TODO these could probably be handled better, since it's a general state
|
||||
// issue that's read/write from only one location in Editor (on tab switch.)
|
||||
|
||||
|
||||
public int getSelectionStart() {
|
||||
return selectionStart;
|
||||
}
|
||||
|
||||
|
||||
public int getSelectionStop() {
|
||||
return selectionStop;
|
||||
}
|
||||
|
||||
|
||||
public int getScrollPosition() {
|
||||
return scrollPosition;
|
||||
}
|
||||
|
||||
|
||||
protected void setState(String p, int start, int stop, int pos) {
|
||||
program = p;
|
||||
selectionStart = start;
|
||||
selectionStop = stop;
|
||||
scrollPosition = pos;
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@ -263,7 +194,7 @@ public class SketchCode {
|
||||
* Load this piece of code from a file.
|
||||
*/
|
||||
public void load() throws IOException {
|
||||
program = Base.loadFile(file);
|
||||
program = BaseNoGui.loadFile(file);
|
||||
|
||||
if (program.indexOf('\uFFFD') != -1) {
|
||||
System.err.println(
|
||||
@ -291,7 +222,7 @@ public class SketchCode {
|
||||
// TODO re-enable history
|
||||
//history.record(s, SketchHistory.SAVE);
|
||||
|
||||
Base.saveFile(program, file);
|
||||
BaseNoGui.saveFile(program, file);
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
@ -300,6 +231,16 @@ public class SketchCode {
|
||||
* Save this file to another location, used by Sketch.saveAs()
|
||||
*/
|
||||
public void saveAs(File newFile) throws IOException {
|
||||
Base.saveFile(program, newFile);
|
||||
BaseNoGui.saveFile(program, newFile);
|
||||
}
|
||||
|
||||
|
||||
public Object getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
||||
public void setMetadata(Object metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
266
arduino-core/src/processing/app/SketchData.java
Normal file
266
arduino-core/src/processing/app/SketchData.java
Normal file
@ -0,0 +1,266 @@
|
||||
package processing.app;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class SketchData {
|
||||
|
||||
/** main pde file for this sketch. */
|
||||
private File primaryFile;
|
||||
|
||||
/** folder that contains this sketch */
|
||||
private File folder;
|
||||
|
||||
/** data folder location for this sketch (may not exist yet) */
|
||||
private File dataFolder;
|
||||
|
||||
/** code folder location for this sketch (may not exist yet) */
|
||||
private File codeFolder;
|
||||
|
||||
/**
|
||||
* Name of sketch, which is the name of main file (without .pde or .java
|
||||
* extension)
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private List<SketchCode> codes = new ArrayList<SketchCode>();
|
||||
|
||||
private static final Comparator<SketchCode> CODE_DOCS_COMPARATOR = new Comparator<SketchCode>() {
|
||||
@Override
|
||||
public int compare(SketchCode x, SketchCode y) {
|
||||
return x.getFileName().compareTo(y.getFileName());
|
||||
}
|
||||
};
|
||||
|
||||
SketchData(File file) {
|
||||
primaryFile = file;
|
||||
|
||||
// get the name of the sketch by chopping .pde or .java
|
||||
// off of the main file name
|
||||
String mainFilename = primaryFile.getName();
|
||||
int suffixLength = getDefaultExtension().length() + 1;
|
||||
name = mainFilename.substring(0, mainFilename.length() - suffixLength);
|
||||
|
||||
folder = new File(file.getParent());
|
||||
//System.out.println("sketch dir is " + folder);
|
||||
}
|
||||
|
||||
static public File checkSketchFile(File file) {
|
||||
// check to make sure that this .pde file is
|
||||
// in a folder of the same name
|
||||
String fileName = file.getName();
|
||||
File parent = file.getParentFile();
|
||||
String parentName = parent.getName();
|
||||
String pdeName = parentName + ".pde";
|
||||
File altPdeFile = new File(parent, pdeName);
|
||||
String inoName = parentName + ".ino";
|
||||
File altInoFile = new File(parent, inoName);
|
||||
|
||||
if (pdeName.equals(fileName) || inoName.equals(fileName))
|
||||
return file;
|
||||
|
||||
if (altPdeFile.exists())
|
||||
return altPdeFile;
|
||||
|
||||
if (altInoFile.exists())
|
||||
return altInoFile;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the list of files.
|
||||
* <P>
|
||||
* Generally this is only done once, rather than
|
||||
* each time a change is made, because otherwise it gets to be
|
||||
* a nightmare to keep track of what files went where, because
|
||||
* not all the data will be saved to disk.
|
||||
* <P>
|
||||
* This also gets called when the main sketch file is renamed,
|
||||
* because the sketch has to be reloaded from a different folder.
|
||||
* <P>
|
||||
* Another exception is when an external editor is in use,
|
||||
* in which case the load happens each time "run" is hit.
|
||||
*/
|
||||
protected void load() throws IOException {
|
||||
codeFolder = new File(folder, "code");
|
||||
dataFolder = new File(folder, "data");
|
||||
|
||||
// get list of files in the sketch folder
|
||||
String list[] = folder.list();
|
||||
|
||||
// reset these because load() may be called after an
|
||||
// external editor event. (fix for 0099)
|
||||
// codeDocs = new SketchCodeDoc[list.length];
|
||||
clearCodeDocs();
|
||||
// data.setCodeDocs(codeDocs);
|
||||
|
||||
List<String> extensions = getExtensions();
|
||||
|
||||
for (String filename : list) {
|
||||
// Ignoring the dot prefix files is especially important to avoid files
|
||||
// with the ._ prefix on Mac OS X. (You'll see this with Mac files on
|
||||
// non-HFS drives, i.e. a thumb drive formatted FAT32.)
|
||||
if (filename.startsWith(".")) continue;
|
||||
|
||||
// Don't let some wacko name a directory blah.pde or bling.java.
|
||||
if (new File(folder, filename).isDirectory()) continue;
|
||||
|
||||
// figure out the name without any extension
|
||||
String base = filename;
|
||||
// now strip off the .pde and .java extensions
|
||||
for (String extension : extensions) {
|
||||
if (base.toLowerCase().endsWith("." + extension)) {
|
||||
base = base.substring(0, base.length() - (extension.length() + 1));
|
||||
|
||||
// Don't allow people to use files with invalid names, since on load,
|
||||
// it would be otherwise possible to sneak in nasty filenames. [0116]
|
||||
if (BaseNoGui.isSanitaryName(base)) {
|
||||
addCode(new SketchCode(new File(folder, filename)));
|
||||
} else {
|
||||
System.err.println(I18n.format("File name {0} is invalid: ignored", filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getCodeCount() == 0)
|
||||
throw new IOException(_("No valid code files found"));
|
||||
|
||||
// move the main class to the first tab
|
||||
// start at 1, if it's at zero, don't bother
|
||||
for (SketchCode code : getCodes()) {
|
||||
//if (code[i].file.getName().equals(mainFilename)) {
|
||||
if (code.getFile().equals(primaryFile)) {
|
||||
moveCodeToFront(code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sort the entries at the top
|
||||
sortCode();
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
for (SketchCode code : getCodes()) {
|
||||
if (code.isModified())
|
||||
code.save();
|
||||
}
|
||||
}
|
||||
|
||||
public int getCodeCount() {
|
||||
return codes.size();
|
||||
}
|
||||
|
||||
public SketchCode[] getCodes() {
|
||||
return codes.toArray(new SketchCode[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default extension for this editor setup.
|
||||
*/
|
||||
public String getDefaultExtension() {
|
||||
return "ino";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String[] array of proper extensions.
|
||||
*/
|
||||
public List<String> getExtensions() {
|
||||
return Arrays.asList("ino", "pde", "c", "cpp", "h");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file object for the primary .pde of this sketch.
|
||||
*/
|
||||
public File getPrimaryFile() {
|
||||
return primaryFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path to the main .pde file for this sketch.
|
||||
*/
|
||||
public String getMainFilePath() {
|
||||
return primaryFile.getAbsolutePath();
|
||||
//return code[0].file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public void addCode(SketchCode sketchCode) {
|
||||
codes.add(sketchCode);
|
||||
}
|
||||
|
||||
public void moveCodeToFront(SketchCode codeDoc) {
|
||||
codes.remove(codeDoc);
|
||||
codes.add(0, codeDoc);
|
||||
}
|
||||
|
||||
protected void replaceCode(SketchCode newCode) {
|
||||
for (SketchCode code : codes) {
|
||||
if (code.getFileName().equals(newCode.getFileName())) {
|
||||
codes.set(codes.indexOf(code), newCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void sortCode() {
|
||||
if (codes.size() < 2)
|
||||
return;
|
||||
SketchCode first = codes.remove(0);
|
||||
Collections.sort(codes, CODE_DOCS_COMPARATOR);
|
||||
codes.add(0, first);
|
||||
}
|
||||
|
||||
public SketchCode getCode(int i) {
|
||||
return codes.get(i);
|
||||
}
|
||||
|
||||
protected void removeCode(SketchCode which) {
|
||||
for (SketchCode code : codes) {
|
||||
if (code == which) {
|
||||
codes.remove(code);
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.err.println("removeCode: internal error.. could not find code");
|
||||
}
|
||||
|
||||
public int indexOfCode(SketchCode who) {
|
||||
for (SketchCode code : codes) {
|
||||
if (code == who)
|
||||
return codes.indexOf(code);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void clearCodeDocs() {
|
||||
codes.clear();
|
||||
}
|
||||
|
||||
public File getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
public File getDataFolder() {
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
public File getCodeFolder() {
|
||||
return codeFolder;
|
||||
}
|
||||
}
|
@ -27,69 +27,336 @@ import static processing.app.I18n._;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import processing.app.Base;
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Uploader;
|
||||
import cc.arduino.packages.UploaderFactory;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.Sketch;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.SketchCode;
|
||||
import processing.app.SketchData;
|
||||
import processing.app.helpers.FileUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.ProcessUtils;
|
||||
import processing.app.helpers.StringReplacer;
|
||||
import processing.app.helpers.filefilters.OnlyDirs;
|
||||
import processing.app.packages.Library;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.packages.LibraryList;
|
||||
import processing.app.preproc.PdePreprocessor;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
public class Compiler implements MessageConsumer {
|
||||
|
||||
private Sketch sketch;
|
||||
/**
|
||||
* File inside the build directory that contains the build options
|
||||
* used for the last build.
|
||||
*/
|
||||
static final public String BUILD_PREFS_FILE = "buildprefs.txt";
|
||||
|
||||
private SketchData sketch;
|
||||
private PreferencesMap prefs;
|
||||
private boolean verbose;
|
||||
|
||||
private List<File> objectFiles;
|
||||
|
||||
private PreferencesMap prefs;
|
||||
private boolean verbose;
|
||||
private boolean sketchIsCompiled;
|
||||
private String targetArch;
|
||||
|
||||
private RunnerException exception;
|
||||
|
||||
/**
|
||||
* Listener interface for progress update on the GUI
|
||||
*/
|
||||
public interface ProgressListener {
|
||||
public void progress(int percent);
|
||||
}
|
||||
|
||||
private ProgressListener progressListener;
|
||||
|
||||
static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose) throws RunnerException {
|
||||
if (SketchData.checkSketchFile(data.getPrimaryFile()) == null)
|
||||
BaseNoGui.showError(_("Bad file selected"),
|
||||
_("Bad sketch primary file or bad sketck directory structure"), null);
|
||||
|
||||
String primaryClassName = data.getName() + ".cpp";
|
||||
Compiler compiler = new Compiler(data, buildPath, primaryClassName);
|
||||
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
|
||||
String newBuildPrefs = compiler.buildPrefsString();
|
||||
|
||||
// Do a forced cleanup (throw everything away) if the previous
|
||||
// build settings do not match the previous ones
|
||||
boolean prefsChanged = compiler.buildPreferencesChanged(buildPrefsFile, newBuildPrefs);
|
||||
compiler.cleanup(prefsChanged, tempBuildFolder);
|
||||
|
||||
if (prefsChanged) {
|
||||
try {
|
||||
PrintWriter out = new PrintWriter(buildPrefsFile);
|
||||
out.print(newBuildPrefs);
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println(_("Could not write build preferences file"));
|
||||
}
|
||||
}
|
||||
|
||||
compiler.setProgressListener(progListener);
|
||||
|
||||
// compile the program. errors will happen as a RunnerException
|
||||
// that will bubble up to whomever called build().
|
||||
if (compiler.compile(verbose)) {
|
||||
compiler.size(compiler.getBuildPreferences());
|
||||
return primaryClassName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public Uploader getUploaderByPreferences(boolean noUploadPort) {
|
||||
TargetPlatform target = BaseNoGui.getTargetPlatform();
|
||||
String board = PreferencesData.get("board");
|
||||
|
||||
if (noUploadPort)
|
||||
{
|
||||
return new UploaderFactory().newUploader(target.getBoards().get(board), null, noUploadPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
BoardPort boardPort = BaseNoGui.getDiscoveryManager().find(PreferencesData.get("serial.port"));
|
||||
return new UploaderFactory().newUploader(target.getBoards().get(board), boardPort, noUploadPort);
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean upload(SketchData data, Uploader uploader, String buildPath, String suggestedClassName, boolean usingProgrammer, boolean noUploadPort, List<String> warningsAccumulator) throws Exception {
|
||||
|
||||
if (uploader == null)
|
||||
uploader = getUploaderByPreferences(noUploadPort);
|
||||
|
||||
boolean success = false;
|
||||
|
||||
if (uploader.requiresAuthorization() && !PreferencesData.has(uploader.getAuthorizationKey())) {
|
||||
BaseNoGui.showError(_("Authorization required"),
|
||||
_("No athorization data found"), null);
|
||||
}
|
||||
|
||||
boolean useNewWarningsAccumulator = false;
|
||||
if (warningsAccumulator == null) {
|
||||
warningsAccumulator = new LinkedList<String>();
|
||||
useNewWarningsAccumulator = true;
|
||||
}
|
||||
|
||||
try {
|
||||
success = uploader.uploadUsingPreferences(data.getFolder(), buildPath, suggestedClassName, usingProgrammer, warningsAccumulator);
|
||||
} finally {
|
||||
if (uploader.requiresAuthorization() && !success) {
|
||||
PreferencesData.remove(uploader.getAuthorizationKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (useNewWarningsAccumulator) {
|
||||
for (String warning : warningsAccumulator) {
|
||||
System.out.print(_("Warning"));
|
||||
System.out.print(": ");
|
||||
System.out.println(warning);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Compiler
|
||||
* @param _sketch Sketch object to be compiled.
|
||||
* @param _buildPath Where the temporary files live and will be built from.
|
||||
* @param _primaryClassName the name of the combined sketch file w/ extension
|
||||
*/
|
||||
public Compiler(Sketch _sketch, String _buildPath, String _primaryClassName)
|
||||
public Compiler(SketchData _sketch, String _buildPath, String _primaryClassName)
|
||||
throws RunnerException {
|
||||
sketch = _sketch;
|
||||
prefs = createBuildPreferences(_buildPath, _primaryClassName);
|
||||
|
||||
// Start with an empty progress listener
|
||||
progressListener = new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int percent) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the build preferences used on the previous build in
|
||||
* buildPath match the ones given.
|
||||
*/
|
||||
protected boolean buildPreferencesChanged(File buildPrefsFile, String newBuildPrefs) {
|
||||
// No previous build, so no match
|
||||
if (!buildPrefsFile.exists())
|
||||
return true;
|
||||
|
||||
String previousPrefs;
|
||||
try {
|
||||
previousPrefs = FileUtils.readFileToString(buildPrefsFile);
|
||||
} catch (IOException e) {
|
||||
System.err.println(_("Could not read prevous build preferences file, rebuilding all"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!previousPrefs.equals(newBuildPrefs)) {
|
||||
System.out.println(_("Build options changed, rebuilding all"));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the build preferences of the given compiler as a string.
|
||||
* Only includes build-specific preferences, to make sure unrelated
|
||||
* preferences don't cause a rebuild (in particular preferences that
|
||||
* change on every start, like last.ide.xxx.daterun). */
|
||||
protected String buildPrefsString() {
|
||||
PreferencesMap buildPrefs = getBuildPreferences();
|
||||
String res = "";
|
||||
SortedSet<String> treeSet = new TreeSet<String>(buildPrefs.keySet());
|
||||
for (String k : treeSet) {
|
||||
if (k.startsWith("build.") || k.startsWith("compiler.") || k.startsWith("recipes."))
|
||||
res += k + " = " + buildPrefs.get(k) + "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected void setProgressListener(ProgressListener _progressListener) {
|
||||
progressListener = (_progressListener == null ?
|
||||
new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int percent) {
|
||||
}
|
||||
} : _progressListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup temporary files used during a build/run.
|
||||
*/
|
||||
protected void cleanup(boolean force, File tempBuildFolder) {
|
||||
// if the java runtime is holding onto any files in the build dir, we
|
||||
// won't be able to delete them, so we need to force a gc here
|
||||
System.gc();
|
||||
|
||||
if (force) {
|
||||
// delete the entire directory and all contents
|
||||
// when we know something changed and all objects
|
||||
// need to be recompiled, or if the board does not
|
||||
// use setting build.dependency
|
||||
//Base.removeDir(tempBuildFolder);
|
||||
|
||||
// note that we can't remove the builddir itself, otherwise
|
||||
// the next time we start up, internal runs using Runner won't
|
||||
// work because the build dir won't exist at startup, so the classloader
|
||||
// will ignore the fact that that dir is in the CLASSPATH in run.sh
|
||||
BaseNoGui.removeDescendants(tempBuildFolder);
|
||||
} else {
|
||||
// delete only stale source files, from the previously
|
||||
// compiled sketch. This allows multiple windows to be
|
||||
// used. Keep everything else, which might be reusable
|
||||
if (tempBuildFolder.exists()) {
|
||||
String files[] = tempBuildFolder.list();
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".s")) {
|
||||
File deleteMe = new File(tempBuildFolder, file);
|
||||
if (!deleteMe.delete()) {
|
||||
System.err.println("Could not delete " + deleteMe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a fresh applet folder (needed before preproc is run below)
|
||||
//tempBuildFolder.mkdirs();
|
||||
}
|
||||
|
||||
protected void size(PreferencesMap prefs) throws RunnerException {
|
||||
String maxTextSizeString = prefs.get("upload.maximum_size");
|
||||
String maxDataSizeString = prefs.get("upload.maximum_data_size");
|
||||
if (maxTextSizeString == null)
|
||||
return;
|
||||
long maxTextSize = Integer.parseInt(maxTextSizeString);
|
||||
long maxDataSize = -1;
|
||||
if (maxDataSizeString != null)
|
||||
maxDataSize = Integer.parseInt(maxDataSizeString);
|
||||
Sizer sizer = new Sizer(prefs);
|
||||
long[] sizes;
|
||||
try {
|
||||
sizes = sizer.computeSize();
|
||||
} catch (RunnerException e) {
|
||||
System.err.println(I18n.format(_("Couldn't determine program size: {0}"),
|
||||
e.getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
long textSize = sizes[0];
|
||||
long dataSize = sizes[1];
|
||||
System.out.println();
|
||||
System.out.println(I18n
|
||||
.format(_("Sketch uses {0} bytes ({2}%%) of program storage space. Maximum is {1} bytes."),
|
||||
textSize, maxTextSize, textSize * 100 / maxTextSize));
|
||||
if (dataSize >= 0) {
|
||||
if (maxDataSize > 0) {
|
||||
System.out
|
||||
.println(I18n
|
||||
.format(
|
||||
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
|
||||
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
|
||||
maxDataSize - dataSize));
|
||||
} else {
|
||||
System.out.println(I18n
|
||||
.format(_("Global variables use {0} bytes of dynamic memory."), dataSize));
|
||||
}
|
||||
}
|
||||
|
||||
if (textSize > maxTextSize)
|
||||
throw new RunnerException(
|
||||
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
|
||||
|
||||
if (maxDataSize > 0 && dataSize > maxDataSize)
|
||||
throw new RunnerException(
|
||||
_("Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint."));
|
||||
|
||||
int warnDataPercentage = Integer.parseInt(prefs.get("build.warn_data_percentage"));
|
||||
if (maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100)
|
||||
System.err.println(_("Low memory available, stability problems may occur."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile sketch.
|
||||
* @param buildPath
|
||||
*
|
||||
* @return true if successful.
|
||||
* @throws RunnerException Only if there's a problem. Only then.
|
||||
*/
|
||||
public boolean compile(boolean _verbose) throws RunnerException {
|
||||
verbose = _verbose || Preferences.getBoolean("build.verbose");
|
||||
preprocess(prefs.get("build.path"));
|
||||
|
||||
verbose = _verbose || PreferencesData.getBoolean("build.verbose");
|
||||
sketchIsCompiled = false;
|
||||
objectFiles = new ArrayList<File>();
|
||||
|
||||
// 0. include paths for core + all libraries
|
||||
sketch.setCompilingProgress(20);
|
||||
progressListener.progress(20);
|
||||
List<File> includeFolders = new ArrayList<File>();
|
||||
includeFolders.add(prefs.getFile("build.core.path"));
|
||||
if (prefs.getFile("build.variant.path") != null)
|
||||
includeFolders.add(prefs.getFile("build.variant.path"));
|
||||
for (Library lib : sketch.getImportedLibraries()) {
|
||||
for (Library lib : importedLibraries) {
|
||||
if (verbose)
|
||||
System.out.println(I18n
|
||||
.format(_("Using library {0} in folder: {1} {2}"), lib.getName(),
|
||||
@ -100,12 +367,12 @@ public class Compiler implements MessageConsumer {
|
||||
System.out.println();
|
||||
|
||||
List<String> archs = new ArrayList<String>();
|
||||
archs.add(Base.getTargetPlatform().getId());
|
||||
archs.add(BaseNoGui.getTargetPlatform().getId());
|
||||
if (prefs.containsKey("architecture.override_check")) {
|
||||
String[] overrides = prefs.get("architecture.override_check").split(",");
|
||||
archs.addAll(Arrays.asList(overrides));
|
||||
}
|
||||
for (Library lib : sketch.getImportedLibraries()) {
|
||||
for (Library lib : importedLibraries) {
|
||||
if (!lib.supportsArchitecture(archs)) {
|
||||
System.err.println(I18n
|
||||
.format(_("WARNING: library {0} claims to run on {1} "
|
||||
@ -117,33 +384,33 @@ public class Compiler implements MessageConsumer {
|
||||
}
|
||||
|
||||
// 1. compile the sketch (already in the buildPath)
|
||||
sketch.setCompilingProgress(30);
|
||||
progressListener.progress(30);
|
||||
compileSketch(includeFolders);
|
||||
sketchIsCompiled = true;
|
||||
|
||||
// 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
|
||||
// Doesn't really use configPreferences
|
||||
sketch.setCompilingProgress(40);
|
||||
progressListener.progress(40);
|
||||
compileLibraries(includeFolders);
|
||||
|
||||
// 3. compile the core, outputting .o files to <buildPath> and then
|
||||
// collecting them into the core.a library file.
|
||||
sketch.setCompilingProgress(50);
|
||||
progressListener.progress(50);
|
||||
compileCore();
|
||||
|
||||
// 4. link it all together into the .elf file
|
||||
sketch.setCompilingProgress(60);
|
||||
progressListener.progress(60);
|
||||
compileLink();
|
||||
|
||||
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
||||
sketch.setCompilingProgress(70);
|
||||
progressListener.progress(70);
|
||||
compileEep();
|
||||
|
||||
// 6. build the .hex file
|
||||
sketch.setCompilingProgress(80);
|
||||
progressListener.progress(80);
|
||||
compileHex();
|
||||
|
||||
sketch.setCompilingProgress(90);
|
||||
progressListener.progress(90);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -151,7 +418,7 @@ public class Compiler implements MessageConsumer {
|
||||
String _primaryClassName)
|
||||
throws RunnerException {
|
||||
|
||||
if (Base.getBoardPreferences() == null) {
|
||||
if (BaseNoGui.getBoardPreferences() == null) {
|
||||
RunnerException re = new RunnerException(
|
||||
_("No board selected; please choose a board from the Tools > Board menu."));
|
||||
re.hideStackTrace();
|
||||
@ -159,14 +426,14 @@ public class Compiler implements MessageConsumer {
|
||||
}
|
||||
|
||||
// Check if the board needs a platform from another package
|
||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
TargetPlatform corePlatform = null;
|
||||
PreferencesMap boardPreferences = Base.getBoardPreferences();
|
||||
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
|
||||
String core = boardPreferences.get("build.core");
|
||||
if (core.contains(":")) {
|
||||
String[] split = core.split(":");
|
||||
core = split[1];
|
||||
corePlatform = Base.getTargetPlatform(split[0], targetPlatform.getId());
|
||||
corePlatform = BaseNoGui.getTargetPlatform(split[0], targetPlatform.getId());
|
||||
if (corePlatform == null) {
|
||||
RunnerException re = new RunnerException(I18n
|
||||
.format(_("Selected board depends on '{0}' core (not installed)."),
|
||||
@ -178,11 +445,11 @@ public class Compiler implements MessageConsumer {
|
||||
|
||||
// Merge all the global preference configuration in order of priority
|
||||
PreferencesMap p = new PreferencesMap();
|
||||
p.putAll(Preferences.getMap());
|
||||
p.putAll(PreferencesData.getMap());
|
||||
if (corePlatform != null)
|
||||
p.putAll(corePlatform.getPreferences());
|
||||
p.putAll(targetPlatform.getPreferences());
|
||||
p.putAll(Base.getBoardPreferences());
|
||||
p.putAll(BaseNoGui.getBoardPreferences());
|
||||
for (String k : p.keySet()) {
|
||||
if (p.get(k) == null)
|
||||
p.put(k, "");
|
||||
@ -190,8 +457,7 @@ public class Compiler implements MessageConsumer {
|
||||
|
||||
p.put("build.path", _buildPath);
|
||||
p.put("build.project_name", _primaryClassName);
|
||||
targetArch = targetPlatform.getId();
|
||||
p.put("build.arch", targetArch.toUpperCase());
|
||||
p.put("build.arch", targetPlatform.getId().toUpperCase());
|
||||
|
||||
// Platform.txt should define its own compiler.path. For
|
||||
// compatibility with earlier 1.5 versions, we define a (ugly,
|
||||
@ -199,7 +465,7 @@ public class Compiler implements MessageConsumer {
|
||||
// point.
|
||||
if (!p.containsKey("compiler.path")) {
|
||||
System.err.println(_("Third-party platform.txt does not define compiler.path. Please report this to the third-party hardware maintainer."));
|
||||
p.put("compiler.path", Base.getAvrBasePath());
|
||||
p.put("compiler.path", BaseNoGui.getAvrBasePath());
|
||||
}
|
||||
|
||||
// Core folder
|
||||
@ -224,7 +490,7 @@ public class Compiler implements MessageConsumer {
|
||||
t = targetPlatform;
|
||||
} else {
|
||||
String[] split = variant.split(":", 2);
|
||||
t = Base.getTargetPlatform(split[0], targetPlatform.getId());
|
||||
t = BaseNoGui.getTargetPlatform(split[0], targetPlatform.getId());
|
||||
variant = split[1];
|
||||
}
|
||||
File variantFolder = new File(t.getFolder(), "variants");
|
||||
@ -356,8 +622,6 @@ public class Compiler implements MessageConsumer {
|
||||
return ret;
|
||||
}
|
||||
|
||||
boolean firstErrorFound;
|
||||
boolean secondErrorFound;
|
||||
|
||||
/**
|
||||
* Either succeeds or throws a RunnerException fit for public consumption.
|
||||
@ -382,9 +646,6 @@ public class Compiler implements MessageConsumer {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
firstErrorFound = false; // haven't found any errors yet
|
||||
secondErrorFound = false;
|
||||
|
||||
Process process;
|
||||
try {
|
||||
process = ProcessUtils.exec(command);
|
||||
@ -520,7 +781,7 @@ public class Compiler implements MessageConsumer {
|
||||
if (!sketchIsCompiled) {
|
||||
// Place errors when compiling the sketch, but never while compiling libraries
|
||||
// or the core. The user's sketch might contain the same filename!
|
||||
e = sketch.placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1);
|
||||
e = placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1);
|
||||
}
|
||||
|
||||
// replace full file path with the name of the sketch tab (unless we're
|
||||
@ -558,7 +819,7 @@ public class Compiler implements MessageConsumer {
|
||||
throws RunnerException {
|
||||
String includes = prepareIncludes(includeFolders);
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
dict.put("includes", includes);
|
||||
dict.put("source_file", sourceFile.getAbsolutePath());
|
||||
dict.put("object_file", objectFile.getAbsolutePath());
|
||||
@ -577,7 +838,7 @@ public class Compiler implements MessageConsumer {
|
||||
String includes = prepareIncludes(includeFolders);
|
||||
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
dict.put("includes", includes);
|
||||
dict.put("source_file", sourceFile.getAbsolutePath());
|
||||
dict.put("object_file", objectFile.getAbsolutePath());
|
||||
@ -596,7 +857,7 @@ public class Compiler implements MessageConsumer {
|
||||
String includes = prepareIncludes(includeFolders);
|
||||
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
dict.put("includes", includes);
|
||||
dict.put("source_file", sourceFile.getAbsolutePath());
|
||||
dict.put("object_file", objectFile.getAbsolutePath());
|
||||
@ -656,7 +917,7 @@ public class Compiler implements MessageConsumer {
|
||||
// 2. compile the libraries, outputting .o files to:
|
||||
// <buildPath>/<library>/
|
||||
void compileLibraries(List<File> includeFolders) throws RunnerException {
|
||||
for (Library lib : sketch.getImportedLibraries()) {
|
||||
for (Library lib : importedLibraries) {
|
||||
compileLibrary(lib, includeFolders);
|
||||
}
|
||||
}
|
||||
@ -758,7 +1019,7 @@ public class Compiler implements MessageConsumer {
|
||||
for (File file : coreObjectFiles) {
|
||||
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
dict.put("archive_file", afile.getName());
|
||||
dict.put("object_file", file.getAbsolutePath());
|
||||
|
||||
@ -799,7 +1060,7 @@ public class Compiler implements MessageConsumer {
|
||||
dict.put("compiler.c.elf.flags", flags);
|
||||
dict.put("archive_file", "core.a");
|
||||
dict.put("object_files", objectFileList);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
|
||||
String[] cmdArray;
|
||||
try {
|
||||
@ -814,7 +1075,7 @@ public class Compiler implements MessageConsumer {
|
||||
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
||||
void compileEep() throws RunnerException {
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
|
||||
String[] cmdArray;
|
||||
try {
|
||||
@ -829,7 +1090,7 @@ public class Compiler implements MessageConsumer {
|
||||
// 6. build the .hex file
|
||||
void compileHex() throws RunnerException {
|
||||
PreferencesMap dict = new PreferencesMap(prefs);
|
||||
dict.put("ide_version", "" + Base.REVISION);
|
||||
dict.put("ide_version", "" + BaseNoGui.REVISION);
|
||||
|
||||
String[] cmdArray;
|
||||
try {
|
||||
@ -853,4 +1114,141 @@ public class Compiler implements MessageConsumer {
|
||||
public PreferencesMap getBuildPreferences() {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build all the code for this sketch.
|
||||
*
|
||||
* In an advanced program, the returned class name could be different,
|
||||
* which is why the className is set based on the return value.
|
||||
* A compilation error will burp up a RunnerException.
|
||||
*
|
||||
* Setting purty to 'true' will cause exception line numbers to be incorrect.
|
||||
* Unless you know the code compiles, you should first run the preprocessor
|
||||
* with purty set to false to make sure there are no errors, then once
|
||||
* successful, re-export with purty set to true.
|
||||
*
|
||||
* @param buildPath Location to copy all the .java files
|
||||
* @return null if compilation failed, main class name if not
|
||||
*/
|
||||
public void preprocess(String buildPath) throws RunnerException {
|
||||
preprocess(buildPath, new PdePreprocessor());
|
||||
}
|
||||
|
||||
public void preprocess(String buildPath, PdePreprocessor preprocessor) throws RunnerException {
|
||||
|
||||
// 1. concatenate all .pde files to the 'main' pde
|
||||
// store line number for starting point of each code bit
|
||||
|
||||
StringBuffer bigCode = new StringBuffer();
|
||||
int bigCount = 0;
|
||||
for (SketchCode sc : sketch.getCodes()) {
|
||||
if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||
sc.setPreprocOffset(bigCount);
|
||||
// These #line directives help the compiler report errors with
|
||||
// correct the filename and line number (issue 281 & 907)
|
||||
bigCode.append("#line 1 \"" + sc.getFileName() + "\"\n");
|
||||
bigCode.append(sc.getProgram());
|
||||
bigCode.append('\n');
|
||||
bigCount += sc.getLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
try {
|
||||
headerOffset = preprocessor.writePrefix(bigCode.toString());
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = _("Build folder disappeared or could not be written");
|
||||
throw new RunnerException(msg);
|
||||
}
|
||||
|
||||
// 2. run preproc on that code using the sugg class name
|
||||
// to create a single .java file and write to buildpath
|
||||
|
||||
try {
|
||||
// Output file
|
||||
File streamFile = new File(buildPath, sketch.getName() + ".cpp");
|
||||
FileOutputStream outputStream = new FileOutputStream(streamFile);
|
||||
preprocessor.write(outputStream);
|
||||
outputStream.close();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = _("Build folder disappeared or could not be written");
|
||||
throw new RunnerException(msg);
|
||||
} catch (RunnerException pe) {
|
||||
// RunnerExceptions are caught here and re-thrown, so that they don't
|
||||
// get lost in the more general "Exception" handler below.
|
||||
throw pe;
|
||||
|
||||
} catch (Exception ex) {
|
||||
// TODO better method for handling this?
|
||||
System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass()));
|
||||
ex.printStackTrace();
|
||||
throw new RunnerException(ex.toString());
|
||||
}
|
||||
|
||||
// grab the imports from the code just preproc'd
|
||||
|
||||
importedLibraries = new LibraryList();
|
||||
for (String item : preprocessor.getExtraImports()) {
|
||||
Library lib = BaseNoGui.importToLibraryTable.get(item);
|
||||
if (lib != null && !importedLibraries.contains(lib)) {
|
||||
importedLibraries.add(lib);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. then loop over the code[] and save each .java file
|
||||
|
||||
for (SketchCode sc : sketch.getCodes()) {
|
||||
if (sc.isExtension("c") || sc.isExtension("cpp") || sc.isExtension("h")) {
|
||||
// no pre-processing services necessary for java files
|
||||
// just write the the contents of 'program' to a .java file
|
||||
// into the build directory. uses byte stream and reader/writer
|
||||
// shtuff so that unicode bunk is properly handled
|
||||
String filename = sc.getFileName(); //code[i].name + ".java";
|
||||
try {
|
||||
BaseNoGui.saveFile(sc.getProgram(), new File(buildPath, filename));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RunnerException(I18n.format(_("Problem moving {0} to the build folder"), filename));
|
||||
}
|
||||
|
||||
} else if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||
// The compiler and runner will need this to have a proper offset
|
||||
sc.addPreprocOffset(headerOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List of library folders.
|
||||
*/
|
||||
private LibraryList 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 dotJavaFilename The .java file where the exception was found.
|
||||
* @param dotJavaLine 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) {
|
||||
// Placing errors is simple, because we inserted #line directives
|
||||
// into the preprocessed source. The compiler gives us correct
|
||||
// the file name and line number. :-)
|
||||
for (SketchCode code : sketch.getCodes()) {
|
||||
if (dotJavaFilename.equals(code.getFileName())) {
|
||||
return new RunnerException(message, sketch.indexOfCode(code), dotJavaLine);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package processing.app.helpers;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
public class BasicUserNotifier extends UserNotifier {
|
||||
|
||||
/**
|
||||
* Show an error message that's actually fatal to the program.
|
||||
* This is an error that can't be recovered. Use showWarning()
|
||||
* for errors that allow P5 to continue running.
|
||||
*/
|
||||
public void showError(String title, String message, Throwable e, int exit_code) {
|
||||
if (title == null) title = _("Error");
|
||||
|
||||
System.err.println(title + ": " + message);
|
||||
|
||||
if (e != null) e.printStackTrace();
|
||||
System.exit(exit_code);
|
||||
}
|
||||
|
||||
public void showMessage(String title, String message) {
|
||||
if (title == null) title = _("Message");
|
||||
|
||||
System.out.println(title + ": " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-fatal error message with optional stack trace side dish.
|
||||
*/
|
||||
public void showWarning(String title, String message, Exception e) {
|
||||
if (title == null) title = _("Warning");
|
||||
|
||||
System.out.println(title + ": " + message);
|
||||
|
||||
if (e != null) e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
283
arduino-core/src/processing/app/helpers/CommandlineParser.java
Normal file
283
arduino-core/src/processing/app/helpers/CommandlineParser.java
Normal file
@ -0,0 +1,283 @@
|
||||
package processing.app.helpers;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.TargetBoard;
|
||||
import processing.app.debug.TargetPackage;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
public class CommandlineParser {
|
||||
|
||||
protected static enum ACTION { GUI, NOOP, VERIFY, UPLOAD, GET_PREF };
|
||||
|
||||
private ACTION action = ACTION.GUI;
|
||||
private boolean doVerboseBuild = false;
|
||||
private boolean doVerboseUpload = false;
|
||||
private boolean doUseProgrammer = false;
|
||||
private boolean noUploadPort = false;
|
||||
private boolean forceSavePrefs = false;
|
||||
private String getPref = null;
|
||||
private List<String> filenames = new LinkedList<String>();
|
||||
|
||||
public static CommandlineParser newCommandlineParser(String[] args) {
|
||||
return new CommandlineParser(args);
|
||||
}
|
||||
|
||||
private CommandlineParser(String[] args) {
|
||||
parseArguments(args);
|
||||
checkAction();
|
||||
}
|
||||
|
||||
private void parseArguments(String[] args) {
|
||||
// Map of possible actions and corresponding options
|
||||
final Map<String, ACTION> actions = new HashMap<String, ACTION>();
|
||||
actions.put("--verify", ACTION.VERIFY);
|
||||
actions.put("--upload", ACTION.UPLOAD);
|
||||
actions.put("--get-pref", ACTION.GET_PREF);
|
||||
|
||||
// Check if any files were passed in on the command line
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
ACTION a = actions.get(args[i]);
|
||||
if (a != null) {
|
||||
if (action != ACTION.GUI && action != ACTION.NOOP) {
|
||||
String[] valid = actions.keySet().toArray(new String[0]);
|
||||
String mess = I18n.format(_("Can only pass one of: {0}"), PApplet.join(valid, ", "));
|
||||
BaseNoGui.showError(null, mess, 3);
|
||||
}
|
||||
if (a == ACTION.GET_PREF) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --get-pref"), 3);
|
||||
getPref = args[i];
|
||||
}
|
||||
action = a;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose") || args[i].equals("-v")) {
|
||||
doVerboseBuild = true;
|
||||
doVerboseUpload = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose-build")) {
|
||||
doVerboseBuild = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--verbose-upload")) {
|
||||
doVerboseUpload = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--useprogrammer")) {
|
||||
doUseProgrammer = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--nouploadport")) {
|
||||
noUploadPort = true;
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--board")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --board"), 3);
|
||||
processBoardArgument(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--port")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --port"), 3);
|
||||
BaseNoGui.selectSerialPort(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--curdir")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --curdir"), 3);
|
||||
// Argument should be already processed by Base.main(...)
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--buildpath")) {
|
||||
i++;
|
||||
if (i >= args.length) {
|
||||
BaseNoGui.showError(null, "Argument required for --buildpath", 3);
|
||||
}
|
||||
File buildFolder = new File(args[i]);
|
||||
if (!buildFolder.exists()) {
|
||||
BaseNoGui.showError(null, "The build path doesn't exist", 3);
|
||||
}
|
||||
if (!buildFolder.isDirectory()) {
|
||||
BaseNoGui.showError(null, "The build path is not a folder", 3);
|
||||
}
|
||||
BaseNoGui.setBuildFolder(buildFolder);
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--pref")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --pref"), 3);
|
||||
processPrefArgument(args[i]);
|
||||
if (action == ACTION.GUI)
|
||||
action = ACTION.NOOP;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--save-prefs")) {
|
||||
forceSavePrefs = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].equals("--preferences-file")) {
|
||||
i++;
|
||||
if (i >= args.length)
|
||||
BaseNoGui.showError(null, _("Argument required for --preferences-file"), 3);
|
||||
// Argument should be already processed by Base.main(...)
|
||||
continue;
|
||||
}
|
||||
if (args[i].startsWith("--"))
|
||||
BaseNoGui.showError(null, I18n.format(_("unknown option: {0}"), args[i]), 3);
|
||||
|
||||
filenames.add(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAction() {
|
||||
if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1)
|
||||
BaseNoGui.showError(null, _("Must specify exactly one sketch file"), 3);
|
||||
|
||||
if ((action == ACTION.NOOP || action == ACTION.GET_PREF) && filenames.size() != 0)
|
||||
BaseNoGui.showError(null, _("Cannot specify any sketch files"), 3);
|
||||
|
||||
if ((action != ACTION.UPLOAD && action != ACTION.VERIFY) && (doVerboseBuild || doVerboseUpload))
|
||||
BaseNoGui.showError(null, _("--verbose, --verbose-upload and --verbose-build can only be used together with --verify or --upload"), 3);
|
||||
}
|
||||
|
||||
private void processBoardArgument(String selectBoard) {
|
||||
// No board selected? Nothing to do
|
||||
if (selectBoard == null)
|
||||
return;
|
||||
|
||||
String[] split = selectBoard.split(":", 4);
|
||||
|
||||
if (split.length < 3) {
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Invalid board name, it should be of the form \"package:arch:board\" or \"package:arch:board:options\""), selectBoard), 3);
|
||||
}
|
||||
|
||||
TargetPackage targetPackage = BaseNoGui.getTargetPackage(split[0]);
|
||||
if (targetPackage == null) {
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Unknown package"), split[0]), 3);
|
||||
}
|
||||
|
||||
TargetPlatform targetPlatform = targetPackage.get(split[1]);
|
||||
if (targetPlatform == null) {
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Unknown architecture"), split[1]), 3);
|
||||
}
|
||||
|
||||
TargetBoard targetBoard = targetPlatform.getBoard(split[2]);
|
||||
if (targetBoard == null) {
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Unknown board"), split[2]), 3);
|
||||
}
|
||||
|
||||
BaseNoGui.selectBoard(targetBoard);
|
||||
|
||||
if (split.length > 3) {
|
||||
String[] options = split[3].split(",");
|
||||
for (String option : options) {
|
||||
String[] keyValue = option.split("=", 2);
|
||||
|
||||
if (keyValue.length != 2)
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Invalid option, should be of the form \"name=value\""), option, targetBoard.getId()), 3);
|
||||
String key = keyValue[0].trim();
|
||||
String value = keyValue[1].trim();
|
||||
|
||||
if (!targetBoard.hasMenu(key))
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Invalid option for board \"{1}\""), key, targetBoard.getId()), 3);
|
||||
if (targetBoard.getMenuLabel(key, value) == null)
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Invalid option for \"{1}\" option for board \"{2}\""), value, key, targetBoard.getId()), 3);
|
||||
|
||||
PreferencesData.set("custom_" + key, targetBoard.getId() + "_" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processPrefArgument(String arg) {
|
||||
String[] split = arg.split("=", 2);
|
||||
if (split.length != 2 || split[0].isEmpty())
|
||||
BaseNoGui.showError(null, I18n.format(_("{0}: Invalid argument to --pref, should be of the form \"pref=value\""), arg), 3);
|
||||
|
||||
PreferencesData.set(split[0], split[1]);
|
||||
}
|
||||
|
||||
public boolean isDoVerboseBuild() {
|
||||
return doVerboseBuild;
|
||||
}
|
||||
|
||||
public boolean isDoVerboseUpload() {
|
||||
return doVerboseUpload;
|
||||
}
|
||||
|
||||
public boolean isForceSavePrefs() {
|
||||
return forceSavePrefs;
|
||||
}
|
||||
|
||||
public String getGetPref() {
|
||||
return getPref;
|
||||
}
|
||||
|
||||
public List<String> getFilenames() {
|
||||
return filenames;
|
||||
}
|
||||
|
||||
public boolean isGetPrefMode() {
|
||||
return action == ACTION.GET_PREF;
|
||||
}
|
||||
|
||||
public boolean isGuiMode() {
|
||||
return action == ACTION.GUI;
|
||||
}
|
||||
|
||||
public boolean isNoOpMode() {
|
||||
return action == ACTION.NOOP;
|
||||
}
|
||||
|
||||
public boolean isUploadMode() {
|
||||
return action == ACTION.UPLOAD;
|
||||
}
|
||||
|
||||
public boolean isVerifyMode() {
|
||||
return action == ACTION.VERIFY;
|
||||
}
|
||||
|
||||
public boolean isVerifyOrUploadMode() {
|
||||
return isVerifyMode() || isUploadMode();
|
||||
}
|
||||
|
||||
public boolean isDoUseProgrammer() {
|
||||
return doUseProgrammer;
|
||||
}
|
||||
|
||||
public boolean isNoUploadPort() {
|
||||
return noUploadPort;
|
||||
}
|
||||
|
||||
}
|
29
arduino-core/src/processing/app/helpers/OSUtils.java
Normal file
29
arduino-core/src/processing/app/helpers/OSUtils.java
Normal file
@ -0,0 +1,29 @@
|
||||
package processing.app.helpers;
|
||||
|
||||
public class OSUtils {
|
||||
|
||||
/**
|
||||
* returns true if running on windows.
|
||||
*/
|
||||
static public boolean isWindows() {
|
||||
//return PApplet.platform == PConstants.WINDOWS;
|
||||
return System.getProperty("os.name").indexOf("Windows") != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if running on linux.
|
||||
*/
|
||||
static public boolean isLinux() {
|
||||
//return PApplet.platform == PConstants.LINUX;
|
||||
return System.getProperty("os.name").indexOf("Linux") != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if Processing is running on a Mac OS X machine.
|
||||
*/
|
||||
static public boolean isMacOS() {
|
||||
//return PApplet.platform == PConstants.MACOSX;
|
||||
return System.getProperty("os.name").indexOf("Mac") != -1;
|
||||
}
|
||||
|
||||
}
|
103
arduino-core/src/processing/app/helpers/PreferencesHelper.java
Normal file
103
arduino-core/src/processing/app/helpers/PreferencesHelper.java
Normal file
@ -0,0 +1,103 @@
|
||||
package processing.app.helpers;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
|
||||
public abstract class PreferencesHelper {
|
||||
|
||||
// /**
|
||||
// * Create a Color with the value of the specified key. The format of the color
|
||||
// * should be an hexadecimal number of 6 digit, eventually prefixed with a '#'.
|
||||
// *
|
||||
// * @param name
|
||||
// * @return A Color object or <b>null</b> if the key is not found or the format
|
||||
// * is wrong
|
||||
// */
|
||||
// static public Color getColor(PreferencesMap prefs, String name) {
|
||||
// Color parsed = parseColor(prefs.get(name));
|
||||
// if (parsed != null)
|
||||
// return parsed;
|
||||
// return Color.GRAY; // set a default
|
||||
// }
|
||||
//
|
||||
//
|
||||
// static public void setColor(PreferencesMap prefs, String attr, Color what) {
|
||||
// putColor(prefs, attr, what);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// static public Font getFontWithDefault(PreferencesMap prefs, PreferencesMap defaults, String attr) {
|
||||
// Font font = getFont(prefs, attr);
|
||||
// if (font == null) {
|
||||
// String value = defaults.get(attr);
|
||||
// prefs.put(attr, value);
|
||||
// font = getFont(prefs, attr);
|
||||
// }
|
||||
// return font;
|
||||
// }
|
||||
//
|
||||
// static public SyntaxStyle getStyle(PreferencesMap prefs, String what) {
|
||||
// String str = prefs.get("editor." + what + ".style");
|
||||
//
|
||||
// StringTokenizer st = new StringTokenizer(str, ",");
|
||||
//
|
||||
// String s = st.nextToken();
|
||||
// if (s.indexOf("#") == 0) s = s.substring(1);
|
||||
// Color color = Color.DARK_GRAY;
|
||||
// try {
|
||||
// color = new Color(Integer.parseInt(s, 16));
|
||||
// } catch (Exception e) { }
|
||||
//
|
||||
// s = st.nextToken();
|
||||
// boolean bold = (s.indexOf("bold") != -1);
|
||||
// boolean italic = (s.indexOf("italic") != -1);
|
||||
// boolean underlined = (s.indexOf("underlined") != -1);
|
||||
//
|
||||
// return new SyntaxStyle(color, italic, bold, underlined);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Set the value of the specified key based on the Color passed as parameter.
|
||||
*
|
||||
* @param attr
|
||||
* @param color
|
||||
*/
|
||||
public static void putColor(PreferencesMap prefs, String attr, Color color) {
|
||||
prefs.put(attr, "#" + String.format("%06x", color.getRGB() & 0xffffff));
|
||||
}
|
||||
|
||||
public static Color parseColor(String v) {
|
||||
try {
|
||||
if (v.indexOf("#") == 0)
|
||||
v = v.substring(1);
|
||||
return new Color(Integer.parseInt(v, 16));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Font getFont(PreferencesMap prefs, String key) {
|
||||
String value = prefs.get(key);
|
||||
if (value == null)
|
||||
return null;
|
||||
String[] split = value.split(",");
|
||||
if (split.length != 3)
|
||||
return null;
|
||||
|
||||
String name = split[0];
|
||||
int style = Font.PLAIN;
|
||||
if (split[1].contains("bold"))
|
||||
style |= Font.BOLD;
|
||||
if (split[1].contains("italic"))
|
||||
style |= Font.ITALIC;
|
||||
int size;
|
||||
try {
|
||||
// ParseDouble handle numbers with decimals too
|
||||
size = (int) Double.parseDouble(split[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
// for wrong formatted size pick the default
|
||||
size = 12;
|
||||
}
|
||||
return new Font(name, style, size);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
to handle preferences.
|
||||
Part of the Arduino project - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2011 Cristian Maglie
|
||||
Copyright (c) 2014 Cristian Maglie
|
||||
|
||||
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
|
||||
@ -27,14 +27,11 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.core.PApplet;
|
||||
import processing.app.legacy.PApplet;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class PreferencesMap extends LinkedHashMap<String, String> {
|
||||
@ -107,9 +104,9 @@ public class PreferencesMap extends LinkedHashMap<String, String> {
|
||||
String key = line.substring(0, equals).trim();
|
||||
String value = line.substring(equals + 1).trim();
|
||||
|
||||
key = processPlatformSuffix(key, ".linux", Base.isLinux());
|
||||
key = processPlatformSuffix(key, ".windows", Base.isWindows());
|
||||
key = processPlatformSuffix(key, ".macosx", Base.isMacOS());
|
||||
key = processPlatformSuffix(key, ".linux", OSUtils.isLinux());
|
||||
key = processPlatformSuffix(key, ".windows", OSUtils.isWindows());
|
||||
key = processPlatformSuffix(key, ".macosx", OSUtils.isMacOS());
|
||||
|
||||
if (key != null)
|
||||
put(key, value);
|
||||
@ -296,4 +293,30 @@ public class PreferencesMap extends LinkedHashMap<String, String> {
|
||||
return null;
|
||||
return new File(file, subFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the specified key as boolean.
|
||||
*
|
||||
* @param key
|
||||
* @return <b>true</b> if the value of the key is the string "true" (case
|
||||
* insensitive compared), <b>false</b> in any other case
|
||||
*/
|
||||
public boolean getBoolean(String key) {
|
||||
return new Boolean(get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the specified key to the string <b>"true"</b> or
|
||||
* <b>"false"</b> based on value of the boolean parameter
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @return <b>true</b> if the previous value of the key was the string "true"
|
||||
* (case insensitive compared), <b>false</b> in any other case
|
||||
*/
|
||||
public boolean putBoolean(String key, boolean value) {
|
||||
String prev = put(key, value ? "true" : "false");
|
||||
return new Boolean(prev);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user