diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 49a8625e5..c00e7786b 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -23,6 +23,17 @@ package processing.app; +import java.awt.*; +import java.awt.event.ActionListener; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.List; +import java.util.Map.Entry; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; + import com.formdev.flatlaf.FlatDarkLaf; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLightLaf; @@ -34,19 +45,6 @@ import processing.core.PApplet; import processing.data.StringList; -import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import java.awt.*; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.List; -import java.util.Map.Entry; - /** * The base class for the main processing application. * Primary role of this class is for platform identification and @@ -231,7 +229,7 @@ static private void createAndShowGUI(String[] args) { Messages.log("Base() constructor succeeded"); // Prevent more than one copy of the PDE from running. - SingleInstance.startServer(base); + new Thread(() -> { SingleInstance.startServer(base); } ).start(); handleWelcomeScreen(base); handleCrustyDisplay(); @@ -850,7 +848,7 @@ public List getContribTools() { return contribTools; } - + private List toolsToInit = new ArrayList<>(); public void rebuildToolList() { // Only do these once because the list of internal tools will never change if (internalTools == null) { @@ -870,43 +868,12 @@ public void rebuildToolList() { // Only init() these the first time they're loaded if (coreTools == null) { coreTools = ToolContribution.loadAll(Base.getToolsFolder()); - for (Tool tool : coreTools) { - tool.init(this); - } + toolsToInit.addAll(coreTools); } // Reset the contributed tools and re-init() all of them. contribTools = ToolContribution.loadAll(Base.getSketchbookToolsFolder()); - for (Tool tool : contribTools) { - try { - tool.init(this); - - // With the exceptions, we can't call statusError because the window - // isn't completely set up yet. Also not gonna pop up a warning because - // people may still be running different versions of Processing. - - } catch (VerifyError | AbstractMethodError ve) { - System.err.println("\"" + tool.getMenuTitle() + "\" is not " + - "compatible with this version of Processing"); - Messages.err("Incompatible Tool found during tool.init()", ve); - - } catch (NoSuchMethodError nsme) { - System.err.println("\"" + tool.getMenuTitle() + "\" is not " + - "compatible with this version of Processing"); - System.err.println("The " + nsme.getMessage() + " method no longer exists."); - Messages.err("Incompatible Tool found during tool.init()", nsme); - - } catch (NoClassDefFoundError ncdfe) { - System.err.println("\"" + tool.getMenuTitle() + "\" is not " + - "compatible with this version of Processing"); - System.err.println("The " + ncdfe.getMessage() + " class is no longer available."); - Messages.err("Incompatible Tool found during tool.init()", ncdfe); - - } catch (Error | Exception e) { - System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\""); - e.printStackTrace(); - } - } + toolsToInit.addAll(contribTools); } @@ -915,7 +882,7 @@ protected void initInternalTool(Class toolClass) { final Tool tool = (Tool) toolClass.getDeclaredConstructor().newInstance(); - tool.init(this); + toolsToInit.add(tool); internalTools.add(tool); } catch (Exception e) { @@ -963,12 +930,40 @@ public void populateToolsMenu(JMenu toolsMenu) { toolsMenu.add(manageTools); } + void initTool(Tool tool) { + if(!toolsToInit.contains(tool)) {return;} + try { + tool.init(this); + toolsToInit.remove(tool); + } catch (VerifyError | AbstractMethodError ve) { + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + Messages.err("Incompatible Tool found during tool.init()", ve); + + } catch (NoSuchMethodError nsme) { + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + System.err.println("The " + nsme.getMessage() + " method no longer exists."); + Messages.err("Incompatible Tool found during tool.init()", nsme); + + } catch (NoClassDefFoundError ncdfe) { + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + System.err.println("The " + ncdfe.getMessage() + " class is no longer available."); + Messages.err("Incompatible Tool found during tool.init()", ncdfe); + + } catch (Error | Exception e) { + System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\""); + e.printStackTrace(); + } + } JMenuItem createToolItem(final Tool tool) { //, Map toolItems) { String title = tool.getMenuTitle(); final JMenuItem item = new JMenuItem(title); item.addActionListener(e -> { try { + initTool(tool); tool.run(); } catch (NoSuchMethodError | NoClassDefFoundError ne) { diff --git a/app/src/processing/app/platform/DefaultPlatform.java b/app/src/processing/app/platform/DefaultPlatform.java index 54f0ec278..eed79bb0b 100644 --- a/app/src/processing/app/platform/DefaultPlatform.java +++ b/app/src/processing/app/platform/DefaultPlatform.java @@ -23,6 +23,12 @@ package processing.app.platform; +import java.awt.*; +import java.io.File; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; + import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLightLaf; import processing.app.Base; @@ -31,10 +37,6 @@ import processing.awt.ShimAWT; import processing.core.PApplet; -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.io.File; /** @@ -110,18 +112,29 @@ public void setLookAndFeel() throws Exception { // (i.e. Nimbus on Linux) with our custom components is badness. // dummy font call so that it's registered for FlatLaf - Font defaultFont = Toolkit.getSansFont(14, Font.PLAIN); - UIManager.put("defaultFont", defaultFont); + new Thread(() -> { + Font defaultFont = Toolkit.getSansFont(14, Font.PLAIN); + UIManager.put("defaultFont", defaultFont); + }).start(); + // pull in FlatLaf.properties from the processing.app.laf folder FlatLaf.registerCustomDefaultsSource("processing.app.laf"); - // start with Light, but updateTheme() will be called soon - UIManager.setLookAndFeel(new FlatLightLaf()); + new Thread(() -> { + // start with Light, but updateTheme() will be called soon + try { + UIManager.setLookAndFeel(new FlatLightLaf()); + } catch (UnsupportedLookAndFeelException e) { + throw new RuntimeException(e); + } + }).start(); // Does not fully remove the gray hairline (probably from a parent // Window object), but is an improvement from the heavier default. - UIManager.put("ToolTip.border", new EmptyBorder(0, 0, 0, 0)); + new Thread(() -> { + UIManager.put("ToolTip.border", new EmptyBorder(0, 0, 0, 0)); + }).start(); /* javax.swing.UIDefaults defaults = UIManager.getDefaults(); diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java index d5d964b16..c74ba6480 100644 --- a/app/src/processing/app/ui/Editor.java +++ b/app/src/processing/app/ui/Editor.java @@ -193,7 +193,7 @@ public void windowDeactivated(WindowEvent e) { timer = new Timer(); - buildMenuBar(); + new Thread(this::buildMenuBar).start(); JPanel contentPain = new JPanel(); setContentPane(contentPain); diff --git a/app/src/processing/app/ui/Toolkit.java b/app/src/processing/app/ui/Toolkit.java index 8a5ae418b..50eaf6a2c 100644 --- a/app/src/processing/app/ui/Toolkit.java +++ b/app/src/processing/app/ui/Toolkit.java @@ -44,16 +44,19 @@ import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.regex.Pattern; +import javax.imageio.ImageIO; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -68,14 +71,12 @@ import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; -import processing.app.Language; -import processing.app.Messages; -import processing.app.Platform; -import processing.app.Preferences; -import processing.app.Util; +import processing.app.*; import processing.awt.PGraphicsJava2D; import processing.awt.PShapeJava2D; +import processing.awt.ShimAWT; import processing.core.PApplet; +import processing.core.PImage; import processing.core.PShape; import processing.data.StringDict; import processing.data.StringList; @@ -794,6 +795,7 @@ static private Image svgToImageMult(String xmlStr, int wide, int high) { */ + static public Image svgToImageMult(String xmlStr, int wide, int high, StringDict replacements) { /* for (StringDict.Entry entry : replacements.entries()) { @@ -823,8 +825,25 @@ static private Image svgToImage(String xmlStr, int wide, int high) { pg.setSize(wide, high); pg.smooth(); + + + + pg.beginDraw(); + var cacheKey = (xmlStr + "|" + wide + "x" + high).hashCode(); + var cachePath = Base.getSettingsFolder().toPath().resolve("svg_cache").resolve(String.valueOf(cacheKey) + ".png"); + if(!Base.DEBUG || true){ + if(Files.exists(cachePath)){ + byte[] bytes = PApplet.loadBytes(cachePath.toFile()); + if (bytes == null) { + return null; + } else { + return new ImageIcon(bytes).getImage(); + } + } + } + try { XML xml = XML.parse(xmlStr); PShape shape = new PShapeJava2D(xml); @@ -835,6 +854,12 @@ static private Image svgToImage(String xmlStr, int wide, int high) { } pg.endDraw(); + try { + Files.createDirectories(cachePath.getParent()); + pg.save(cachePath.toString()); + } catch (IOException e) { + e.printStackTrace(); + } return pg.image; } @@ -1361,8 +1386,9 @@ static private Font initFont(String filename, int size) throws IOException, Font Font font = Font.createFont(Font.TRUETYPE_FONT, input); input.close(); - // Register the font to be available for other function calls - GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font); + new Thread(() -> { + GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font); + }).start(); return font.deriveFont((float) size); } diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index d9df211eb..c4b6a5adb 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -6822,28 +6822,9 @@ static public String[] loadStrings(InputStream input) { static public String[] loadStrings(BufferedReader reader) { try { - String[] lines = new String[100]; - int lineCount = 0; - String line; - while ((line = reader.readLine()) != null) { - if (lineCount == lines.length) { - String[] temp = new String[lineCount << 1]; - System.arraycopy(lines, 0, temp, 0, lineCount); - lines = temp; - } - lines[lineCount++] = line; - } + var lines = reader.lines().toArray(String[]::new); reader.close(); - - if (lineCount == lines.length) { - return lines; - } - - // resize array to appropriate amount for these lines - String[] output = new String[lineCount]; - System.arraycopy(lines, 0, output, 0, lineCount); - return output; - + return lines; } catch (IOException e) { e.printStackTrace(); //throw new RuntimeException("Error inside loadStrings()"); diff --git a/java/src/processing/mode/java/JavaTextArea.java b/java/src/processing/mode/java/JavaTextArea.java index ecab00eed..628a47fdc 100644 --- a/java/src/processing/mode/java/JavaTextArea.java +++ b/java/src/processing/mode/java/JavaTextArea.java @@ -52,7 +52,9 @@ public class JavaTextArea extends PdeTextArea { public JavaTextArea(TextAreaDefaults defaults, JavaEditor editor) { super(defaults, new JavaInputHandler(editor), editor); - suggestionGenerator = new CompletionGenerator((JavaMode) editor.getMode()); + new Thread(() -> { + suggestionGenerator = new CompletionGenerator((JavaMode) editor.getMode()); + }).start(); tweakMode = false; } diff --git a/java/src/processing/mode/java/PreprocService.java b/java/src/processing/mode/java/PreprocService.java index 410cff02f..bf144fa54 100644 --- a/java/src/processing/mode/java/PreprocService.java +++ b/java/src/processing/mode/java/PreprocService.java @@ -80,7 +80,7 @@ public class PreprocService { protected final JavaMode javaMode; protected final Sketch sketch; - protected final ASTParser parser = ASTParser.newParser(AST.JLS11); + protected ASTParser parser; private final Thread preprocessingThread; private final BlockingQueue requestQueue = new ArrayBlockingQueue<>(1); @@ -116,6 +116,9 @@ public PreprocService(JavaMode javaMode, Sketch sketch) { * The "main loop" for the background thread that checks for code issues. */ private void mainLoop() { + if(parser == null) { + parser = ASTParser.newParser(AST.JLS11); + } running = true; PreprocSketch prevResult = null; CompletableFuture runningCallbacks = null; diff --git a/java/src/processing/mode/java/debug/Debugger.java b/java/src/processing/mode/java/debug/Debugger.java index e9d42895b..23cd7f130 100644 --- a/java/src/processing/mode/java/debug/Debugger.java +++ b/java/src/processing/mode/java/debug/Debugger.java @@ -112,7 +112,7 @@ public class Debugger { public Debugger(JavaEditor editor) { this.editor = editor; - inspector = new VariableInspector(editor); +// inspector = new VariableInspector(editor); } @@ -207,6 +207,9 @@ public void toggleEnabled() { } else { debugItem.setText(Language.text("menu.debug.enable")); } + if(inspector == null) { + inspector = new VariableInspector(editor); + } inspector.setVisible(enabled); for (Component item : debugMenu.getMenuComponents()) { @@ -298,6 +301,7 @@ public void removeClassLoadListener(ClassLoadListener listener) { public void dispose() { + if(inspector == null) return; inspector.dispose(); }