diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 3c8ef92fd..0243a47bf 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -111,6 +111,9 @@ public class Base { List editors = Collections.synchronizedList(new ArrayList()); Editor activeEditor; + static File portableFolder = null; + static final String portableSketchbookFolder = "sketchbook"; + static public void main(String args[]) throws Exception { initPlatform(); @@ -156,6 +159,13 @@ public class Base { } */ + initPlatform(); + + // Portable folder + portableFolder = getContentFile("portable"); + if (!portableFolder.exists()) + portableFolder = null; + // // Set the look and feel before opening the window // try { // platform.setLookAndFeel(); @@ -249,8 +259,12 @@ public class Base { // If a value is at least set, first check to see if the folder exists. // If it doesn't, warn the user that the sketchbook folder is being reset. if (sketchbookPath != null) { - File skechbookFolder = new File(sketchbookPath); - if (!skechbookFolder.exists()) { + File sketchbookFolder; + if (portableFolder != null) + sketchbookFolder = new File(portableFolder, sketchbookPath); + else + sketchbookFolder = new File(sketchbookPath); + if (!sketchbookFolder.exists()) { Base.showWarning(_("Sketchbook folder disappeared"), _("The sketchbook folder no longer exists.\n" + "Arduino will switch to the default sketchbook\n" + @@ -264,7 +278,10 @@ public class Base { // If no path is set, get the default sketchbook folder for this platform if (sketchbookPath == null) { File defaultFolder = getDefaultSketchbookFolder(); - Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath()); + if (portableFolder != null) + Preferences.set("sketchbook.path", portableSketchbookFolder); + else + Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath()); if (!defaultFolder.exists()) { defaultFolder.mkdirs(); } @@ -422,6 +439,15 @@ 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); + try { + path = absolute.getCanonicalPath(); + } + catch (IOException e) { + // path unchanged. + } + } int[] location; if (windowPositionValid) { String locationStr = Preferences.get("last.sketch" + i + ".location"); @@ -460,6 +486,11 @@ public class Base { !editor.getSketch().isModified()) { continue; } + if (portableFolder != null) { + path = RelativePath.relativePath(portableFolder.toString(), path); + if (path == null) + continue; + } Preferences.set("last.sketch" + index + ".path", path); int[] location = editor.getPlacement(); @@ -478,6 +509,11 @@ public class Base { String untitledPath = untitledFolder.getAbsolutePath(); if (path.startsWith(untitledPath)) { path = ""; + } else + if (portableFolder != null) { + path = RelativePath.relativePath(portableFolder.toString(), path); + if (path == null) + path = ""; } Preferences.set("last.sketch" + index + ".path", path); } @@ -1759,6 +1795,9 @@ public class Base { static public File getSettingsFolder() { + if (portableFolder != null) + return portableFolder; + File settingsFolder = null; String preferencesPath = Preferences.get("settings.path"); @@ -1938,7 +1977,19 @@ public class Base { return boardPreferences; } + static public File getPortableFolder() { + return portableFolder; + } + + + static public String getPortableSketchbookFolder() { + return portableSketchbookFolder; + } + + static public File getSketchbookFolder() { + if (portableFolder != null) + return new File(portableFolder, Preferences.get("sketchbook.path")); return new File(Preferences.get("sketchbook.path")); } @@ -1971,6 +2022,9 @@ public class Base { protected File getDefaultSketchbookFolder() { + if (portableFolder != null) + return new File(portableFolder, portableSketchbookFolder); + File sketchbookFolder = null; try { sketchbookFolder = platform.getDefaultSketchbookFolder(); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index be7c64dc0..0661c08f9 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -326,7 +326,14 @@ public class Preferences { File file = Base.selectFolder(_("Select new sketchbook location"), dflt, dialog); if (file != null) { - sketchbookLocationField.setText(file.getAbsolutePath()); + String path = file.getAbsolutePath(); + if (Base.getPortableFolder() != null) { + path = RelativePath.relativePath(Base.getPortableFolder().toString(), path); + if (path == null) { + path = Base.getPortableSketchbookFolder(); + } + } + sketchbookLocationField.setText(path); } } }); @@ -439,6 +446,10 @@ public class Preferences { autoAssociateBox.setBounds(left, top, d.width + 10, d.height); right = Math.max(right, left + d.width); top += d.height + GUI_BETWEEN; + + // If using portable mode, it's bad manner to change PC setting. + if (Base.getPortableFolder() != null) + autoAssociateBox.setEnabled(false); } // More preferences are in the ... @@ -591,6 +602,12 @@ public class Preferences { // if the sketchbook path has changed, rebuild the menus String oldPath = get("sketchbook.path"); String newPath = sketchbookLocationField.getText(); + if (newPath.isEmpty()) { + if (Base.getPortableFolder() == null) + newPath = editor.base.getDefaultSketchbookFolder().toString(); + else + newPath = Base.getPortableSketchbookFolder(); + } if (!newPath.equals(oldPath)) { editor.base.rebuildSketchbookMenus(); set("sketchbook.path", newPath); diff --git a/app/src/processing/app/RelativePath.java b/app/src/processing/app/RelativePath.java new file mode 100644 index 000000000..7daeb990e --- /dev/null +++ b/app/src/processing/app/RelativePath.java @@ -0,0 +1,74 @@ +/* + * by Shigeru KANEMOTO at SWITCHSCIENCE. + */ + +package processing.app; + +import java.io.File; +import java.io.IOException; + +class RelativePath { + // + // Compute relative path to "target" from a directory "origin". + // + // If "origin" is not absolute, it is relative from the current directory. + // If "target" is not absolute, it is relative from "origin". + // + public static String relativePath(String origin, String target) { + try { + origin = (new File(origin)).getCanonicalPath(); + File targetFile = new File(target); + if (targetFile.isAbsolute()) + target = targetFile.getCanonicalPath(); + else + target = (new File(origin, target)).getCanonicalPath(); + } + catch (IOException e) { + return null; + } + + if (origin.equals(target)) { + // origin and target is identical. + return "."; + } + + if (origin.equals(File.separator)) { + // origin is root. + return "." + target; + } + + String prefix = ""; + String root = File.separator; + + if (System.getProperty("os.name").indexOf("Windows") != -1) { + if (origin.startsWith("\\\\") || target.startsWith("\\\\")) { + // Windows UNC path not supported. + return null; + } + + char originLetter = origin.charAt(0); + char targetLetter = target.charAt(0); + if (Character.isLetter(originLetter) && Character.isLetter(targetLetter)) { + // Windows only + if (originLetter != targetLetter) { + // Drive letters differ + return null; + } + } + + prefix = "" + originLetter + ':'; + root = prefix + File.separator; + } + + String relative = ""; + while (!target.startsWith(origin + File.separator)) { + origin = (new File(origin)).getParent(); + if (origin.equals(root)) + origin = prefix; + relative += ".."; + relative += File.separator; + } + + return relative + target.substring(origin.length() + 1); + } +} diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 64c6bc048..b8500854c 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -826,7 +826,7 @@ public class Sketch { FileDialog.SAVE); if (isReadOnly() || isUntitled()) { // default to the sketchbook folder - fd.setDirectory(Preferences.get("sketchbook.path")); + fd.setDirectory(Base.getSketchbookFolder().getAbsolutePath()); } else { // default to the parent folder of where this was fd.setDirectory(folder.getParent());