diff --git a/app/Editor.java b/app/Editor.java index 9193fe224..5ba63d830 100644 --- a/app/Editor.java +++ b/app/Editor.java @@ -1163,7 +1163,8 @@ public class Editor extends JFrame /** - * Called by EditorStatus to complete the job. + * Called by EditorStatus to complete the job and re-dispatch + * to handleNew, handleOpen, handleQuit. */ public void checkModified2() { switch (checkModifiedMode) { @@ -1191,11 +1192,11 @@ public class Editor extends JFrame /** - * Extra public method so that Sketch can call - * this when a sketch is selected to be deleted, - * and it won't prompt for save as. + * Extra public method so that Sketch can call this when a sketch + * is selected to be deleted, and it won't call checkModified() + * to prompt for save as. */ - public void handleNew() { + public void handleNewUnchecked() { doStop(); handleNewShift = false; handleNewLibrary = false; @@ -1220,7 +1221,8 @@ public class Editor extends JFrame * Does all the plumbing to create a new project * then calls handleOpen to load it up. * - * @param noPrompt true if the app is starting (auto-create a sketch) + * @param noPrompt true to disable prompting for the sketch + * name, used when the app is starting (auto-create a sketch) */ protected void handleNew2(boolean noPrompt) { try { @@ -1258,12 +1260,23 @@ public class Editor extends JFrame path = sketchbook.handleOpen(); if (path == null) return; } - doStop(); + doClose(); + //doStop(); handleOpenPath = path; checkModified(HANDLE_OPEN); } + /** + * Open a sketch from a particular path, but don't check to save changes. + * Used by Sketch.saveAs() to re-open a sketch after the "Save As" + */ + public void handleOpenUnchecked(String path) { + doClose(); + handleOpen2(path); + } + + /** * Second stage of open, occurs after having checked to * see if the modifications (if any) to the previous sketch @@ -1468,14 +1481,11 @@ public class Editor extends JFrame * in Editor since it has the callback from EditorStatus. */ public void handleQuit() { - // stop isn't sufficient with external vm & quit + // doStop() isn't sufficient with external vm & quit // instead use doClose() which will kill the external vm - //doStop(); doClose(); - //if (!checkModified()) return; checkModified(HANDLE_QUIT); - //System.out.println("exiting doquit"); } diff --git a/app/Sketch.java b/app/Sketch.java index ed6809c6e..2fc557359 100644 --- a/app/Sketch.java +++ b/app/Sketch.java @@ -437,6 +437,9 @@ public class Sketch { options[0]); if (result == JOptionPane.YES_OPTION) { if (current == code[0]) { + // need to unset all the modified flags, otherwise tries + // to do a save on the handleNew() + // delete the entire sketch Base.removeDir(folder); @@ -444,13 +447,13 @@ public class Sketch { //sketchbook.rebuildMenus(); // make a new sketch, and i think this will rebuild the sketch menu - editor.handleNew(); + editor.handleNewUnchecked(); } else { // delete the file if (!current.file.delete()) { Base.showMessage("Couldn't do it", - "Could not delete \"" + current.name + "\"."); + "Could not delete \"" + current.name + "\"."); return; } @@ -594,17 +597,18 @@ public class Sketch { if (folder.exists()) return; Base.showWarning("Sketch Disappeared", - "The sketch folder has disappeared " + - "(did you delete it?)\n" + - "Will attempt to re-save in the same location," + + "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(); modified = true; for (int i = 0; i < codeCount; i++) { - //code[i].modified = true; // make sure it gets re-saved - code[i].save(); + code[i].save(); // this will force a save + } + for (int i = 0; i < hiddenCount; i++) { + hidden[i].save(); // this will force a save } calcModified(); @@ -631,7 +635,7 @@ public class Sketch { } // don't do anything if not actually modified - if (!modified) return false; + //if (!modified) return false; if (isReadOnly()) { // if the files are read-only, need to first do a "save as". @@ -650,32 +654,35 @@ public class Sketch { } + /* public void saveCurrent() throws IOException { current.save(); calcModified(); } + */ /** - * Handles 'save as' for a sketch. + * Handles 'Save As' for a sketch. *

* This basically just duplicates the current sketch folder to * a new location, and then calls 'Save'. (needs to take the current * state of the open files and save them to the new folder.. * but not save over the old versions for the old sketch..) *

- * also removes the previously-generated .class and .jar files, + * Also removes the previously-generated .class and .jar files, * because they can cause trouble. */ public boolean saveAs() throws IOException { // get new name for folder - FileDialog fd = new FileDialog(editor, //new Frame(), + FileDialog fd = new FileDialog(editor, "Save sketch folder as...", FileDialog.SAVE); if (isReadOnly()) { // default to the sketchbook folder fd.setDirectory(Preferences.get("sketchbook.path")); } else { + // default to the parent folder of where this was fd.setDirectory(folder.getParent()); } fd.setFile(folder.getName()); @@ -704,8 +711,6 @@ public class Sketch { try { String newPath = newFolder.getCanonicalPath() + File.separator; String oldPath = folder.getCanonicalPath() + File.separator; - //System.out.println(newPath); - //System.out.println(oldPath); if (newPath.indexOf(oldPath) == 0) { Base.showWarning("How very Borges of you", @@ -721,9 +726,43 @@ public class Sketch { if (newFolder.exists()) { Base.removeDir(newFolder); } - // in fact, you can't do this on windows because it tries - // to go into the same folder, but it happens on osx a lot. + // in fact, you can't do this on windows because the file dialog + // will instead put you inside the folder, but it happens on osx a lot. + // now make a fresh copy of the folder + newFolder.mkdirs(); + + // grab the contents of the current tab before saving + // first get the contents of the editor text area + if (current.modified) { + current.program = editor.getText(); + } + + // save the other tabs to their new location + for (int i = 1; i < codeCount; i++) { + File newFile = new File(newFolder, code[i].file.getName()); + code[i].saveAs(newFile); + } + + // save the hidden code to its new location + for (int i = 0; i < hiddenCount; i++) { + File newFile = new File(newFolder, hidden[i].file.getName()); + hidden[i].saveAs(newFile); + } + + // re-copy the data folder (this may take a while.. add progress bar?) + if (dataFolder.exists()) { + File newDataFolder = new File(newFolder, "data"); + Base.copyDir(dataFolder, newDataFolder); + } + + // save the main tab with its new name + File newFile = new File(newFolder, newName + ".pde"); + code[0].saveAs(newFile); + + editor.handleOpenUnchecked(newFile.getPath()); + + /* // copy the entire contents of the sketch folder Base.copyDir(folder, newFolder); @@ -771,6 +810,7 @@ public class Sketch { // update the tabs for the name change editor.header.repaint(); + */ // let Editor know that the save was successful return true; @@ -1358,25 +1398,13 @@ public class Sketch { zipFileContents = new Hashtable(); - boolean replaceHtml = true; - - // create the project directory - // pass null for datapath because the files shouldn't be - // copied to the build dir.. that's only for the temp stuff - File appletDir = new File(folder, "applet"); - - boolean writeHtml = true; - if (appletDir.exists()) { - File htmlFile = new File(appletDir, "index.html"); - if (htmlFile.exists() && !replaceHtml) { - writeHtml = false; - } - } else { - appletDir.mkdirs(); - } + // nuke the old applet folder because it can cause trouble + File appletFolder = new File(folder, "applet"); + Base.removeDir(appletFolder); + appletFolder.mkdirs(); // build the sketch - String foundName = build(appletDir.getPath(), name); + String foundName = build(appletFolder.getPath(), name); // (already reported) error during export, exit this function if (foundName == null) return false; @@ -1390,148 +1418,146 @@ public class Sketch { return false; } - if (writeHtml) { - int wide = PApplet.DEFAULT_WIDTH; - int high = PApplet.DEFAULT_HEIGHT; + int wide = PApplet.DEFAULT_WIDTH; + int high = PApplet.DEFAULT_HEIGHT; - PatternMatcher matcher = new Perl5Matcher(); - PatternCompiler compiler = new Perl5Compiler(); + PatternMatcher matcher = new Perl5Matcher(); + PatternCompiler compiler = new Perl5Compiler(); - // this matches against any uses of the size() function, - // whether they contain numbers of variables or whatever. - // this way, no warning is shown if size() isn't actually - // used in the applet, which is the case especially for - // beginners that are cutting/pasting from the reference. - // modified for 83 to match size(XXX, ddd so that it'll - // properly handle size(200, 200) and size(200, 200, P3D) - String sizing = - "[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)"; - Pattern pattern = compiler.compile(sizing); + // this matches against any uses of the size() function, + // whether they contain numbers of variables or whatever. + // this way, no warning is shown if size() isn't actually + // used in the applet, which is the case especially for + // beginners that are cutting/pasting from the reference. + // modified for 83 to match size(XXX, ddd so that it'll + // properly handle size(200, 200) and size(200, 200, P3D) + String sizing = + "[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)"; + Pattern pattern = compiler.compile(sizing); - // adds a space at the beginning, in case size() is the very - // first thing in the program (very common), since the regexp - // needs to check for things in front of it. - PatternMatcherInput input = - new PatternMatcherInput(" " + code[0].program); - if (matcher.contains(input, pattern)) { - MatchResult result = matcher.getMatch(); - try { - wide = Integer.parseInt(result.group(1).toString()); - high = Integer.parseInt(result.group(2).toString()); + // adds a space at the beginning, in case size() is the very + // first thing in the program (very common), since the regexp + // needs to check for things in front of it. + PatternMatcherInput input = + new PatternMatcherInput(" " + code[0].program); + if (matcher.contains(input, pattern)) { + MatchResult result = matcher.getMatch(); + try { + wide = Integer.parseInt(result.group(1).toString()); + high = Integer.parseInt(result.group(2).toString()); - } catch (NumberFormatException e) { - // found a reference to size, but it didn't - // seem to contain numbers - final String message = - "The size of this applet could not automatically be\n" + - "determined from your code. You'll have to edit the\n" + - "HTML file to set the size of the applet."; + } catch (NumberFormatException e) { + // found a reference to size, but it didn't + // seem to contain numbers + final String message = + "The size of this applet could not automatically be\n" + + "determined from your code. You'll have to edit the\n" + + "HTML file to set the size of the applet."; - Base.showWarning("Could not find applet size", message, null); - } - } // else no size() command found + Base.showWarning("Could not find applet size", message, null); + } + } // else no size() command found - // originally tried to grab this with a regexp matcher, - // but it wouldn't span over multiple lines for the match. - // this could prolly be forced, but since that's the case - // better just to parse by hand. - StringBuffer dbuffer = new StringBuffer(); - String lines[] = PApplet.split(code[0].program, '\n'); - for (int i = 0; i < lines.length; i++) { - if (lines[i].trim().startsWith("/**")) { // this is our comment - // some smartass put the whole thing on the same line - //if (lines[j].indexOf("*/") != -1) break; + // originally tried to grab this with a regexp matcher, + // but it wouldn't span over multiple lines for the match. + // this could prolly be forced, but since that's the case + // better just to parse by hand. + StringBuffer dbuffer = new StringBuffer(); + String lines[] = PApplet.split(code[0].program, '\n'); + for (int i = 0; i < lines.length; i++) { + if (lines[i].trim().startsWith("/**")) { // this is our comment + // some smartass put the whole thing on the same line + //if (lines[j].indexOf("*/") != -1) break; - for (int j = i+1; j < lines.length; j++) { - if (lines[j].trim().endsWith("*/")) { - // remove the */ from the end, and any extra *s - // in case there's also content on this line - // nah, don't bother.. make them use the three lines - break; - } - - int offset = 0; - while ((offset < lines[j].length()) && - ((lines[j].charAt(offset) == '*') || - (lines[j].charAt(offset) == ' '))) { - offset++; - } - // insert the return into the html to help w/ line breaks - dbuffer.append(lines[j].substring(offset) + "\n"); + for (int j = i+1; j < lines.length; j++) { + if (lines[j].trim().endsWith("*/")) { + // remove the */ from the end, and any extra *s + // in case there's also content on this line + // nah, don't bother.. make them use the three lines + break; } + + int offset = 0; + while ((offset < lines[j].length()) && + ((lines[j].charAt(offset) == '*') || + (lines[j].charAt(offset) == ' '))) { + offset++; + } + // insert the return into the html to help w/ line breaks + dbuffer.append(lines[j].substring(offset) + "\n"); } } - String description = dbuffer.toString(); - - StringBuffer sources = new StringBuffer(); - for (int i = 0; i < codeCount; i++) { - sources.append("" + - code[i].name + " "); - } - - File htmlOutputFile = new File(appletDir, "index.html"); - FileOutputStream fos = new FileOutputStream(htmlOutputFile); - PrintStream ps = new PrintStream(fos); - - // @@sketch@@, @@width@@, @@height@@, @@archive@@, @@source@@ - // and now @@description@@ - - InputStream is = null; - // if there is an applet.html file in the sketch folder, use that - File customHtml = new File(folder, "applet.html"); - if (customHtml.exists()) { - is = new FileInputStream(customHtml); - } - if (is == null) { - is = Base.getStream("applet.html"); - } - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - - String line = null; - while ((line = reader.readLine()) != null) { - if (line.indexOf("@@") != -1) { - StringBuffer sb = new StringBuffer(line); - int index = 0; - while ((index = sb.indexOf("@@sketch@@")) != -1) { - sb.replace(index, index + "@@sketch@@".length(), - name); - } - while ((index = sb.indexOf("@@source@@")) != -1) { - sb.replace(index, index + "@@source@@".length(), - sources.toString()); - } - while ((index = sb.indexOf("@@archive@@")) != -1) { - sb.replace(index, index + "@@archive@@".length(), - name + ".jar"); - } - while ((index = sb.indexOf("@@width@@")) != -1) { - sb.replace(index, index + "@@width@@".length(), - String.valueOf(wide)); - } - while ((index = sb.indexOf("@@height@@")) != -1) { - sb.replace(index, index + "@@height@@".length(), - String.valueOf(high)); - } - while ((index = sb.indexOf("@@description@@")) != -1) { - sb.replace(index, index + "@@description@@".length(), - description); - } - line = sb.toString(); - } - ps.println(line); - } - - reader.close(); - ps.flush(); - ps.close(); } + String description = dbuffer.toString(); + + StringBuffer sources = new StringBuffer(); + for (int i = 0; i < codeCount; i++) { + sources.append("" + + code[i].name + " "); + } + + File htmlOutputFile = new File(appletFolder, "index.html"); + FileOutputStream fos = new FileOutputStream(htmlOutputFile); + PrintStream ps = new PrintStream(fos); + + // @@sketch@@, @@width@@, @@height@@, @@archive@@, @@source@@ + // and now @@description@@ + + InputStream is = null; + // if there is an applet.html file in the sketch folder, use that + File customHtml = new File(folder, "applet.html"); + if (customHtml.exists()) { + is = new FileInputStream(customHtml); + } + if (is == null) { + is = Base.getStream("applet.html"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + + String line = null; + while ((line = reader.readLine()) != null) { + if (line.indexOf("@@") != -1) { + StringBuffer sb = new StringBuffer(line); + int index = 0; + while ((index = sb.indexOf("@@sketch@@")) != -1) { + sb.replace(index, index + "@@sketch@@".length(), + name); + } + while ((index = sb.indexOf("@@source@@")) != -1) { + sb.replace(index, index + "@@source@@".length(), + sources.toString()); + } + while ((index = sb.indexOf("@@archive@@")) != -1) { + sb.replace(index, index + "@@archive@@".length(), + name + ".jar"); + } + while ((index = sb.indexOf("@@width@@")) != -1) { + sb.replace(index, index + "@@width@@".length(), + String.valueOf(wide)); + } + while ((index = sb.indexOf("@@height@@")) != -1) { + sb.replace(index, index + "@@height@@".length(), + String.valueOf(high)); + } + while ((index = sb.indexOf("@@description@@")) != -1) { + sb.replace(index, index + "@@description@@".length(), + description); + } + line = sb.toString(); + } + ps.println(line); + } + + reader.close(); + ps.flush(); + ps.close(); // copy the source files to the target, since we like // to encourage people to share their code for (int i = 0; i < codeCount; i++) { try { Base.copyFile(code[i].file, - new File(appletDir, code[i].file.getName())); + new File(appletFolder, code[i].file.getName())); } catch (IOException e) { e.printStackTrace(); } @@ -1539,7 +1565,7 @@ public class Sketch { // create new .jar file FileOutputStream zipOutputFile = - new FileOutputStream(new File(appletDir, name + ".jar")); + new FileOutputStream(new File(appletFolder, name + ".jar")); ZipOutputStream zos = new ZipOutputStream(zipOutputFile); ZipEntry entry; @@ -1597,7 +1623,7 @@ public class Sketch { } else { // just copy the file over.. prolly a .dll or something Base.copyFile(exportFile, - new File(appletDir, exportFile.getName())); + new File(appletFolder, exportFile.getName())); } } } @@ -1626,12 +1652,12 @@ public class Sketch { // since there may be some inner classes // (add any .class files from the applet dir, then delete them) // TODO this needs to be recursive (for packages) - String classfiles[] = appletDir.list(); + String classfiles[] = appletFolder.list(); for (int i = 0; i < classfiles.length; i++) { if (classfiles[i].endsWith(".class")) { entry = new ZipEntry(classfiles[i]); zos.putNextEntry(entry); - zos.write(Base.grabFile(new File(appletDir, classfiles[i]))); + zos.write(Base.grabFile(new File(appletFolder, classfiles[i]))); zos.closeEntry(); } } @@ -1641,7 +1667,7 @@ public class Sketch { // since the classes are outside the jar file. for (int i = 0; i < classfiles.length; i++) { if (classfiles[i].endsWith(".class")) { - File deadguy = new File(appletDir, classfiles[i]); + File deadguy = new File(appletFolder, classfiles[i]); if (!deadguy.delete()) { Base.showWarning("Could not delete", classfiles[i] + " could not \n" + @@ -1655,7 +1681,7 @@ public class Sketch { zos.flush(); zos.close(); - Base.openFolder(appletDir); + Base.openFolder(appletFolder); return true; } diff --git a/app/SketchCode.java b/app/SketchCode.java index 07d9b8905..7576a494d 100644 --- a/app/SketchCode.java +++ b/app/SketchCode.java @@ -79,4 +79,12 @@ public class SketchCode { Base.saveFile(program, file); modified = false; } + + + /** + * Save this file to another location, used by Sketch.saveAs() + */ + public void saveAs(File newFile) throws IOException { + Base.saveFile(program, newFile); + } } diff --git a/todo.txt b/todo.txt index 5d7a29248..d7d8b13ba 100644 --- a/todo.txt +++ b/todo.txt @@ -27,6 +27,10 @@ o gnu page for libiconv o http://www.gnu.org/software/libiconv/ X on 10.2, the version of jikes from 69 (the cvs build) works fine _ update the faq when doing the release +X additional requests for this (and it's an easy fix) +X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1114449442;start=0 +X maintain tab scroll and caret positions +X save caret position when switching tabs _ make simple tool for casey to rebuild all the examples at once _ need to rebuild with this release because of 1.3/1.4 issues @@ -137,14 +141,12 @@ _ problem with it launching a new thread for every single update! _ set applet.frame on runner, so ppl can mess with the frame itself +_ option to suppress warning dialogs +_ starting with the one about modifying the sketch name for spaces + _ osx is swallowing exceptions on external apps _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114520230;start=5 -_ additional requests for this (and it's an easy fix) -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1114449442;start=0 - 1 _ maintain tab scroll and caret positions - 1 _ save caret position when switching tabs - _ sun.applet.Main is appletviewer _ settings.path.fallback not being used