From 1052d6643f5bc773ff429eb5846a17e0840445b6 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 13 Aug 2015 11:54:18 -0400 Subject: [PATCH] clean up internal sketch loading, breaks api but fixes #3586 and avoids other complications --- app/src/processing/app/Base.java | 85 ++++++++++--------- app/src/processing/app/Mode.java | 37 +------- app/src/processing/app/SketchException.java | 66 +++++++------- app/src/processing/app/ui/Editor.java | 74 +++++----------- .../processing/app/ui/EditorException.java | 47 ++++++++++ core/todo.txt | 13 ++- java/src/processing/mode/java/JavaEditor.java | 48 +++++------ java/src/processing/mode/java/JavaMode.java | 5 +- todo.txt | 14 ++- 9 files changed, 192 insertions(+), 197 deletions(-) create mode 100644 app/src/processing/app/ui/EditorException.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b0c0a63c1..e8d10c440 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -814,9 +814,8 @@ 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) { + protected Editor handleOpen(String path, boolean untitled, + EditorState state) { try { // System.err.println("entering handleOpen " + path); @@ -856,54 +855,56 @@ public class Base { nextMode = mode; } -// Editor.State state = new Editor.State(editors); - Editor editor = null; try { - editor = nextMode.createEditor(this, path, state); + Editor editor = nextMode.createEditor(this, path, state); + // opened successfully, let's go to work + 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); + + return editor; + + } catch (EditorException ee) { + if (!ee.getMessage().equals("")) { // blank if the user canceled + Base.showWarning("Error opening sketch", ee.getMessage(), ee); + } } catch (NoSuchMethodError nsme) { Base.showWarning("Mode out of date", nextMode.getTitle() + " is not compatible with this version of Processing.\n" + "Try updating the Mode or contact its author for a new version.", nsme); } catch (Throwable t) { - showBadnessTrace("Mode Problems", - "A nasty error occurred while trying to use " + nextMode.getTitle() + ".\n" + - "It may not be compatible with this version of Processing.\n" + - "Try updating the Mode or contact its author for a new version.", t, false); - } - if (editor == null) { - // if the bad mode is the default mode, don't go into an infinite loop - // trying to recreate a window with the default mode. - Mode defaultMode = getDefaultMode(); - if (nextMode == defaultMode) { - 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 with the default Mode.", - null); + if (nextMode.equals(getDefaultMode())) { + showBadnessTrace("Serious Problem", + "An unexpected, unknown, and unrecoverable error occurred\n" + + "while opening a new editor window. Please report this.", t, true); } else { - editor = defaultMode.createEditor(this, path, state); + showBadnessTrace("Mode Problems", + "A nasty error occurred while trying to use " + nextMode.getTitle() + ".\n" + + "It may not be compatible with this version of Processing.\n" + + "Try updating the Mode or contact its author for a new version.", t, false); } } - - // Make sure that the sketch actually loaded - Sketch sketch = editor.getSketch(); - if (sketch == null) { - return null; // Just walk away quietly - } - - sketch.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); - - return editor; - -// } catch (NoSuchMethodError nsme) { -// Base.showWarning(title, message); + /* + if (editors.isEmpty()) { + // if the bad mode is the default mode, don't go into an infinite loop + // trying to recreate a window with the default mode. + Mode defaultMode = getDefaultMode(); + if (nextMode == defaultMode) { + 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 with the default Mode.", + null); + } else { + editor = defaultMode.createEditor(this, path, state); + } + } + */ } catch (Throwable t) { showBadnessTrace("Terrible News", @@ -911,8 +912,8 @@ public class Base { "trying to create a new editor window.", t, nextMode == getDefaultMode()); // quit if default nextMode = getDefaultMode(); - return null; } + return null; } diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index 8ae69378e..3a136ce11 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -36,6 +36,7 @@ import javax.swing.tree.*; import processing.app.syntax.*; import processing.app.ui.Editor; +import processing.app.ui.EditorException; import processing.app.ui.EditorState; import processing.app.ui.ExamplesFrame; import processing.app.ui.SketchbookFrame; @@ -215,38 +216,6 @@ public abstract class Mode { } - /* - protected void loadBackground() { - String suffix = Toolkit.highResDisplay() ? "-2x.png" : ".png"; - backgroundImage = loadImage("theme/mode" + suffix); - if (backgroundImage == null) { - // If the image wasn't available, try the other resolution. - // i.e. we don't (currently) have low-res versions of mode.png, - // so this will grab the 2x version and scale it when drawn. - suffix = !Toolkit.highResDisplay() ? "-2x.png" : ".png"; - backgroundImage = loadImage("theme/mode" + suffix); - } - } - - - public void drawBackground(Graphics g, int offset) { - if (backgroundImage != null) { - if (!Toolkit.highResDisplay()) { - // Image might be downsampled from a 2x version. If so, we need nice - // anti-aliasing for the very geometric images we're using. - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BICUBIC); - } - g.drawImage(backgroundImage, 0, -offset, - BACKGROUND_WIDTH, BACKGROUND_HEIGHT, null); - } - } - */ - - public File getContentFile(String path) { return new File(folder, path); } @@ -280,8 +249,8 @@ public abstract class Mode { /** * Create a new editor associated with this mode. */ - abstract public Editor createEditor(Base base, String path, EditorState state); - //abstract public Editor createEditor(Base base, String path, int[] location); + abstract public Editor createEditor(Base base, String path, + EditorState state) throws EditorException; /** diff --git a/app/src/processing/app/SketchException.java b/app/src/processing/app/SketchException.java index e2d6eeef3..ccf8b924e 100644 --- a/app/src/processing/app/SketchException.java +++ b/app/src/processing/app/SketchException.java @@ -28,33 +28,35 @@ package processing.app; * An exception with a line number attached that occurs * during either pre-processing, compile, or run time. */ -public class SketchException extends Exception /*RuntimeException*/ { +public class SketchException extends Exception { protected String message; protected int codeIndex; protected int codeLine; protected int codeColumn; protected boolean showStackTrace; - + public SketchException(String message) { this(message, true); } + public SketchException(String message, boolean showStackTrace) { this(message, -1, -1, -1, showStackTrace); } + public SketchException(String message, int file, int line) { this(message, file, line, -1, true); } - + public SketchException(String message, int file, int line, int column) { this(message, file, line, column, true); } - - - public SketchException(String message, int file, int line, int column, + + + public SketchException(String message, int file, int line, int column, boolean showStackTrace) { this.message = message; this.codeIndex = file; @@ -62,71 +64,71 @@ public class SketchException extends Exception /*RuntimeException*/ { this.codeColumn = column; this.showStackTrace = showStackTrace; } - - - /** - * Override getMessage() in Throwable, so that I can set + + + /** + * Override getMessage() in Throwable, so that I can set * the message text outside the constructor. */ public String getMessage() { return message; } - - + + public void setMessage(String message) { this.message = message; } - - + + public int getCodeIndex() { return codeIndex; } - - + + public void setCodeIndex(int index) { codeIndex = index; } - - + + public boolean hasCodeIndex() { return codeIndex != -1; } - - + + public int getCodeLine() { return codeLine; } - - + + public void setCodeLine(int line) { this.codeLine = line; } - - + + public boolean hasCodeLine() { return codeLine != -1; } - - + + public void setCodeColumn(int column) { this.codeColumn = column; } - - + + public int getCodeColumn() { return codeColumn; } - + public void showStackTrace() { showStackTrace = true; } - - + + public void hideStackTrace() { showStackTrace = false; } - + /** * Nix the java.lang crap out of an exception message diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index 3276bc04b..33b2e7c58 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -151,7 +151,8 @@ public abstract class Editor extends JFrame implements RunnerListener { // protected Editor(final Base base, String path, int[] location, final Mode mode) { - protected Editor(final Base base, String path, EditorState state, final Mode mode) { + protected Editor(final Base base, String path, final EditorState state, + final Mode mode) throws EditorException { super("Processing", state.checkConfig()); this.base = base; this.state = state; @@ -366,10 +367,7 @@ public abstract class Editor extends JFrame implements RunnerListener { }); // Open the document that was passed in - boolean loaded = handleOpenInternal(path); - if (!loaded) { - sketch = null; - } + handleOpenInternal(path); // Add a window listener to watch for changes to the files in the sketch addWindowFocusListener(new ChangeDetector(this)); @@ -2611,29 +2609,13 @@ public abstract class Editor extends JFrame implements RunnerListener { } - /** - * 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" - */ -// protected void handleOpenUnchecked(String path, int codeIndex, -// int selStart, int selStop, int scrollPos) { -// internalCloseRunner(); -// handleOpenInternal(path); -// // Replacing a document that may be untitled. If this is an actual -// // untitled document, then editor.untitled will be set by Base. -// untitled = false; -// -// sketch.setCurrentCode(codeIndex); -// textarea.select(selStart, selStop); -// textarea.setScrollPosition(scrollPos); -// } - - /** * Second stage of open, occurs after having checked to see if the * modifications (if any) to the previous sketch need to be saved. + * Because this method is called in Editor's constructor, a subclass + * shouldn't rely on any of its variables being initialized already. */ - protected boolean handleOpenInternal(String path) { + protected void handleOpenInternal(String path) throws EditorException { // check to make sure that this .pde file is // in a folder of the same name final File file = new File(path); @@ -2649,13 +2631,11 @@ public abstract class Editor extends JFrame implements RunnerListener { // but open the file with the default extension instead. path = altFile.getAbsolutePath(); } else if (!mode.canEdit(file)) { - final String modeName = (mode.getTitle().equals("Java")) ? "Processing" - : mode.getTitle(); - Base - .showWarning("Bad file selected", modeName - + " can only open its own sketches\nand other files ending in " - + mode.getDefaultExtension(), null); - return false; + final String modeName = mode.getTitle().equals("Java") ? + "Processing" : (mode.getTitle() + " Mode"); + throw new EditorException(modeName + " can only open its own sketches\n" + + "and other files ending in " + + mode.getDefaultExtension()); } else { final String properParent = file.getName().substring(0, file.getName().lastIndexOf('.')); @@ -2679,16 +2659,11 @@ public abstract class Editor extends JFrame implements RunnerListener { // create properly named folder File properFolder = new File(file.getParent(), properParent); if (properFolder.exists()) { - Base.showWarning("Error", - "A folder named \"" + properParent + "\" " + - "already exists. Can't open sketch.", null); - return false; + throw new EditorException("A folder named \"" + properParent + "\" " + + "already exists. Can't open sketch."); } if (!properFolder.mkdirs()) { - //throw new IOException("Couldn't create sketch folder"); - Base.showWarning("Error", - "Could not create the sketch folder.", null); - return false; + throw new EditorException("Could not create the sketch folder."); } // copy the sketch inside File properPdeFile = new File(properFolder, file.getName()); @@ -2696,8 +2671,7 @@ public abstract class Editor extends JFrame implements RunnerListener { try { Util.copyFile(origPdeFile, properPdeFile); } catch (IOException e) { - Base.showWarning("Error", "Could not copy to a proper location.", e); - return false; + throw new EditorException("Could not copy to a proper location.", e); } // remove the original file, so user doesn't get confused @@ -2706,16 +2680,17 @@ public abstract class Editor extends JFrame implements RunnerListener { // update with the new path path = properPdeFile.getAbsolutePath(); - } else if (result == JOptionPane.NO_OPTION) { - return false; + } else { //if (result == JOptionPane.NO_OPTION) { + // Catch all other cases, including Cancel or ESC + //return false; + throw new EditorException(); } } try { sketch = new Sketch(path, this); } catch (IOException e) { - Base.showWarning("Error", "Could not create the sketch.", e); - return false; + throw new EditorException("Could not create the sketch.", e); } header.rebuild(); @@ -2727,15 +2702,6 @@ public abstract class Editor extends JFrame implements RunnerListener { // (in case there's a crash or something that can't be recovered) // TODO this probably need not be here because of the Recent menu, right? Preferences.save(); - - // opening was successful - return true; - -// } catch (Exception e) { -// e.printStackTrace(); -// statusError(e); -// return false; -// } } /** diff --git a/app/src/processing/app/ui/EditorException.java b/app/src/processing/app/ui/EditorException.java new file mode 100644 index 000000000..67c170a88 --- /dev/null +++ b/app/src/processing/app/ui/EditorException.java @@ -0,0 +1,47 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2015 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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.ui; + + +//public class EditorException extends RuntimeException { +public class EditorException extends Exception { +// String message; + Throwable cause; + + + // user canceled + public EditorException() { + super(); + } + + + public EditorException(String title) { //, String message) { + super(title); +// this.message = message; + } + + +// public EditorException(String title, String message, Throwable cause) { + public EditorException(String title, Throwable cause) { + super(title, cause); + } +} \ No newline at end of file diff --git a/core/todo.txt b/core/todo.txt index adec52cc2..13188197a 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,10 +1,14 @@ 0242 core (3.0b4) +X dataPath() not working when app is not run from app dir on Linux +X https://github.com/processing/processing/issues/2195 earlier X are we clear on sketchPath() for OS X? X working dir (user.dir?) returns home dir, not app dir in Oracle Java X could add -Dapp.root=$APP_ROOT and get via System.getProperty("app.root") X https://github.com/processing/processing/issues/2181 +X textWidth() incorrect with default (JAVA2D) renderer and default font +X https://github.com/processing/processing/issues/2175 opengl X filter(PShader) broken in HDPI mode @@ -151,8 +155,6 @@ _ the table pointer version will be speedy and allow chaining high -_ dataPath() not working when app is not run from app dir on Linux -_ https://github.com/processing/processing/issues/2195 _ point() rendering differently in 2.0.3 and 2.1 _ https://github.com/processing/processing/issues/2278 _ internally, we probably have to call set() if it's a 1 pixel point @@ -368,14 +370,17 @@ _ maybe a hack where a new menubar is added? CORE / PFont and text() +_ font rotation (native font problem?) with natives? +_ https://github.com/processing/processing/issues/731 +_ Text rotation, placement and font metrics incorrect when scaled +_ https://github.com/processing/processing/issues/2167 + _ remove subsetting stuff from PFont? _ or use hint(ENABLE_FONT_SUBSETTING)? _ what's the difference with ascent on loadFont vs. createFont? _ svg fonts _ would be nifty if we could convert on the fly to ttf for speed... _ https://github.com/processing/processing/issues/787 -_ font rotation (native font problem?) with natives? -_ https://github.com/processing/processing/issues/731 _ text position is quantized in JAVA2D _ text placement is ugly, seems like fractional metrics problem _ https://github.com/processing/processing/issues/138 diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index a34fb29dc..0a5e05fc7 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -34,6 +34,7 @@ import processing.app.syntax.PdeTextAreaDefaults; import processing.app.ui.About; import processing.app.ui.ColorChooser; import processing.app.ui.Editor; +import processing.app.ui.EditorException; import processing.app.ui.EditorFooter; import processing.app.ui.EditorHeader; import processing.app.ui.EditorState; @@ -68,6 +69,7 @@ public class JavaEditor extends Editor { protected Color currentLineColor; protected Color breakpointMarkerColor; protected Color currentLineMarkerColor; + protected List breakpointedLines = new ArrayList(); protected LineHighlight currentLine; // where the debugger is suspended @@ -103,7 +105,8 @@ public class JavaEditor extends Editor { protected ErrorCheckerService errorCheckerService; - protected JavaEditor(Base base, String path, EditorState state, Mode mode) { + protected JavaEditor(Base base, String path, EditorState state, + Mode mode) throws EditorException { super(base, path, state, mode); jmode = (JavaMode) mode; @@ -1675,31 +1678,24 @@ public class JavaEditor extends Editor { } - /** - * Event handler called when loading another sketch in this editor. Clears - * breakpoints of previous sketch. - * - * @param path - * @return true if a sketch was opened, false if aborted - */ - @Override - protected boolean handleOpenInternal(String path) { - // log("handleOpenInternal, path: " + path); - boolean didOpen = super.handleOpenInternal(path); - if (didOpen && debugger != null) { - // should already been stopped (open calls handleStop) - debugger.clearBreakpoints(); - clearBreakpointedLines(); // force clear breakpoint highlights - variableInspector().reset(); // clear contents of variable inspector - } - //if(didOpen){ - // autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure - // loadAutoSaver(); - // viewingAutosaveBackup = autosaver.isAutoSaveBackup(); - // log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); - //} - return didOpen; - } + // handleOpenInternal() only called by the Editor constructor, meaning that + // this code is all useless. All these things will be in their default state. +// /** +// * Event handler called when loading another sketch in this editor. +// * Clears breakpoints of previous sketch. +// * @return true if a sketch was opened, false if aborted +// */ +// @Override +// protected void handleOpenInternal(String path) throws EditorException { +// super.handleOpenInternal(path); +// +// // should already been stopped (open calls handleStop) +// if (debugger != null) { +// debugger.clearBreakpoints(); +// } +// clearBreakpointedLines(); +// variableInspector().reset(); +// } /** diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index 21c2f22d1..9f88cbdbd 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -33,6 +33,7 @@ import javax.swing.ImageIcon; import processing.app.*; import processing.app.ui.Editor; +import processing.app.ui.EditorException; import processing.app.ui.EditorState; import processing.mode.java.runner.Runner; import processing.mode.java.tweak.SketchParser; @@ -40,7 +41,8 @@ import processing.mode.java.tweak.SketchParser; public class JavaMode extends Mode { - public Editor createEditor(Base base, String path, EditorState state) { + public Editor createEditor(Base base, String path, + EditorState state) throws EditorException { return new JavaEditor(base, path, state, this); } @@ -53,6 +55,7 @@ public class JavaMode extends Mode { loadIcons(); } + /** * Needed by code completion panel. See {@link processing.mode.java.pdex.CompletionPanel} */ diff --git a/todo.txt b/todo.txt index 5fca2c324..5cde8d81c 100644 --- a/todo.txt +++ b/todo.txt @@ -3,8 +3,10 @@ X Fix NullPointerException with some sketches that have no size() command X https://github.com/processing/processing/issues/3585 X Invalid OS X code signature X https://github.com/processing/processing/issues/3575 -_ canceling the "create folder, move sketch, and continue?" will cause crash -_ throws an NPE and then forces a quit +X canceling "create folder, move sketch, and continue?" will cause crash +X throws an NPE and then forces a quit +X https://github.com/processing/processing/issues/3586 +X also showError() there shouldn't die if other Java windows open gsoc X Second round of arm patches (v5) @@ -13,6 +15,10 @@ X https://github.com/processing/processing/pull/3583 earlier X closing the color selector makes things freeze (only Linux and Windows?) X https://github.com/processing/processing/issues/2381 +X Comment/Uncomment should ignore leading whitespace +X https://github.com/processing/processing/issues/1961 +X Export unsaved sketch > agree to save prompt > export doesn't finish +X https://github.com/processing/processing/issues/2724 known issues @@ -28,8 +34,8 @@ _ mouse events (i.e. toggle breakpoint) seem to be firing twice 3.0 final -_ more ARM patches -_ https://github.com/processing/processing/pull/3566 +_ move Platform into its own class? +_ https://github.com/processing/processing/issues/2765 _ Contributions Manager UI design _ https://github.com/processing/processing/issues/3482 _ Ready to add contributed example packages?