diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index e3d22f3fc..ac02fbe3a 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -46,9 +46,9 @@ import processing.mode.java.JavaMode; public class Base { // Added accessors for 0218 because the UpdateCheck class was not properly // updating the values, due to javac inlining the static final values. - static private final int REVISION = 227; + static private final int REVISION = 228; /** This might be replaced by main() if there's a lib/version.txt file. */ - static private String VERSION_NAME = "0227"; //$NON-NLS-1$ + static private String VERSION_NAME = "0228"; //$NON-NLS-1$ /** Set true if this a proper release rather than a numbered revision. */ // static private boolean RELEASE = false; @@ -207,13 +207,11 @@ public class Base { // Prevent more than one copy of the PDE from running. SingleInstance.startServer(base); - } catch (Exception e) { + } catch (Throwable t) { // Catch-all to hopefully pick up some of the weirdness we've been // running into lately. - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - Base.showError("We're off on the wrong foot", - "An error occurred during startup.\n" + sw, e); + showBadnessTrace("We're off on the wrong foot", + "An error occurred during startup.", t, true); } log("done creating base..."); //$NON-NLS-1$ } @@ -921,79 +919,88 @@ public class Base { // protected Editor handleOpen(String path, int[] location) { // protected Editor handleOpen(String path, Rectangle bounds, int divider) { protected Editor handleOpen(String path, boolean untitled, EditorState state) { - // System.err.println("entering handleOpen " + path); + try { + // System.err.println("entering handleOpen " + path); - final File file = new File(path); - if (!file.exists()) { - return null; - } - - // System.err.println(" editors: " + editors); - // Cycle through open windows to make sure that it's not already open. - for (Editor editor : editors) { - if (editor.getSketch().getMainFile().equals(file)) { - editor.toFront(); - // move back to the top of the recent list - handleRecent(editor); - return editor; - } - } - - if (!Sketch.isSanitaryName(file.getName())) { - Base.showWarning("You're tricky, but not tricky enough", - file.getName() + " is not a valid name for a sketch.\n" + - "Better to stick to ASCII, no spaces, and make sure\n" + - "it doesn't start with a number.", null); - return null; - } - - if (!nextMode.canEdit(file)) { - final Mode mode = selectMode(file); - if (mode == null) { + final File file = new File(path); + if (!file.exists()) { return null; } - nextMode = mode; - } + + // System.err.println(" editors: " + editors); + // Cycle through open windows to make sure that it's not already open. + for (Editor editor : editors) { + if (editor.getSketch().getMainFile().equals(file)) { + editor.toFront(); + // move back to the top of the recent list + handleRecent(editor); + return editor; + } + } + + if (!Sketch.isSanitaryName(file.getName())) { + Base.showWarning("You're tricky, but not tricky enough", + file.getName() + " is not a valid name for a sketch.\n" + + "Better to stick to ASCII, no spaces, and make sure\n" + + "it doesn't start with a number.", null); + return null; + } + + if (!nextMode.canEdit(file)) { + final Mode mode = selectMode(file); + if (mode == null) { + return null; + } + nextMode = mode; + } // Editor.State state = new Editor.State(editors); - Editor editor = nextMode.createEditor(this, path, state); - if (editor == null) { - // if it's the last editor window + Editor editor = nextMode.createEditor(this, path, state); + if (editor == null) { + // if it's the last editor window // if (editors.size() == 0 && defaultFileMenu == null) { - // if it's not mode[0] already, then don't go into an infinite loop - // trying to recreate a window with the default mode. - if (nextMode == coreModes[0]) { - Base.showError("Editor Problems", - "An error occurred while trying to change modes.\n" + - "We'll have to quit for now because it's an\n" + - "unfortunate bit of indigestion.", - null); - } else { - editor = coreModes[0].createEditor(this, path, state); + // if it's not mode[0] already, then don't go into an infinite loop + // trying to recreate a window with the default mode. + if (nextMode == coreModes[0]) { + Base.showError("Editor Problems", + "An error occurred while trying to change modes.\n" + + "We'll have to quit for now because it's an\n" + + "unfortunate bit of indigestion.", + null); + } else { + editor = coreModes[0].createEditor(this, path, state); + } } - } - // Make sure that the sketch actually loaded - if (editor.getSketch() == null) { + // Make sure that the sketch actually loaded + if (editor.getSketch() == null) { // System.err.println("sketch was null, getting out of handleOpen"); - return null; // Just walk away quietly - } + return null; // Just walk away quietly + } // editor.untitled = untitled; - editor.getSketch().setUntitled(untitled); - editors.add(editor); - handleRecent(editor); + editor.getSketch().setUntitled(untitled); + editors.add(editor); + handleRecent(editor); - // now that we're ready, show the window - // (don't do earlier, cuz we might move it based on a window being closed) - editor.setVisible(true); + // now that we're ready, show the window + // (don't do earlier, cuz we might move it based on a window being closed) + editor.setVisible(true); - return editor; + return editor; + + } catch (Throwable t) { + showBadnessTrace("Terrible News", + "A serious error occurred while " + + "trying to create a new editor window.", t, false); + nextMode = coreModes[0]; + return null; + } } + private static class ModeInfo { public final String title; - public final String id; public ModeInfo(String id, String title) { @@ -1002,6 +1009,7 @@ public class Base { } } + private static ModeInfo modeInfoFor(final File sketch) { final File sketchFolder = sketch.getParentFile(); final File sketchProps = new File(sketchFolder, "sketch.properties"); @@ -1023,6 +1031,7 @@ public class Base { return null; } + private Mode promptForMode(final File sketch, final ModeInfo preferredMode) { final String extension = sketch.getName().substring(sketch.getName().lastIndexOf('.') + 1); @@ -1065,6 +1074,7 @@ public class Base { null, modes, modes[0]); } + private Mode selectMode(final File sketch) { final ModeInfo modeInfo = modeInfoFor(sketch); final Mode specifiedMode = modeInfo == null ? null : findMode(modeInfo.id); @@ -1074,6 +1084,7 @@ public class Base { return promptForMode(sketch, modeInfo); } + protected Mode findMode(String id) { for (Mode mode : getModeList()) { if (mode.getIdentifier().equals(id)) { @@ -1083,6 +1094,7 @@ public class Base { return null; } + /** * Close a sketch as specified by its editor window. * @param editor Editor object of the sketch to be closed. @@ -2255,6 +2267,35 @@ public class Base { } + /** + * Testing a new warning window that includes the stack trace. + */ + static private void showBadnessTrace(String title, String message, + Throwable t, boolean fatal) { + if (title == null) title = fatal ? "Error" : "Warning"; + + if (commandLine) { + System.err.println(title + ": " + message); + if (t != null) { + t.printStackTrace(); + } + + } else { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + // Necessary to replace \n with
(even if pre) otherwise Java + // treats it as a closed tag and reverts to plain formatting. + message = "" + message + "

" + + sw.toString().replaceAll("\n", "
"); + + JOptionPane.showMessageDialog(new Frame(), message, title, + fatal ? + JOptionPane.ERROR_MESSAGE : + JOptionPane.WARNING_MESSAGE); + } + } + + // ................................................................... @@ -2486,7 +2527,8 @@ public class Base { //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { - return name.endsWith(".jdk") && dir.isDirectory(); + return dir.isDirectory() && + name.endsWith(".jdk") && !name.startsWith("."); } }); return new File(plugins[0], "Contents/Home/jre"); diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 357621714..34aa23834 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -24,6 +24,7 @@ package processing.app; import java.awt.Dimension; import java.awt.Font; import java.awt.FontFormatException; +import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsDevice; @@ -152,12 +153,12 @@ public class Toolkit { static ArrayList iconImages; - // Removed in favor of Window being the base object, so that dialogs can - // be supported as well. If this breaks tools/modes, we can bring it back, - // but it was essentially an undocumented feature. -// static public void setIcon(Frame frame) { -// setIcon(frame); -// } + // Deprecated version of the function, but can't get rid of it without + // breaking tools and modes (they'd only require a recompile, but they would + // no longer be backwards compatible. + static public void setIcon(Frame frame) { + setIcon((Window) frame); + } /** @@ -167,10 +168,6 @@ public class Toolkit { */ static public void setIcon(Window window) { if (!Base.isMacOS()) { -// // too low-res, prepping for nicer icons in 2.0 timeframe -// Image image = awtToolkit.createImage(PApplet.ICON_IMAGE); -// frame.setIconImage(image); - if (iconImages == null) { iconImages = new ArrayList(); final int[] sizes = { 16, 32, 48, 64, 128, 256, 512 }; diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java index b4cb57cd4..a815ab6da 100644 --- a/app/src/processing/app/contrib/AvailableContribution.java +++ b/app/src/processing/app/contrib/AvailableContribution.java @@ -48,7 +48,10 @@ class AvailableContribution extends Contribution { url = params.get("url"); sentence = params.get("sentence"); paragraph = params.get("paragraph"); - version = PApplet.parseInt(params.get("version"), 0); + String versionStr = params.get("version"); + if (versionStr != null) { + version = PApplet.parseInt(versionStr, 0); + } prettyVersion = params.get("prettyVersion"); } diff --git a/app/src/processing/app/tools/Archiver.java b/app/src/processing/app/tools/Archiver.java index ab2a3e424..4e34b9748 100644 --- a/app/src/processing/app/tools/Archiver.java +++ b/app/src/processing/app/tools/Archiver.java @@ -102,6 +102,11 @@ public class Archiver implements Tool { public void fileSelected(File newbie) { if (newbie != null) { try { + // Force a .zip extension + // https://github.com/processing/processing/issues/2526 + if (!newbie.getName().toLowerCase().endsWith(".zip")) { + newbie = new File(newbie.getAbsolutePath() + ".zip"); + } //System.out.println(newbie); FileOutputStream zipOutputFile = new FileOutputStream(newbie); ZipOutputStream zos = new ZipOutputStream(zipOutputFile); diff --git a/app/src/processing/mode/java/AutoFormat.java b/app/src/processing/mode/java/AutoFormat.java index 935e2a903..91d8a7cec 100644 --- a/app/src/processing/mode/java/AutoFormat.java +++ b/app/src/processing/mode/java/AutoFormat.java @@ -38,56 +38,62 @@ import processing.core.PApplet; *

* After some further digging, this code in fact appears to be a modified * version of Jason Pell's GPLed "Java Beautifier" class found - * here. - * Which is itself based on code from Van Di-Han Ho from - * here. + * here, + * which is itself based on code from Van Di-Han Ho from + * here. * [Ben Fry, August 2009] */ public class AutoFormat implements Formatter { private char[] chars; private final StringBuilder buf = new StringBuilder(); - private final StringBuilder result = new StringBuilder(); private int indentValue; private boolean EOF; - private boolean a_flg, e_flg, if_flg, s_flag, q_flg; - private boolean s_if_flg[]; + private boolean a_flg, if_flg, s_flag, elseFlag; + + /** Number of ? entered without exiting at : of a?b:c structures. */ + private int conditionalLevel; + private int pos; -// private int lineNumber; - private int s_level[]; private int c_level; - private int sp_flg[][]; - private int s_ind[][]; - private int s_if_lev[]; - private int if_lev, level; - private int ind[]; - private int paren; - private int p_flg[]; + private int[][] sp_flg; + private int[][] s_ind; + private int if_lev; + + /** Number of curly brackets entered and not exited. */ + private int level; + + /** Number of parentheses entered and not exited. */ + private int parenLevel; + + private int[] ind; + private int[] p_flg; private char l_char; - private int ct; - private int s_tabs[][]; + private int[][] s_tabs; private boolean jdoc_flag; private char cc; private int tabs; private char c; + private char lastNonWhitespace = 0; private final Stack castFlags = new Stack(); - private void comment() { - final boolean save_s_flg = s_flag; + private void handleMultiLineComment() { + final boolean saved_s_flag = s_flag; - buf.append(c = next()); // extra char + char ch; + buf.append(ch = nextChar()); // extra char while (true) { - buf.append(c = next()); - while ((c != '/')) { - if (c == '\n') { -// lineNumber++; + buf.append(ch = nextChar()); + while (ch != '/') { + if (ch == '\n') { +// lineNumber++; writeIndentedComment(); s_flag = true; } - buf.append(c = next()); + buf.append(ch = nextChar()); } if (buf.length() >= 2 && buf.charAt(buf.length() - 2) == '*') { jdoc_flag = false; @@ -96,50 +102,65 @@ public class AutoFormat implements Formatter { } writeIndentedComment(); - s_flag = save_s_flg; + s_flag = saved_s_flag; jdoc_flag = false; return; } - - private char get_string() { - char ch; - while (true) { - buf.append(ch = next()); - if (ch == '\\') { - buf.append(next()); - continue; - } - if (ch == '\'' || ch == '"') { - buf.append(cc = next()); - while (!EOF && cc != ch) { - if (cc == '\\') { - buf.append(next()); - } - buf.append(cc = next()); - } - continue; - } - if (ch == '\n') { - writeIndentedLine(); - a_flg = true; - continue; - } - return ch; + + private void handleSingleLineComment() { + char ch = nextChar(); + while (ch != '\n') { + buf.append(ch); + ch = nextChar(); } +// lineNumber++; + writeIndentedLine(); + s_flag = true; } + +// /** +// * Transfers buf to result until a character is reached that +// * is neither \, \n, or in a string. \n is not written, but +// * writeIndentedLine is called on finding it. +// * @return The first character not listed above. +// */ +// private char get_string() { +// char ch1, ch2; +// while (true) { +// buf.append(ch1 = nextChar()); +// if (ch1 == '\\') { +// buf.append(nextChar()); +// } else if (ch1 == '\'' || ch1 == '\"') { +// buf.append(ch2 = nextChar()); +// while (!EOF && ch2 != ch1) { +// if (ch2 == '\\') { +// // Next char is escaped, ignore. +// buf.append(nextChar()); +// } +// buf.append(ch2 = nextChar()); +// } +// } else if (ch1 == '\n') { +// writeIndentedLine(); +// a_flg = true; +// } else { +// return ch1; +// } +// } +// } + private void writeIndentedLine() { if (buf.length() == 0) { if (s_flag) { - s_flag = a_flg = e_flg = false; + s_flag = a_flg = elseFlag = false; } return; } if (s_flag) { - final boolean shouldIndent = (tabs > 0) && (buf.charAt(0) != '{') - && a_flg; + final boolean shouldIndent = + (tabs > 0) && (buf.charAt(0) != '{') && a_flg; if (shouldIndent) { tabs++; } @@ -150,23 +171,22 @@ public class AutoFormat implements Formatter { } a_flg = false; } - if (e_flg) { + if (elseFlag) { if (lastNonSpaceChar() == '}') { trimRight(result); - result.append(" "); + result.append(' '); } - e_flg = false; + elseFlag = false; } result.append(buf); buf.setLength(0); } - + private char lastNonSpaceChar() { - for (int i=result.length()-1; i>=0; i--) { + for (int i = result.length() - 1; i >= 0; i--) { char c_i = result.charAt(i); - if (c_i == ' ' || c_i == '\n') continue; - else return c_i; + if (c_i != ' ' && c_i != '\n') return c_i; } return 0; } @@ -187,7 +207,7 @@ public class AutoFormat implements Formatter { jdoc_flag = true; } if (buf.charAt(i) == '/' && buf.charAt(i + 1) == '*') { - if (saved_s_flag && prev() != ';') { + if (saved_s_flag && getLastNonWhitespace() != ';') { result.append(buf.substring(i)); } else { result.append(buf); @@ -204,18 +224,6 @@ public class AutoFormat implements Formatter { } - private void handleSingleLineComment() { - c = next(); - while (c != '\n') { - buf.append(c); - c = next(); - } -// lineNumber++; - writeIndentedLine(); - s_flag = true; - } - - private void printIndentation() { if (tabs < 0) { tabs = 0; @@ -225,7 +233,7 @@ public class AutoFormat implements Formatter { } final int spaces = tabs * indentValue; for (int k = 0; k < spaces; k++) { - result.append(" "); + result.append(' '); } } @@ -238,10 +246,7 @@ public class AutoFormat implements Formatter { } - private char lastNonWhitespace = 0; - - - private int prev() { + private int getLastNonWhitespace() { return lastNonWhitespace; } @@ -256,33 +261,32 @@ public class AutoFormat implements Formatter { if (pos == chars.length - 1) { EOF = true; } else { - pos--; // reset for next() + pos--; // reset for nextChar() } } - private char next() { + private char nextChar() { if (EOF) { - return 0; + return '\0'; } pos++; - final char c; + char retVal; if (pos < chars.length) { - c = chars[pos]; - if (!Character.isWhitespace(c)) - lastNonWhitespace = c; + retVal = chars[pos]; + if (!Character.isWhitespace(retVal)) + lastNonWhitespace = retVal; } else { - c = 0; + retVal = '\0'; } - if (pos == chars.length - 1) { + if (pos == chars.length-1) { EOF = true; } - return c; + return retVal; } - /* else processing */ - private void gotelse() { + private void gotElse() { tabs = s_tabs[c_level][if_lev]; p_flg[level] = sp_flg[c_level][if_lev]; ind[level] = s_ind[c_level][if_lev]; @@ -290,23 +294,22 @@ public class AutoFormat implements Formatter { } - /* read to new_line */ - private boolean getnl() { + private boolean readUntilNewLine() { final int savedTabs = tabs; char c = peek(); while (!EOF && (c == '\t' || c == ' ')) { - buf.append(next()); + buf.append(nextChar()); c = peek(); } if (c == '/') { - buf.append(next()); + buf.append(nextChar()); c = peek(); if (c == '*') { - buf.append(next()); - comment(); + buf.append(nextChar()); + handleMultiLineComment(); } else if (c == '/') { - buf.append(next()); + buf.append(nextChar()); handleSingleLineComment(); return true; } @@ -315,7 +318,7 @@ public class AutoFormat implements Formatter { c = peek(); if (c == '\n') { // eat it - next(); + nextChar(); // lineNumber++; tabs = savedTabs; return true; @@ -344,24 +347,25 @@ public class AutoFormat implements Formatter { public String format(final String source) { final String normalizedText = source.replaceAll("\r", ""); - final String cleanText = normalizedText - + (normalizedText.endsWith("\n") ? "" : "\n"); + final String cleanText = + normalizedText + (normalizedText.endsWith("\n") ? "" : "\n"); result.setLength(0); indentValue = Preferences.getInteger("editor.tabs.size"); -// lineNumber = 0; - q_flg = e_flg = a_flg = if_flg = false; +// lineNumber = 0; + boolean forFlag = a_flg = if_flg = false; s_flag = true; - c_level = if_lev = level = paren = 0; + int forParenthLevel = 0; + conditionalLevel = parenLevel = c_level = if_lev = level = 0; tabs = 0; jdoc_flag = false; - s_level = new int[10]; + int[] s_level = new int[10]; sp_flg = new int[20][10]; s_ind = new int[20][10]; - s_if_lev = new int[10]; - s_if_flg = new boolean[10]; + int[] s_if_lev = new int[10]; + boolean[] s_if_flg = new boolean[10]; ind = new int[10]; p_flg = new int[10]; s_tabs = new int[20][10]; @@ -369,10 +373,10 @@ public class AutoFormat implements Formatter { chars = cleanText.toCharArray(); // lineNumber = 1; - EOF = false; // set in next() when EOF + EOF = false; // set in nextChar() when EOF while (!EOF) { - c = next(); + c = nextChar(); switch (c) { default: buf.append(c); @@ -388,12 +392,13 @@ public class AutoFormat implements Formatter { case ' ': case '\t': - e_flg = lookup("else"); - if (e_flg) { - gotelse(); + elseFlag = lookup("else"); + if (elseFlag) { + gotElse(); if ((!s_flag) || buf.length() > 0) { buf.append(c); } + writeIndentedLine(); s_flag = false; break; @@ -408,9 +413,9 @@ public class AutoFormat implements Formatter { if (EOF) { break; } - e_flg = lookup("else"); - if (e_flg) { - gotelse(); + elseFlag = lookup("else"); + if (elseFlag) { + gotElse(); } if (lookup_com("//")) { final char lastChar = buf.charAt(buf.length() - 1); @@ -422,19 +427,18 @@ public class AutoFormat implements Formatter { writeIndentedLine(); result.append("\n"); s_flag = true; - if (e_flg) { + if (elseFlag) { p_flg[level]++; tabs++; - } else if (prev() == l_char) { + } else if (getLastNonWhitespace() == l_char) { a_flg = true; } break; case '{': - e_flg = lookup("else"); - if (e_flg) { - gotelse(); - } + elseFlag = lookup("else"); + if (elseFlag) gotElse(); + if (s_if_lev.length == c_level) { s_if_lev = PApplet.expand(s_if_lev); s_if_flg = PApplet.expand(s_if_flg); @@ -454,9 +458,9 @@ public class AutoFormat implements Formatter { buf.append(" "); buf.append(c); writeIndentedLine(); - getnl(); + readUntilNewLine(); writeIndentedLine(); - //fprintf(outfil,"\n"); + result.append("\n"); tabs++; s_flag = true; @@ -489,11 +493,12 @@ public class AutoFormat implements Formatter { printIndentation(); result.append(c); if (peek() == ';') { - result.append(next()); + result.append(nextChar()); } - getnl(); + + readUntilNewLine(); writeIndentedLine(); - result.append("\n"); + result.append('\n'); s_flag = true; if (c_level < s_level[level]) { if (level > 0) { @@ -511,21 +516,21 @@ public class AutoFormat implements Formatter { case '"': case '\'': buf.append(c); - cc = next(); + cc = nextChar(); while (!EOF && cc != c) { buf.append(cc); if (cc == '\\') { - buf.append(cc = next()); + buf.append(cc = nextChar()); } if (cc == '\n') { // lineNumber++; writeIndentedLine(); s_flag = true; } - cc = next(); + cc = nextChar(); } buf.append(cc); - if (getnl()) { + if (readUntilNewLine()) { l_char = cc; // push a newline into the stream chars[pos--] = '\n'; @@ -533,13 +538,21 @@ public class AutoFormat implements Formatter { break; case ';': + if (forFlag) { + // This is like a comma. + trimRight(buf); + buf.append("; "); + // Not non-whitespace: allow \n. + advanceToNonSpace(); + break; + } buf.append(c); writeIndentedLine(); if (p_flg[level] > 0 && ind[level] == 0) { tabs -= p_flg[level]; p_flg[level] = 0; } - getnl(); + readUntilNewLine(); writeIndentedLine(); result.append("\n"); s_flag = true; @@ -555,26 +568,39 @@ public class AutoFormat implements Formatter { case '\\': buf.append(c); - buf.append(next()); + buf.append(nextChar()); break; case '?': - q_flg = true; + conditionalLevel++; buf.append(c); break; case ':': - buf.append(c); + // Java 8 :: operator. if (peek() == ':') { writeIndentedLine(); - result.append(next()); + result.append(c).append(nextChar()); break; } - if (q_flg) { - q_flg = false; + // End a?b:c structures. + else if (conditionalLevel>0) { + conditionalLevel--; + buf.append(c); break; } + + else if (forFlag) { + trimRight(buf); + buf.append(" : "); + // Not to non-whitespace: allow \n. + advanceToNonSpace(); + break; + } + + buf.append(c); + if (!lookup("default") && !lookup("case")) { s_flag = false; writeIndentedLine(); @@ -584,26 +610,27 @@ public class AutoFormat implements Formatter { tabs++; } if (peek() == ';') { - result.append(next()); + result.append(nextChar()); } - getnl(); + readUntilNewLine(); writeIndentedLine(); - result.append("\n"); + result.append('\n'); s_flag = true; break; case '/': - final char la = peek(); - if (la == '/') { - buf.append(c).append(next()); + final char next = peek(); + if (next == '/') { + // call nextChar to move on. + buf.append(c).append(nextChar()); handleSingleLineComment(); result.append("\n"); - } else if (la == '*') { + } else if (next == '*') { if (buf.length() > 0) { writeIndentedLine(); } - buf.append(c).append(next()); - comment(); + buf.append(c).append(nextChar()); + handleMultiLineComment(); } else { buf.append(c); } @@ -613,15 +640,23 @@ public class AutoFormat implements Formatter { final boolean isCast = castFlags.isEmpty() ? false : castFlags.pop(); - paren--; - if (paren < 0) { - paren = 0; + parenLevel--; + + // If we're further back than the start of a for loop, we've + // left it. + if (forFlag && forParenthLevel > parenLevel) { + forFlag = false; } + + if (parenLevel < 0) { + parenLevel = 0; + } + buf.append(c); writeIndentedLine(); - if (getnl()) { + if (readUntilNewLine()) { chars[pos--] = '\n'; - if (paren != 0) { + if (parenLevel != 0) { a_flg = true; } else if (tabs > 0 && !isCast) { p_flg[level]++; @@ -644,42 +679,16 @@ public class AutoFormat implements Formatter { } buf.append(c); - paren++; + parenLevel++; + // isFor says "is it the start of a for?". If it is, we set forFlag and + // forParenthLevel. If it is not parenth_lvl was incremented above and + // that's it. if (isFor) { - // TODO(feinberg): handle new-style for loops - c = get_string(); - while (c != ';' && c != ':') { - c = get_string(); + if (!forFlag) { + forParenthLevel = parenLevel; + forFlag = true; } - ct = 0; - int for_done = 0; - while (for_done == 0) { - c = get_string(); - while (c != ')') { - if (c == '(') { - ct++; - } - c = get_string(); - } - if (ct != 0) { - ct--; - } else { - for_done = 1; - } - } // endwhile for_done - paren--; - if (paren < 0) { - paren = 0; - } - writeIndentedLine(); - if (getnl()) { - chars[pos--] = '\n'; - p_flg[level]++; - tabs++; - ind[level] = 0; - } - break; } else if (isIf) { writeIndentedLine(); s_tabs[c_level][if_lev] = tabs; diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 32f287df0..4b6516220 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,3 +1,47 @@ +PROCESSING 2.2.1 (REV 0227) - 19 May 2014 + +A handful of bug fixes, the most prominent rolls back a change that broke +PDE X and other Modes and Tools. + ++ Bring back setIcon(Frame) for PDE X and others + https://github.com/processing/processing-experimental/issues/64 + ++ Add additional code for crashing when the Mode is changed or new editor + windows opened. + ++ Use mouseReleased() instead of mousePressed() in the color selector, + otherwise it registers the release as a click in the color window + https://github.com/processing/processing/issues/2514 + ++ Missing 'version' in contribution properties file causes NullPointerException + https://github.com/processing/processing/issues/2517 + ++ A handful of fixes to Auto Format + https://github.com/processing/processing/pull/2271 + ++ Command line tools not working on OS X due to AppleDouble file boogers. + https://github.com/processing/processing/issues/2520 + ++ Make "Archive Sketch" Tool force a .zip file extension + https://github.com/processing/processing/issues/2526 + ++ Event handling modifications in video and serial libraries w/ Python Mode + https://github.com/processing/processing/pull/2527 + https://github.com/processing/processing/pull/2528 + https://github.com/processing/processing/pull/2529 + ++ Permit mouse PRESS to set mouseX/mouseY + https://github.com/processing/processing/pull/2509 + ++ Fix for video: the loop() method was broken in the last release. + https://github.com/processing/processing/issues/2524 + ++ Updated reference files included in the download. + + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + PROCESSING 2.2 (REV 0226) - 12 May 2014 Major changes to, and improvements upon, how "Export to Application" works. diff --git a/core/done.txt b/core/done.txt index 99dda8671..694933b4b 100644 --- a/core/done.txt +++ b/core/done.txt @@ -1,3 +1,10 @@ +0227 core (2.2.1) +X Permit mouse PRESS to set mouseX/mouseY +X https://github.com/processing/processing/pull/2509 +A Fix for video, loop() broken in 2.2 +A https://github.com/processing/processing/issues/2524 + + 0226 core (2.2) X fix parsing with missing categorical values X fix for splice() throwing a ClassCastException with other object types diff --git a/core/todo.txt b/core/todo.txt index abe9963fe..ea362845a 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,7 +1,11 @@ -0227 core +0228 core high +_ pull for image resize and alpha issues +_ https://github.com/processing/processing/pull/2324 +_ dataPath() not working when app is not run from app dir on Linux +_ https://github.com/processing/processing/issues/2195 _ "Buffers have not been created" error for sketches w/o draw() _ https://github.com/processing/processing/issues/2469 _ could not reproduce diff --git a/done.txt b/done.txt index 172d7230a..225f3aa3a 100644 --- a/done.txt +++ b/done.txt @@ -1,3 +1,29 @@ +0227 pde (2.2.1) +X use mouseReleased() instead of mousePressed() in color selector +X otherwise it registers the release as a click in the color window +X https://github.com/processing/processing/issues/2514 +X missing 'version' in contrib causes NPE +X https://github.com/processing/processing/issues/2517 +X bring back setIcon(Frame) for PDE X and others +X https://github.com/processing/processing-experimental/issues/64 +X how was PDE X able to crash 2.2? +X add additional code to rework how this is handled +X Auto Format patch mess +X https://github.com/processing/processing/pull/2271 +X why is the JDK path showing up as a ._ feller in OS X? +X https://github.com/processing/processing/issues/2520 +X "Archive Sketch" Tool doesn't force a .zip file extension +X https://github.com/processing/processing/issues/2526 + +python +J modifications for captureEvent and Python +J https://github.com/processing/processing/pull/2527 +J Permit implementing movieEvent without having to link to Movie at build time +J https://github.com/processing/processing/pull/2528 +J implement serial events without having to link to Serial at build time +J https://github.com/processing/processing/pull/2529 + + 0226 pde (2.2) X sketches only starting once, or half-starting and hanging X https://github.com/processing/processing/issues/2402 diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index befad4afa..f473f863d 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -112,15 +112,21 @@ public class Serial implements SerialPortEventListener { throw new RuntimeException("Error opening serial port " + e.getPortName() + ": " + e.getExceptionType()); } - try { - serialEventMethod = parent.getClass().getMethod("serialEvent", new Class[] { this.getClass() }); - } catch (Exception e) { - } + serialEventMethod = findCallback("serialEvent"); + serialAvailableMethod = findCallback("serialAvailable"); + } + private Method findCallback(final String name) { try { - serialAvailableMethod = parent.getClass().getMethod("serialAvailable", new Class[] { this.getClass() }); + return parent.getClass().getMethod(name, this.getClass()); } catch (Exception e) { } + // Permit callback(Object) as alternative to callback(Serial). + try { + return parent.getClass().getMethod(name, Object.class); + } catch (Exception e) { + } + return null; } @@ -133,7 +139,7 @@ public class Serial implements SerialPortEventListener { if (serialAvailableMethod != null && invokeSerialAvailable) { invokeSerialAvailable = false; try { - serialAvailableMethod.invoke(parent, new Object[] { this }); + serialAvailableMethod.invoke(parent, this); } catch (Exception e) { System.err.println("Error, disabling serialAvailable() for "+port.getPortName()); System.err.println(e.getLocalizedMessage()); @@ -392,7 +398,7 @@ public class Serial implements SerialPortEventListener { // available() and read() inside draw - but this function has no // thread-safety issues since it's being invoked during pre in the context // of the Processing applet - serialEventMethod.invoke(parent, new Object[] { this }); + serialEventMethod.invoke(parent, this); } catch (Exception e) { System.err.println("Error, disabling serialEvent() for "+port.getPortName()); System.err.println(e.getLocalizedMessage()); diff --git a/java/libraries/video/src/processing/video/Capture.java b/java/libraries/video/src/processing/video/Capture.java index 8f233b9c5..5d4221fb5 100644 --- a/java/libraries/video/src/processing/video/Capture.java +++ b/java/libraries/video/src/processing/video/Capture.java @@ -112,7 +112,7 @@ public class Capture extends PImage implements PConstants { protected Method sinkCopyMethod; protected Method sinkSetMethod; protected Method sinkDisposeMethod; - protected Method sinkGetMethod; + protected Method sinkGetMethod; protected String copyMask; protected Buffer natBuffer = null; protected BufferDataAppSink natSink = null; @@ -239,7 +239,7 @@ public class Capture extends PImage implements PConstants { /** * Disposes all the native resources associated to this capture device. - * + * * NOTE: This is not official API and may/will be removed at any time. */ public void dispose() { @@ -271,10 +271,10 @@ public class Capture extends PImage implements PConstants { pipeline.dispose(); pipeline = null; - + parent.g.removeCache(this); parent.unregisterMethod("dispose", this); - parent.unregisterMethod("post", this); + parent.unregisterMethod("post", this); } } @@ -308,11 +308,11 @@ public class Capture extends PImage implements PConstants { /** * ( begin auto-generated from Capture_start.xml ) - * + * * Starts capturing frames from the selected device. - * + * * ( end auto-generated ) - * + * * @webref capture * @brief Starts capturing frames from the selected device */ @@ -425,7 +425,7 @@ public class Capture extends PImage implements PConstants { newFrame = true; } - + public synchronized void loadPixels() { super.loadPixels(); if (useBufferSink) { @@ -441,24 +441,24 @@ public class Capture extends PImage implements PConstants { try { // sinkGetMethod will copy the latest buffer to the pixels array, // and the pixels will be copied to the texture when the OpenGL - // renderer needs to draw it. - sinkGetMethod.invoke(bufferSink, new Object[] { pixels }); + // renderer needs to draw it. + sinkGetMethod.invoke(bufferSink, new Object[] { pixels }); } catch (Exception e) { e.printStackTrace(); - } - } + } + } - outdatedPixels = false; + outdatedPixels = false; } } - - + + public int get(int x, int y) { if (outdatedPixels) loadPixels(); return super.get(x, y); } - - + + protected void getImpl(int sourceX, int sourceY, int sourceWidth, int sourceHeight, PImage target, int targetX, int targetY) { @@ -466,8 +466,8 @@ public class Capture extends PImage implements PConstants { super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight, target, targetX, targetY); } - - + + //////////////////////////////////////////////////////////// // List methods. @@ -966,7 +966,7 @@ public class Capture extends PImage implements PConstants { /** * Uses a generic object as handler of the capture. This object should have a - * movieEvent method that receives a GSMovie argument. This method will + * captureEvent method that receives a Capture argument. This method will * be called upon a new frame read event. * */ @@ -974,8 +974,17 @@ public class Capture extends PImage implements PConstants { eventHandler = obj; try { - captureEventMethod = parent.getClass().getMethod("captureEvent", - new Class[] { Capture.class }); + captureEventMethod = obj.getClass().getMethod("captureEvent", Capture.class); + return; + } catch (Exception e) { + // no such method, or an error.. which is fine, just ignore + } + + // The captureEvent method may be declared as receiving Object, rather + // than Capture. + try { + captureEventMethod = obj.getClass().getMethod("captureEvent", Object.class); + return; } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -1008,18 +1017,7 @@ public class Capture extends PImage implements PConstants { copyPixels = null; return; } - - // Creates a movieEvent. - if (captureEventMethod != null) { - try { - captureEventMethod.invoke(eventHandler, new Object[] { this }); - } catch (Exception e) { - System.err.println( - "error, disabling captureEvent() for capture object"); - e.printStackTrace(); - captureEventMethod = null; - } - } + fireCaptureEvent(); } @@ -1028,20 +1026,23 @@ public class Capture extends PImage implements PConstants { bufWidth = w; bufHeight = h; if (natBuffer != null) { - // To handle the situation where read() is not called in the sketch, so - // that the native buffers are not being sent to the sinke, and therefore, not disposed - // by it. - natBuffer.dispose(); - } + // To handle the situation where read() is not called in the sketch, + // so that the native buffers are not being sent to the sink, + // and therefore, not disposed by it. + natBuffer.dispose(); + } natBuffer = buffer; + fireCaptureEvent(); + } - // Creates a movieEvent. + + private void fireCaptureEvent() { if (captureEventMethod != null) { try { - captureEventMethod.invoke(eventHandler, new Object[] { this }); + captureEventMethod.invoke(eventHandler, this); + } catch (Exception e) { - System.err.println( - "error, disabling captureEvent() for capture object"); + System.err.println("error, disabling captureEvent()"); e.printStackTrace(); captureEventMethod = null; } @@ -1130,7 +1131,7 @@ public class Capture extends PImage implements PConstants { * copy the frames to OpenGL. * * NOTE: This is not official API and may/will be removed at any time. - * + * * @param Object dest */ public void setBufferSink(Object sink) { @@ -1141,7 +1142,7 @@ public class Capture extends PImage implements PConstants { /** * Sets the object to use as destination for the frames read from the stream. - * + * * NOTE: This is not official API and may/will be removed at any time. * * @param Object dest @@ -1186,22 +1187,22 @@ public class Capture extends PImage implements PConstants { throw new RuntimeException("Capture: provided sink object doesn't have "+ "a setBufferSource method."); } - + try { - sinkDisposeMethod = bufferSink.getClass().getMethod("disposeSourceBuffer", + sinkDisposeMethod = bufferSink.getClass().getMethod("disposeSourceBuffer", new Class[] { }); } catch (Exception e) { throw new RuntimeException("Capture: provided sink object doesn't have " + "a disposeSourceBuffer method."); } - + try { - sinkGetMethod = bufferSink.getClass().getMethod("getBufferPixels", + sinkGetMethod = bufferSink.getClass().getMethod("getBufferPixels", new Class[] { int[].class }); } catch (Exception e) { throw new RuntimeException("Capture: provided sink object doesn't have " + "a getBufferPixels method."); - } + } } @@ -1212,8 +1213,8 @@ public class Capture extends PImage implements PConstants { copyMask = "red_mask=(int)0xFF, green_mask=(int)0xFF00, blue_mask=(int)0xFF0000"; } } - - + + public synchronized void post() { if (useBufferSink && sinkDisposeMethod != null) { try { @@ -1222,5 +1223,5 @@ public class Capture extends PImage implements PConstants { e.printStackTrace(); } } - } -} \ No newline at end of file + } +} diff --git a/java/libraries/video/src/processing/video/Movie.java b/java/libraries/video/src/processing/video/Movie.java index a98781059..958be1109 100644 --- a/java/libraries/video/src/processing/video/Movie.java +++ b/java/libraries/video/src/processing/video/Movie.java @@ -722,10 +722,19 @@ public class Movie extends PImage implements PConstants { eventHandler = obj; try { - movieEventMethod = eventHandler.getClass().getMethod("movieEvent", - new Class[] { Movie.class }); + movieEventMethod = eventHandler.getClass().getMethod("movieEvent", Movie.class); + return; } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore + // no such method, or an error... which is fine, just ignore + } + + // movieEvent can alternatively be defined as receiving an Object, to allow + // Processing mode implementors to support the video library without linking + // to it at build-time. + try { + movieEventMethod = eventHandler.getClass().getMethod("movieEvent", Object.class); + } catch (Exception e) { + // no such method, or an error... which is fine, just ignore } } @@ -808,20 +817,10 @@ public class Movie extends PImage implements PConstants { } if (playing) { - // Creates a movieEvent. - if (movieEventMethod != null) { - try { - movieEventMethod.invoke(eventHandler, new Object[] { this }); - } catch (Exception e) { - System.err.println("error, disabling movieEvent() for " + filename); - e.printStackTrace(); - movieEventMethod = null; - } - } + fireMovieEvent(); } } - protected synchronized void invokeEvent(int w, int h, Buffer buffer) { available = true; bufWidth = w; @@ -835,19 +834,22 @@ public class Movie extends PImage implements PConstants { natBuffer = buffer; if (playing) { - // Creates a movieEvent. - if (movieEventMethod != null) { - try { - movieEventMethod.invoke(eventHandler, new Object[] { this }); - } catch (Exception e) { - System.err.println("error, disabling movieEvent() for " + filename); - e.printStackTrace(); - movieEventMethod = null; - } - } + fireMovieEvent(); } } + private void fireMovieEvent() { + // Creates a movieEvent. + if (movieEventMethod != null) { + try { + movieEventMethod.invoke(eventHandler, this); + } catch (Exception e) { + System.err.println("error, disabling movieEvent() for " + filename); + e.printStackTrace(); + movieEventMethod = null; + } + } + } protected void eosEvent() { if (repeat) { diff --git a/todo.txt b/todo.txt index c69083e14..340c441f5 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,4 @@ -0227 pde -X use mouseReleased() instead of mousePressed() in color selector -X otherwise it registers the release as a click in the color window -X https://github.com/processing/processing/issues/2514 +0228 pde medium @@ -26,8 +23,6 @@ _ add font fixes to the rest of the API _ https://github.com/processing/processing/commit/eaff673d173b2d27f276cf5c59e3abf6c0fab86b _ g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, _ RenderingHints.VALUE_FRACTIONALMETRICS_ON); -_ dataPath() not working when app is not run from app dir on Linux -_ https://github.com/processing/processing/issues/2195 _ should default to the local Java on Windows and Linux _ have export apps default to the local JRE _ Linux is probably using the system JRE if available