diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..b7d98e49d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Files which should always be normalized and converted +# to native line endings on checkout. +*.java text +*.pde text + +# Files that will always have CRLF line endings on checkout. +*.bat eol=crlf +build/macosx/jAppleMenuBar.url eol=crlf + diff --git a/app/src/processing/app/ColorChooser.java b/app/src/processing/app/ColorChooser.java index e76d9d1aa..de8e5e65a 100644 --- a/app/src/processing/app/ColorChooser.java +++ b/app/src/processing/app/ColorChooser.java @@ -80,7 +80,7 @@ public class ColorChooser { //extends JFrame implements DocumentListener { Box rangeBox = new Box(BoxLayout.Y_AXIS); rangeBox.setAlignmentY(0); rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); - rangeBox.add(range.getCanvas()); + rangeBox.add(range); box.add(rangeBox); box.add(Box.createHorizontalStrut(10)); @@ -88,7 +88,7 @@ public class ColorChooser { //extends JFrame implements DocumentListener { Box sliderBox = new Box(BoxLayout.Y_AXIS); sliderBox.setAlignmentY(0); sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); - sliderBox.add(slider.getCanvas()); + sliderBox.add(slider); box.add(sliderBox); box.add(Box.createHorizontalStrut(10)); @@ -106,10 +106,6 @@ public class ColorChooser { //extends JFrame implements DocumentListener { window.pack(); window.setResizable(false); - - // initialize once the components exist - range.init(); - slider.init(); // Dimension size = getSize(); // Dimension screen = Toolkit.getScreenSize(); @@ -236,8 +232,8 @@ public class ColorChooser { //extends JFrame implements DocumentListener { updateRGB(Integer.parseInt(str, 16)); updateHSB(); } - range.redraw(); - slider.redraw(); + range.repaint(); + slider.repaint(); //colorPanel.setBackground(new Color(red, green, blue)); colorPanel.repaint(); updating = false; @@ -486,58 +482,46 @@ public class ColorChooser { //extends JFrame implements DocumentListener { } - public class ColorRange extends PApplet { + public class ColorRange extends JComponent { - static final int WIDE = 256; - static final int HIGH = 256; + static final int WIDTH = 256; + static final int HEIGHT = 256; - int lastX, lastY; + private int lastX, lastY; + public ColorRange() { + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + updateMouse(e); + } + }); - public int sketchWidth() { - return WIDE; - } - - public int sketchHeight() { - return HIGH; - } - - public void setup() { - noLoop(); + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + updateMouse(e); + } + }); - colorMode(HSB, 360, 256, 256); - noFill(); - rectMode(CENTER); + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + super.keyPressed(e); - loadPixels(); - } - - public void draw() { - if (width == WIDE && height == HIGH) { - int index = 0; - for (int j = 0; j < 256; j++) { - for (int i = 0; i < 256; i++) { - pixels[index++] = color(hue, i, 255 - j); + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + ColorChooser.this.hide(); } } - - updatePixels(); - stroke((brightness > 50) ? 0 : 255); - rect(lastX, lastY, 9, 9); - } + }); } - public void mousePressed() { - updateMouse(); - } + private void updateMouse(MouseEvent e) { + int mouseX = e.getX(); + int mouseY = e.getY(); - public void mouseDragged() { - updateMouse(); - } - - public void updateMouse() { - if ((mouseX >= 0) && (mouseX < 256) && - (mouseY >= 0) && (mouseY < 256)) { + if ((mouseX >= 0) && (mouseX < WIDTH) && + (mouseY >= 0) && (mouseY < HEIGHT)) { int nsaturation = (int) (100 * (mouseX / 255.0f)); int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f))); saturationField.setText(String.valueOf(nsaturation)); @@ -548,102 +532,105 @@ public class ColorChooser { //extends JFrame implements DocumentListener { } } - public Dimension getPreferredSize() { - return new Dimension(WIDE, HIGH); - } + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); - public Dimension getMinimumSize() { - return new Dimension(WIDE, HIGH); - } - - public Dimension getMaximumSize() { - return new Dimension(WIDE, HIGH); - } - - public void keyPressed() { - if (key == ESC) { - ColorChooser.this.hide(); - // don't quit out of processing - // http://dev.processing.org/bugs/show_bug.cgi?id=1006 - key = 0; + for (int j = 0; j < WIDTH; j++) { + for (int i = 0; i < HEIGHT; i++) { + g.setColor(Color.getHSBColor(hue / 360f, i / 256f, (255 - j) / 256f)); + g.fillRect(i, j, 1, 1); + } } + + g.setColor((brightness > 50) ? Color.BLACK : Color.WHITE); + g.drawRect(lastX - 5, lastY - 5, 10, 10); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(WIDTH, HEIGHT); + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + public Dimension getMaximumSize() { + return getPreferredSize(); } } - public class ColorSlider extends PApplet { + public class ColorSlider extends JComponent { - static final int WIDE = 20; - static final int HIGH = 256; + static final int WIDTH = 20; + static final int HEIGHT = 256; - public int sketchWidth() { - return WIDE; - } - - public int sketchHeight() { - return HIGH; - } - - public void setup() { - colorMode(HSB, 255, 100, 100); - noLoop(); - loadPixels(); - } - - public void draw() { -// if ((g == null) || (g.pixels == null)) return; - if ((width != WIDE) || (height < HIGH)) { - //System.out.println("bad size " + width + " " + height); - return; - } - - int index = 0; - int sel = 255 - (int) (255 * (hue / 359f)); - for (int j = 0; j < 256; j++) { - int c = color(255 - j, 100, 100); - if (j == sel) c = 0xFF000000; - for (int i = 0; i < WIDE; i++) { - g.pixels[index++] = c; + public ColorSlider() { + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + updateMouse(e); } - } - updatePixels(); + }); + + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + updateMouse(e); + } + }); + + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + super.keyPressed(e); + + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + ColorChooser.this.hide(); + } + } + }); } - public void mousePressed() { - updateMouse(); - } + private void updateMouse(MouseEvent e) { + int mouseX = e.getX(); + int mouseY = e.getY(); - public void mouseDragged() { - updateMouse(); - } - - public void updateMouse() { - if ((mouseX >= 0) && (mouseX < 256) && - (mouseY >= 0) && (mouseY < 256)) { + if ((mouseX >= 0) && (mouseX < WIDTH) && + (mouseY >= 0) && (mouseY < HEIGHT)) { int nhue = 359 - (int) (359 * (mouseY / 255.0f)); hueField.setText(String.valueOf(nhue)); } } + public void paintComponent(Graphics g) { + super.paintComponent(g); + + int sel = 255 - (int) (255 * (hue / 359.0)); + for (int j = 0; j < HEIGHT; j++) { + Color color = Color.getHSBColor((255 - j) / 256f, 1, 1); + if (j == sel) { + color = Color.BLACK; + } + g.setColor(color); + g.drawRect(0, j, WIDTH, 1); + } + } + public Dimension getPreferredSize() { - return new Dimension(WIDE, HIGH); + return new Dimension(WIDTH, HEIGHT); } public Dimension getMinimumSize() { - return new Dimension(WIDE, HIGH); + return getPreferredSize(); } public Dimension getMaximumSize() { - return new Dimension(WIDE, HIGH); - } - - public void keyPressed() { - if (key == ESC) { - ColorChooser.this.hide(); - // don't quit out of processing - // http://dev.processing.org/bugs/show_bug.cgi?id=1006 - key = 0; - } + return getPreferredSize(); } } diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java index 3bb1ed4ee..183d7ffd2 100644 --- a/app/src/processing/app/contrib/Contribution.java +++ b/app/src/processing/app/contrib/Contribution.java @@ -1,231 +1,231 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas - - 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.contrib; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import processing.core.PApplet; - - -abstract public class Contribution { - static final String SPECIAL_CATEGORY_NAME = "Starred"; - static final List validCategories = - Arrays.asList("3D", "Animation", "Data", "Geometry", "GUI", "Hardware", - "I/O", "Math", "Simulation", "Sound", SPECIAL_CATEGORY_NAME, "Typography", - "Utilities", "Video & Vision", "Other"); - - //protected String category; // "Sound" - protected List categories; // "Sound", "Typography" - protected String name; // "pdf" or "PDF Export" - protected String authorList; // Ben Fry - protected String url; // http://processing.org - protected String sentence; // Write graphics to PDF files. - protected String paragraph; // - protected int version; // 102 - protected String prettyVersion; // "1.0.2" - protected long lastUpdated; // 1402805757 - protected int minRevision; // 0 - protected int maxRevision; // 227 - - - // "Sound" -// public String getCategory() { -// return category; -// } - - - // "Sound", "Utilities"... see valid list in ContributionListing - protected List getCategories() { - return categories; - } - - - protected String getCategoryStr() { - StringBuilder sb = new StringBuilder(); - for (String category : categories) { - sb.append(category); - sb.append(','); - } - sb.deleteCharAt(sb.length()-1); // delete last comma - return sb.toString(); - } - - - protected boolean hasCategory(String category) { - if (category != null) { - for (String c : categories) { - if (category.equalsIgnoreCase(c)) { - return true; - } - } - } - return false; - } - - - // "pdf" or "PDF Export" - public String getName() { - return name; - } - - - // "[Ben Fry](http://benfry.com/)" - public String getAuthorList() { - return authorList; - } - - - // "http://processing.org" - public String getUrl() { - return url; - } - - - // "Write graphics to PDF files." - public String getSentence() { - return sentence; - } - - - // - public String getParagraph() { - return paragraph; - } - - - // 102 - public int getVersion() { - return version; - } - - - // "1.0.2" - public String getPrettyVersion() { - return prettyVersion; - } - - // 1402805757 - public long getLastUpdated() { - return lastUpdated; - } - - // 0 - public int getMinRevision() { - return minRevision; - } - - // 227 - public int getMaxRevision() { - return maxRevision; - } - - - public boolean isCompatible(int versionNum) { - return ((maxRevision == 0 || versionNum < maxRevision) && versionNum > minRevision); - } - - - abstract public ContributionType getType(); - - - public String getTypeName() { - return getType().toString(); - } - - - abstract public boolean isInstalled(); - - -// /** -// * Returns true if the type of contribution requires the PDE to restart -// * when being added or removed. -// */ -// public boolean requiresRestart() { -// return getType() == ContributionType.TOOL || getType() == ContributionType.MODE; -// } - - - boolean isRestartFlagged() { - return false; - } - - - /** Overridden by LocalContribution. */ - boolean isDeletionFlagged() { - return false; - } - - - boolean isUpdateFlagged() { - return false; - } - - - /** - * Returns true if the contribution is a starred/recommended contribution, or - * is by the Processing Foundation. - * - * @return - */ - boolean isSpecial() { - try { - return (authorList.indexOf("The Processing Foundation") != -1 || - categories.contains(SPECIAL_CATEGORY_NAME)); - } catch (NullPointerException npe) { - return false; - } - } - - - /** - * @return a single element list with "Unknown" as the category. - */ - static List defaultCategory() { - List outgoing = new ArrayList(); - outgoing.add("Unknown"); - return outgoing; - } - - - /** - * @return the list of categories that this contribution is part of - * (e.g. "Typography / Geometry"). "Unknown" if the category null. - */ - static List parseCategories(String categoryStr) { - List outgoing = new ArrayList(); - - if (categoryStr != null) { - String[] listing = PApplet.trim(PApplet.split(categoryStr, ',')); - for (String category : listing) { - if (validCategories.contains(category)) { - outgoing.add(category); - } - } - } - if (outgoing.size() == 0) { - return defaultCategory(); - } - return outgoing; - } -} +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2011-12 Ben Fry and Casey Reas + + 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.contrib; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import processing.core.PApplet; + + +abstract public class Contribution { + static final String SPECIAL_CATEGORY_NAME = "Starred"; + static final List validCategories = + Arrays.asList("3D", "Animation", "Data", "Geometry", "GUI", "Hardware", + "I/O", "Math", "Simulation", "Sound", SPECIAL_CATEGORY_NAME, "Typography", + "Utilities", "Video & Vision", "Other"); + + //protected String category; // "Sound" + protected List categories; // "Sound", "Typography" + protected String name; // "pdf" or "PDF Export" + protected String authorList; // Ben Fry + protected String url; // http://processing.org + protected String sentence; // Write graphics to PDF files. + protected String paragraph; // + protected int version; // 102 + protected String prettyVersion; // "1.0.2" + protected long lastUpdated; // 1402805757 + protected int minRevision; // 0 + protected int maxRevision; // 227 + + + // "Sound" +// public String getCategory() { +// return category; +// } + + + // "Sound", "Utilities"... see valid list in ContributionListing + protected List getCategories() { + return categories; + } + + + protected String getCategoryStr() { + StringBuilder sb = new StringBuilder(); + for (String category : categories) { + sb.append(category); + sb.append(','); + } + sb.deleteCharAt(sb.length()-1); // delete last comma + return sb.toString(); + } + + + protected boolean hasCategory(String category) { + if (category != null) { + for (String c : categories) { + if (category.equalsIgnoreCase(c)) { + return true; + } + } + } + return false; + } + + + // "pdf" or "PDF Export" + public String getName() { + return name; + } + + + // "[Ben Fry](http://benfry.com/)" + public String getAuthorList() { + return authorList; + } + + + // "http://processing.org" + public String getUrl() { + return url; + } + + + // "Write graphics to PDF files." + public String getSentence() { + return sentence; + } + + + // + public String getParagraph() { + return paragraph; + } + + + // 102 + public int getVersion() { + return version; + } + + + // "1.0.2" + public String getPrettyVersion() { + return prettyVersion; + } + + // 1402805757 + public long getLastUpdated() { + return lastUpdated; + } + + // 0 + public int getMinRevision() { + return minRevision; + } + + // 227 + public int getMaxRevision() { + return maxRevision; + } + + + public boolean isCompatible(int versionNum) { + return ((maxRevision == 0 || versionNum < maxRevision) && versionNum > minRevision); + } + + + abstract public ContributionType getType(); + + + public String getTypeName() { + return getType().toString(); + } + + + abstract public boolean isInstalled(); + + +// /** +// * Returns true if the type of contribution requires the PDE to restart +// * when being added or removed. +// */ +// public boolean requiresRestart() { +// return getType() == ContributionType.TOOL || getType() == ContributionType.MODE; +// } + + + boolean isRestartFlagged() { + return false; + } + + + /** Overridden by LocalContribution. */ + boolean isDeletionFlagged() { + return false; + } + + + boolean isUpdateFlagged() { + return false; + } + + + /** + * Returns true if the contribution is a starred/recommended contribution, or + * is by the Processing Foundation. + * + * @return + */ + boolean isSpecial() { + try { + return (authorList.indexOf("The Processing Foundation") != -1 || + categories.contains(SPECIAL_CATEGORY_NAME)); + } catch (NullPointerException npe) { + return false; + } + } + + + /** + * @return a single element list with "Unknown" as the category. + */ + static List defaultCategory() { + List outgoing = new ArrayList(); + outgoing.add("Unknown"); + return outgoing; + } + + + /** + * @return the list of categories that this contribution is part of + * (e.g. "Typography / Geometry"). "Unknown" if the category null. + */ + static List parseCategories(String categoryStr) { + List outgoing = new ArrayList(); + + if (categoryStr != null) { + String[] listing = PApplet.trim(PApplet.split(categoryStr, ',')); + for (String category : listing) { + if (validCategories.contains(category)) { + outgoing.add(category); + } + } + } + if (outgoing.size() == 0) { + return defaultCategory(); + } + return outgoing; + } +} diff --git a/app/src/processing/app/contrib/ContributionManager.java b/app/src/processing/app/contrib/ContributionManager.java index eba5d13a8..c46de9c91 100644 --- a/app/src/processing/app/contrib/ContributionManager.java +++ b/app/src/processing/app/contrib/ContributionManager.java @@ -1,551 +1,551 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas - - 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.contrib; - -import java.io.*; -import java.net.*; -import java.util.*; - -import javax.swing.SwingWorker; - -import processing.app.Base; -import processing.app.Editor; -import processing.app.Language; - - -public class ContributionManager { - static public final ContributionListing contribListing; - - static { - contribListing = ContributionListing.getInstance(); - } - - - /** - * Blocks until the file is downloaded or an error occurs. Returns true if the - * file was successfully downloaded, false otherwise. - * - * @param source - * the URL of the file to download - * @param dest - * the file on the local system where the file will be written. This - * must be a file (not a directory), and must already exist. - * @param progress - * null if progress is irrelevant, such as when downloading for an - * install during startup, when the ProgressMonitor is useless since - * UI isn't setup yet. - * @throws FileNotFoundException - * if an error occurred downloading the file - */ - static boolean download(URL source, File dest, ProgressMonitor progress) { - boolean success = false; - try { -// System.out.println("downloading file " + source); -// URLConnection conn = source.openConnection(); - HttpURLConnection conn = (HttpURLConnection) source.openConnection(); - HttpURLConnection.setFollowRedirects(true); - conn.setConnectTimeout(15 * 1000); - conn.setReadTimeout(60 * 1000); - conn.setRequestMethod("GET"); - conn.connect(); - - if (progress != null) { - // TODO this is often -1, may need to set progress to indeterminate - int fileSize = conn.getContentLength(); -// System.out.println("file size is " + fileSize); - progress.startTask(Language.text("contrib.progress.downloading"), fileSize); - } - - InputStream in = conn.getInputStream(); - FileOutputStream out = new FileOutputStream(dest); - - byte[] b = new byte[8192]; - int amount; - if (progress != null) { - int total = 0; - while (!progress.isCanceled() && (amount = in.read(b)) != -1) { - out.write(b, 0, amount); - total += amount; - progress.setProgress(total); - } - } else { - while ((amount = in.read(b)) != -1) { - out.write(b, 0, amount); - } - } - out.flush(); - out.close(); - success = true; - - } catch (SocketTimeoutException ste) { - if (progress != null) { - progress.error(ste); - progress.cancel(); - } - } catch (IOException ioe) { - if (progress != null) { - progress.error(ioe); - progress.cancel(); - } - // Hiding stack trace. An error has been shown where needed. -// ioe.printStackTrace(); - } - if (progress != null) - progress.finished(); - return success; - } - - - /** - * Non-blocking call to download and install a contribution in a new thread. - * - * @param url - * Direct link to the contribution. - * @param toBeReplaced - * The Contribution that will be replaced by this library being - * installed (e.g. an advertised version of a contribution, or the - * old version of a contribution that is being updated). Must not be - * null. - */ - static void downloadAndInstall(final Editor editor, - final URL url, - final AvailableContribution ad, - final JProgressMonitor downloadProgress, - final JProgressMonitor installProgress, - final StatusPanel status) { - - new Thread(new Runnable() { - public void run() { - String filename = url.getFile(); - filename = filename.substring(filename.lastIndexOf('/') + 1); - try { - File contribZip = File.createTempFile("download", filename); - contribZip.setWritable(true); // necessary? - - try { - download(url, contribZip, downloadProgress); - - if (!downloadProgress.isCanceled() && !downloadProgress.isError()) { - installProgress.startTask(Language.text("contrib.progress.installing"), ProgressMonitor.UNKNOWN); - LocalContribution contribution = - ad.install(editor.getBase(), contribZip, false, status); - - if (contribution != null) { - contribListing.replaceContribution(ad, contribution); - if (contribution.getType() == ContributionType.MODE) { - ArrayList contribModes = editor.getBase().getModeContribs(); - if (!contribModes.contains(contribution)) - contribModes.add((ModeContribution) contribution); - } - refreshInstalled(editor); - } - installProgress.finished(); - } - else { - if (downloadProgress.exception instanceof SocketTimeoutException) { - status.setErrorMessage(Language - .interpolate("contrib.errors.contrib_download.timeout", - ad.getName())); - } else { - status.setErrorMessage(Language - .interpolate("contrib.errors.download_and_install", - ad.getName())); - } - } - contribZip.delete(); - - } catch (Exception e) { - // Hiding stack trace. The error message ought to suffice. -// e.printStackTrace(); - status - .setErrorMessage(Language - .interpolate("contrib.errors.download_and_install", - ad.getName())); - downloadProgress.cancel(); - installProgress.cancel(); - } - } catch (IOException e) { - status.setErrorMessage(Language.text("contrib.errors.temporary_directory")); - downloadProgress.cancel(); - installProgress.cancel(); - } - } - }, "Contribution Installer").start(); - } - - - - /** - * Non-blocking call to download and install a contribution in a new thread. - * - * @param url - * Direct link to the contribution. - * @param ad - * The AvailableContribution to be downloaded and installed. - */ - static void downloadAndInstallOnStartup(final Base base, final URL url, - final AvailableContribution ad) { - - new Thread(new Runnable() { - public void run() { - String filename = url.getFile(); - filename = filename.substring(filename.lastIndexOf('/') + 1); - try { - File contribZip = File.createTempFile("download", filename); - contribZip.setWritable(true); // necessary? - - try { - download(url, contribZip, null); - - LocalContribution contribution = ad.install(base, contribZip, - false, null); - - if (contribution != null) { - contribListing.replaceContribution(ad, contribution); - if (contribution.getType() == ContributionType.MODE) { - ArrayList contribModes = base - .getModeContribs(); - if (contribModes != null && !contribModes.contains(contribution)) { - contribModes.add((ModeContribution) contribution); - } - } - if (base.getActiveEditor() != null) - refreshInstalled(base.getActiveEditor()); - } - - contribZip.delete(); - - handleUpdateFailedMarkers(ad, filename.substring(0, filename.lastIndexOf('.'))); - - } catch (Exception e) { -// Chuck the stack trace. The user might have no idea why it is appearing, or what (s)he did wrong... -// e.printStackTrace(); - System.out.println("Error during download and install of " - + ad.getName()); - } - } catch (IOException e) { - System.err - .println("Could not write to temporary directory during download and install of " - + ad.getName()); - } - } - }, "Contribution Installer").start(); - } - - -/** - * After install, this function checks whether everything went properly or not. - * If not, it adds a marker file so that the next time Processing is started, installPreviouslyFailed() - * can install the contribution. - * @param ac - * The contribution just installed. - * @param filename - * The name of the folder in which the contribution is supposed to be stored. - */ - static private void handleUpdateFailedMarkers(final AvailableContribution ac, String filename) { - - File contribLocn = ac.getType().getSketchbookFolder(); - - for (File contribDir : contribLocn.listFiles()) - if (contribDir.isDirectory()) { - File[] contents = contribDir.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File dir, String file) { - return file.equals(ac.getType() + ".properties"); - } - }); - if (contents.length > 0 && Base.readSettings(contents[0]).get("name").equals(ac.getName())) { - return; - } - } - - try { - new File(contribLocn, ac.getName()).createNewFile(); - } catch (IOException e) { -// Again, forget about the stack trace. The user ain't done wrong -// e.printStackTrace(); - System.err.println("The unupdated contribution marker seems to not like " - + ac.getName() + ". You may have to install it manually to update..."); - } - - } - - - static public void refreshInstalled(Editor e) { - - Iterator iter = e.getBase().getEditors().iterator(); - while (iter.hasNext()) { - Editor ed = iter.next(); - ed.getMode().rebuildImportMenu(); - ed.getMode().resetExamples(); - ed.rebuildToolMenu(); - ed.rebuildModeMenu(); - } - } - - - /** - * Returns a file in the parent folder that does not exist yet. If - * parent/fileName already exists, this will look for parent/fileName(2) - * then parent/fileName(3) and so forth. - * - * @return a file that does not exist yet - */ - public static File getUniqueName(File parentFolder, String fileName) { - File backupFolderForLib; - int i = 1; - do { - String folderName = fileName; - if (i >= 2) { - folderName += "(" + i + ")"; - } - i++; - - backupFolderForLib = new File(parentFolder, folderName); - } while (backupFolderForLib.exists()); - - return backupFolderForLib; - } - - - /** - * Returns the name of a file without its path or extension. - * - * For example, - * "/path/to/helpfullib.zip" returns "helpfullib" - * "helpfullib-0.1.1.plb" returns "helpfullib-0.1.1" - */ - static public String getFileName(File libFile) { - String path = libFile.getPath(); - int lastSeparator = path.lastIndexOf(File.separatorChar); - - String fileName; - if (lastSeparator != -1) { - fileName = path.substring(lastSeparator + 1); - } else { - fileName = path; - } - - int lastDot = fileName.lastIndexOf('.'); - if (lastDot != -1) { - return fileName.substring(0, lastDot); - } - - return fileName; - } - - - /** - * Called by Base to clean up entries previously marked for deletion - * and remove any "requires restart" flags. - * Also updates all entries previously marked for update. - */ - static public void cleanup(final Base base) throws Exception { - - deleteTemp(Base.getSketchbookModesFolder()); - deleteTemp(Base.getSketchbookToolsFolder()); - - deleteFlagged(Base.getSketchbookLibrariesFolder()); - deleteFlagged(Base.getSketchbookModesFolder()); - deleteFlagged(Base.getSketchbookToolsFolder()); - - installPreviouslyFailed(base, Base.getSketchbookModesFolder()); - updateFlagged(base, Base.getSketchbookModesFolder()); - - updateFlagged(base, Base.getSketchbookToolsFolder()); - - SwingWorker s = new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - try { - Thread.sleep(1 * 1000); - installPreviouslyFailed(base, Base.getSketchbookToolsFolder()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - }; - s.execute(); - - - - clearRestartFlags(Base.getSketchbookModesFolder()); - clearRestartFlags(Base.getSketchbookToolsFolder()); - } - - - /** - * Deletes the icky tmp folders that were left over from installs and updates - * in the previous run of Processing. Needed to be called only on the tools - * and modes sketchbook folders. - * - * @param root - */ - static private void deleteTemp(File root) { - - LinkedList deleteList = new LinkedList(); - - for (File f : root.listFiles()) - if (f.getName().matches(root.getName().substring(0, 4) + "\\d*" + "tmp")) - deleteList.add(f); - - Iterator folderIter = deleteList.iterator(); - - while (folderIter.hasNext()) { - Base.removeDir(folderIter.next()); - } - } - - - /** - * Deletes all the modes/tools/libs that are flagged for removal. - * - * @param root - * @throws Exception - */ - static private void deleteFlagged(File root) throws Exception { - File[] markedForDeletion = root.listFiles(new FileFilter() { - public boolean accept(File folder) { - return (folder.isDirectory() && LocalContribution - .isDeletionFlagged(folder)); - } - }); - for (File folder : markedForDeletion) { - Base.removeDir(folder); - } - } - - - /** - * Installs all the modes/tools whose installation failed during an - * auto-update the previous time Processing was started up. - * - * @param base - * @param root - * @throws Exception - */ - static private void installPreviouslyFailed(Base base, File root) throws Exception { - File[] installList = root.listFiles(new FileFilter() { - public boolean accept(File folder) { - return (folder.isFile()); - } - }); - - for (File file : installList) { - Iterator iter = contribListing.advertisedContributions.iterator(); - while (iter.hasNext()) { - AvailableContribution availableContrib = iter.next(); - if (file.getName().equals(availableContrib.getName())) { - file.delete(); - installOnStartUp(base, availableContrib); - contribListing - .replaceContribution(availableContrib, availableContrib); - } - } - } - } - - - /** - * Updates all the flagged modes/tools. - * - * @param base - * @param root - * @throws Exception - */ - static private void updateFlagged(Base base, File root) throws Exception { - File[] markedForUpdate = root.listFiles(new FileFilter() { - public boolean accept(File folder) { - return (folder.isDirectory() && LocalContribution - .isUpdateFlagged(folder)); - } - }); - - ArrayList updateContribsNames = new ArrayList(); - LinkedList updateContribsList = new LinkedList(); - - String type = root.getName().substring(root.getName().lastIndexOf('/') + 1); - String propFileName = null; - - if (type.equalsIgnoreCase("tools")) - propFileName = "tool.properties"; - else if (type.equalsIgnoreCase("modes")) - propFileName = "mode.properties"; - else if (type.equalsIgnoreCase("libraries")) //putting this here, just in case - propFileName = "libraries.properties"; - - for (File folder : markedForUpdate) { - HashMap properties = Base - .readSettings(new File(folder, propFileName)); - updateContribsNames.add(properties.get("name")); - Base.removeDir(folder); - } - - Iterator iter = contribListing.advertisedContributions.iterator(); - while (iter.hasNext()) { - AvailableContribution availableContribs = iter.next(); - if (updateContribsNames.contains(availableContribs.getName())) { - updateContribsList.add(availableContribs); - } - } - - Iterator iter2 = updateContribsList.iterator(); - while (iter2.hasNext()) { - AvailableContribution contribToUpdate = iter2.next(); - installOnStartUp(base, contribToUpdate); - contribListing.replaceContribution(contribToUpdate, contribToUpdate); - } - } - - - static private void installOnStartUp(final Base base, final AvailableContribution availableContrib) { - if (availableContrib.link == null) { - Base.showWarning(Language.interpolate("contrib.errors.update_on_restart_failed", availableContrib.getName()), - Language.text("contrib.unsupported_operating_system")); - return; - } - try { - URL downloadUrl = new URL(availableContrib.link); - - ContributionManager.downloadAndInstallOnStartup(base, downloadUrl, availableContrib); - - } catch (MalformedURLException e) { - Base.showWarning(Language.interpolate("contrib.errors.update_on_restart_failed", availableContrib.getName()), - Language.text("contrib.errors.malformed_url"), e); - } - } - - - static private void clearRestartFlags(File root) throws Exception { - File[] folderList = root.listFiles(new FileFilter() { - public boolean accept(File folder) { - return folder.isDirectory(); - } - }); - for (File folder : folderList) { - LocalContribution.clearRestartFlags(folder); - } - } -} +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2011-12 Ben Fry and Casey Reas + + 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.contrib; + +import java.io.*; +import java.net.*; +import java.util.*; + +import javax.swing.SwingWorker; + +import processing.app.Base; +import processing.app.Editor; +import processing.app.Language; + + +public class ContributionManager { + static public final ContributionListing contribListing; + + static { + contribListing = ContributionListing.getInstance(); + } + + + /** + * Blocks until the file is downloaded or an error occurs. Returns true if the + * file was successfully downloaded, false otherwise. + * + * @param source + * the URL of the file to download + * @param dest + * the file on the local system where the file will be written. This + * must be a file (not a directory), and must already exist. + * @param progress + * null if progress is irrelevant, such as when downloading for an + * install during startup, when the ProgressMonitor is useless since + * UI isn't setup yet. + * @throws FileNotFoundException + * if an error occurred downloading the file + */ + static boolean download(URL source, File dest, ProgressMonitor progress) { + boolean success = false; + try { +// System.out.println("downloading file " + source); +// URLConnection conn = source.openConnection(); + HttpURLConnection conn = (HttpURLConnection) source.openConnection(); + HttpURLConnection.setFollowRedirects(true); + conn.setConnectTimeout(15 * 1000); + conn.setReadTimeout(60 * 1000); + conn.setRequestMethod("GET"); + conn.connect(); + + if (progress != null) { + // TODO this is often -1, may need to set progress to indeterminate + int fileSize = conn.getContentLength(); +// System.out.println("file size is " + fileSize); + progress.startTask(Language.text("contrib.progress.downloading"), fileSize); + } + + InputStream in = conn.getInputStream(); + FileOutputStream out = new FileOutputStream(dest); + + byte[] b = new byte[8192]; + int amount; + if (progress != null) { + int total = 0; + while (!progress.isCanceled() && (amount = in.read(b)) != -1) { + out.write(b, 0, amount); + total += amount; + progress.setProgress(total); + } + } else { + while ((amount = in.read(b)) != -1) { + out.write(b, 0, amount); + } + } + out.flush(); + out.close(); + success = true; + + } catch (SocketTimeoutException ste) { + if (progress != null) { + progress.error(ste); + progress.cancel(); + } + } catch (IOException ioe) { + if (progress != null) { + progress.error(ioe); + progress.cancel(); + } + // Hiding stack trace. An error has been shown where needed. +// ioe.printStackTrace(); + } + if (progress != null) + progress.finished(); + return success; + } + + + /** + * Non-blocking call to download and install a contribution in a new thread. + * + * @param url + * Direct link to the contribution. + * @param toBeReplaced + * The Contribution that will be replaced by this library being + * installed (e.g. an advertised version of a contribution, or the + * old version of a contribution that is being updated). Must not be + * null. + */ + static void downloadAndInstall(final Editor editor, + final URL url, + final AvailableContribution ad, + final JProgressMonitor downloadProgress, + final JProgressMonitor installProgress, + final StatusPanel status) { + + new Thread(new Runnable() { + public void run() { + String filename = url.getFile(); + filename = filename.substring(filename.lastIndexOf('/') + 1); + try { + File contribZip = File.createTempFile("download", filename); + contribZip.setWritable(true); // necessary? + + try { + download(url, contribZip, downloadProgress); + + if (!downloadProgress.isCanceled() && !downloadProgress.isError()) { + installProgress.startTask(Language.text("contrib.progress.installing"), ProgressMonitor.UNKNOWN); + LocalContribution contribution = + ad.install(editor.getBase(), contribZip, false, status); + + if (contribution != null) { + contribListing.replaceContribution(ad, contribution); + if (contribution.getType() == ContributionType.MODE) { + ArrayList contribModes = editor.getBase().getModeContribs(); + if (!contribModes.contains(contribution)) + contribModes.add((ModeContribution) contribution); + } + refreshInstalled(editor); + } + installProgress.finished(); + } + else { + if (downloadProgress.exception instanceof SocketTimeoutException) { + status.setErrorMessage(Language + .interpolate("contrib.errors.contrib_download.timeout", + ad.getName())); + } else { + status.setErrorMessage(Language + .interpolate("contrib.errors.download_and_install", + ad.getName())); + } + } + contribZip.delete(); + + } catch (Exception e) { + // Hiding stack trace. The error message ought to suffice. +// e.printStackTrace(); + status + .setErrorMessage(Language + .interpolate("contrib.errors.download_and_install", + ad.getName())); + downloadProgress.cancel(); + installProgress.cancel(); + } + } catch (IOException e) { + status.setErrorMessage(Language.text("contrib.errors.temporary_directory")); + downloadProgress.cancel(); + installProgress.cancel(); + } + } + }, "Contribution Installer").start(); + } + + + + /** + * Non-blocking call to download and install a contribution in a new thread. + * + * @param url + * Direct link to the contribution. + * @param ad + * The AvailableContribution to be downloaded and installed. + */ + static void downloadAndInstallOnStartup(final Base base, final URL url, + final AvailableContribution ad) { + + new Thread(new Runnable() { + public void run() { + String filename = url.getFile(); + filename = filename.substring(filename.lastIndexOf('/') + 1); + try { + File contribZip = File.createTempFile("download", filename); + contribZip.setWritable(true); // necessary? + + try { + download(url, contribZip, null); + + LocalContribution contribution = ad.install(base, contribZip, + false, null); + + if (contribution != null) { + contribListing.replaceContribution(ad, contribution); + if (contribution.getType() == ContributionType.MODE) { + ArrayList contribModes = base + .getModeContribs(); + if (contribModes != null && !contribModes.contains(contribution)) { + contribModes.add((ModeContribution) contribution); + } + } + if (base.getActiveEditor() != null) + refreshInstalled(base.getActiveEditor()); + } + + contribZip.delete(); + + handleUpdateFailedMarkers(ad, filename.substring(0, filename.lastIndexOf('.'))); + + } catch (Exception e) { +// Chuck the stack trace. The user might have no idea why it is appearing, or what (s)he did wrong... +// e.printStackTrace(); + System.out.println("Error during download and install of " + + ad.getName()); + } + } catch (IOException e) { + System.err + .println("Could not write to temporary directory during download and install of " + + ad.getName()); + } + } + }, "Contribution Installer").start(); + } + + +/** + * After install, this function checks whether everything went properly or not. + * If not, it adds a marker file so that the next time Processing is started, installPreviouslyFailed() + * can install the contribution. + * @param ac + * The contribution just installed. + * @param filename + * The name of the folder in which the contribution is supposed to be stored. + */ + static private void handleUpdateFailedMarkers(final AvailableContribution ac, String filename) { + + File contribLocn = ac.getType().getSketchbookFolder(); + + for (File contribDir : contribLocn.listFiles()) + if (contribDir.isDirectory()) { + File[] contents = contribDir.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String file) { + return file.equals(ac.getType() + ".properties"); + } + }); + if (contents.length > 0 && Base.readSettings(contents[0]).get("name").equals(ac.getName())) { + return; + } + } + + try { + new File(contribLocn, ac.getName()).createNewFile(); + } catch (IOException e) { +// Again, forget about the stack trace. The user ain't done wrong +// e.printStackTrace(); + System.err.println("The unupdated contribution marker seems to not like " + + ac.getName() + ". You may have to install it manually to update..."); + } + + } + + + static public void refreshInstalled(Editor e) { + + Iterator iter = e.getBase().getEditors().iterator(); + while (iter.hasNext()) { + Editor ed = iter.next(); + ed.getMode().rebuildImportMenu(); + ed.getMode().resetExamples(); + ed.rebuildToolMenu(); + ed.rebuildModeMenu(); + } + } + + + /** + * Returns a file in the parent folder that does not exist yet. If + * parent/fileName already exists, this will look for parent/fileName(2) + * then parent/fileName(3) and so forth. + * + * @return a file that does not exist yet + */ + public static File getUniqueName(File parentFolder, String fileName) { + File backupFolderForLib; + int i = 1; + do { + String folderName = fileName; + if (i >= 2) { + folderName += "(" + i + ")"; + } + i++; + + backupFolderForLib = new File(parentFolder, folderName); + } while (backupFolderForLib.exists()); + + return backupFolderForLib; + } + + + /** + * Returns the name of a file without its path or extension. + * + * For example, + * "/path/to/helpfullib.zip" returns "helpfullib" + * "helpfullib-0.1.1.plb" returns "helpfullib-0.1.1" + */ + static public String getFileName(File libFile) { + String path = libFile.getPath(); + int lastSeparator = path.lastIndexOf(File.separatorChar); + + String fileName; + if (lastSeparator != -1) { + fileName = path.substring(lastSeparator + 1); + } else { + fileName = path; + } + + int lastDot = fileName.lastIndexOf('.'); + if (lastDot != -1) { + return fileName.substring(0, lastDot); + } + + return fileName; + } + + + /** + * Called by Base to clean up entries previously marked for deletion + * and remove any "requires restart" flags. + * Also updates all entries previously marked for update. + */ + static public void cleanup(final Base base) throws Exception { + + deleteTemp(Base.getSketchbookModesFolder()); + deleteTemp(Base.getSketchbookToolsFolder()); + + deleteFlagged(Base.getSketchbookLibrariesFolder()); + deleteFlagged(Base.getSketchbookModesFolder()); + deleteFlagged(Base.getSketchbookToolsFolder()); + + installPreviouslyFailed(base, Base.getSketchbookModesFolder()); + updateFlagged(base, Base.getSketchbookModesFolder()); + + updateFlagged(base, Base.getSketchbookToolsFolder()); + + SwingWorker s = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + try { + Thread.sleep(1 * 1000); + installPreviouslyFailed(base, Base.getSketchbookToolsFolder()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return null; + } + }; + s.execute(); + + + + clearRestartFlags(Base.getSketchbookModesFolder()); + clearRestartFlags(Base.getSketchbookToolsFolder()); + } + + + /** + * Deletes the icky tmp folders that were left over from installs and updates + * in the previous run of Processing. Needed to be called only on the tools + * and modes sketchbook folders. + * + * @param root + */ + static private void deleteTemp(File root) { + + LinkedList deleteList = new LinkedList(); + + for (File f : root.listFiles()) + if (f.getName().matches(root.getName().substring(0, 4) + "\\d*" + "tmp")) + deleteList.add(f); + + Iterator folderIter = deleteList.iterator(); + + while (folderIter.hasNext()) { + Base.removeDir(folderIter.next()); + } + } + + + /** + * Deletes all the modes/tools/libs that are flagged for removal. + * + * @param root + * @throws Exception + */ + static private void deleteFlagged(File root) throws Exception { + File[] markedForDeletion = root.listFiles(new FileFilter() { + public boolean accept(File folder) { + return (folder.isDirectory() && LocalContribution + .isDeletionFlagged(folder)); + } + }); + for (File folder : markedForDeletion) { + Base.removeDir(folder); + } + } + + + /** + * Installs all the modes/tools whose installation failed during an + * auto-update the previous time Processing was started up. + * + * @param base + * @param root + * @throws Exception + */ + static private void installPreviouslyFailed(Base base, File root) throws Exception { + File[] installList = root.listFiles(new FileFilter() { + public boolean accept(File folder) { + return (folder.isFile()); + } + }); + + for (File file : installList) { + Iterator iter = contribListing.advertisedContributions.iterator(); + while (iter.hasNext()) { + AvailableContribution availableContrib = iter.next(); + if (file.getName().equals(availableContrib.getName())) { + file.delete(); + installOnStartUp(base, availableContrib); + contribListing + .replaceContribution(availableContrib, availableContrib); + } + } + } + } + + + /** + * Updates all the flagged modes/tools. + * + * @param base + * @param root + * @throws Exception + */ + static private void updateFlagged(Base base, File root) throws Exception { + File[] markedForUpdate = root.listFiles(new FileFilter() { + public boolean accept(File folder) { + return (folder.isDirectory() && LocalContribution + .isUpdateFlagged(folder)); + } + }); + + ArrayList updateContribsNames = new ArrayList(); + LinkedList updateContribsList = new LinkedList(); + + String type = root.getName().substring(root.getName().lastIndexOf('/') + 1); + String propFileName = null; + + if (type.equalsIgnoreCase("tools")) + propFileName = "tool.properties"; + else if (type.equalsIgnoreCase("modes")) + propFileName = "mode.properties"; + else if (type.equalsIgnoreCase("libraries")) //putting this here, just in case + propFileName = "libraries.properties"; + + for (File folder : markedForUpdate) { + HashMap properties = Base + .readSettings(new File(folder, propFileName)); + updateContribsNames.add(properties.get("name")); + Base.removeDir(folder); + } + + Iterator iter = contribListing.advertisedContributions.iterator(); + while (iter.hasNext()) { + AvailableContribution availableContribs = iter.next(); + if (updateContribsNames.contains(availableContribs.getName())) { + updateContribsList.add(availableContribs); + } + } + + Iterator iter2 = updateContribsList.iterator(); + while (iter2.hasNext()) { + AvailableContribution contribToUpdate = iter2.next(); + installOnStartUp(base, contribToUpdate); + contribListing.replaceContribution(contribToUpdate, contribToUpdate); + } + } + + + static private void installOnStartUp(final Base base, final AvailableContribution availableContrib) { + if (availableContrib.link == null) { + Base.showWarning(Language.interpolate("contrib.errors.update_on_restart_failed", availableContrib.getName()), + Language.text("contrib.unsupported_operating_system")); + return; + } + try { + URL downloadUrl = new URL(availableContrib.link); + + ContributionManager.downloadAndInstallOnStartup(base, downloadUrl, availableContrib); + + } catch (MalformedURLException e) { + Base.showWarning(Language.interpolate("contrib.errors.update_on_restart_failed", availableContrib.getName()), + Language.text("contrib.errors.malformed_url"), e); + } + } + + + static private void clearRestartFlags(File root) throws Exception { + File[] folderList = root.listFiles(new FileFilter() { + public boolean accept(File folder) { + return folder.isDirectory(); + } + }); + for (File folder : folderList) { + LocalContribution.clearRestartFlags(folder); + } + } +} diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java index bb6faf1ea..929625cd0 100644 --- a/app/src/processing/app/contrib/LocalContribution.java +++ b/app/src/processing/app/contrib/LocalContribution.java @@ -1,677 +1,677 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas - - 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.contrib; - -import java.io.*; -import java.net.URL; -import java.net.URLClassLoader; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.zip.*; - -import javax.swing.JOptionPane; - -import processing.app.*; -import processing.core.PApplet; - - -/** - * A contribution that has been downloaded to the disk, and may or may not - * be installed. - */ -public abstract class LocalContribution extends Contribution { - static public final String DELETION_FLAG = "marked_for_deletion"; - static public final String UPDATE_FLAGGED = "marked_for_update"; - static public final String RESTART_FLAG = "requires_restart"; - - protected String id; // 1 (unique id for this library) - protected int latestVersion; // 103 - protected File folder; - protected HashMap properties; - protected ClassLoader loader; - - - public LocalContribution(File folder) { - this.folder = folder; - - // required for contributed modes, but not for built-in core modes - File propertiesFile = new File(folder, getTypeName() + ".properties"); - if (propertiesFile.exists()) { - properties = Base.readSettings(propertiesFile); - - name = properties.get("name"); - id = properties.get("id"); - categories = parseCategories(properties.get("category")); - if (name == null) { - name = folder.getName(); - } - authorList = properties.get("authorList"); - url = properties.get("url"); - sentence = properties.get("sentence"); - paragraph = properties.get("paragraph"); - - try { - version = Integer.parseInt(properties.get("version")); - } catch (NumberFormatException e) { - System.err.println("The version number for the “" + name + "” library is not set properly."); - System.err.println("Please contact the library author to fix it according to the guidelines."); - } - - prettyVersion = properties.get("prettyVersion"); - - try { - lastUpdated = Long.parseLong(properties.get("lastUpdated")); - } catch (NumberFormatException e) { - lastUpdated = 0; - - // Better comment these out till all contribs have a lastUpdated -// System.err.println("The last updated timestamp for the “" + name + "” library is not set properly."); -// System.err.println("Please contact the library author to fix it according to the guidelines."); - } - - String minRev = properties.get("minRevision"); - if (minRev != null) { - minRevision = PApplet.parseInt(minRev, 0); - } - - String maxRev = properties.get("maxRevision"); - if (maxRev != null) { - maxRevision = PApplet.parseInt(maxRev, 0); - } - - } else { - Base.log("No properties file at " + propertiesFile.getAbsolutePath()); - // We'll need this to be set at a minimum. - name = folder.getName(); - categories = defaultCategory(); - } - - if (categories.contains(SPECIAL_CATEGORY_NAME)) - validateSpecial(); - } - - - private void validateSpecial() { - for (AvailableContribution available : ContributionListing.getInstance().advertisedContributions) - if (available.getName().equals(name)) { - if (!available.isSpecial()) - categories.remove(SPECIAL_CATEGORY_NAME); - } - return; - } - - - public String initLoader(String className) throws Exception { - File modeDirectory = new File(folder, getTypeName()); - if (modeDirectory.exists()) { - Base.log("checking mode folder regarding " + className); - // If no class name specified, search the main .jar for the - // full name package and mode name. - if (className == null) { - String shortName = folder.getName(); - File mainJar = new File(modeDirectory, shortName + ".jar"); - if (mainJar.exists()) { - className = findClassInZipFile(shortName, mainJar); - } else { - throw new IgnorableException(mainJar.getAbsolutePath() + " does not exist."); - } - - if (className == null) { - throw new IgnorableException("Could not find " + shortName + - " class inside " + mainJar.getAbsolutePath()); - } - } - - // Add .jar and .zip files from the "mode" folder into the classpath - File[] archives = Base.listJarFiles(modeDirectory); - if (archives != null && archives.length > 0) { - URL[] urlList = new URL[archives.length]; - for (int j = 0; j < urlList.length; j++) { - Base.log("Found archive " + archives[j] + " for " + getName()); - urlList[j] = archives[j].toURI().toURL(); - } -// loader = new URLClassLoader(urlList, Thread.currentThread().getContextClassLoader()); - loader = new URLClassLoader(urlList); - Base.log("loading above JARs with loader " + loader); -// System.out.println("listing classes for loader " + loader); -// listClasses(loader); - } - } - - // If no archives were found, just use the regular ClassLoader - if (loader == null) { - loader = Thread.currentThread().getContextClassLoader(); - } - return className; - } - - - /* - // doesn't work with URLClassLoader, but works with the system CL - static void listClasses(ClassLoader loader) { -// loader = Thread.currentThread().getContextClassLoader(); - try { - Field f = ClassLoader.class.getDeclaredField("classes"); - f.setAccessible(true); - Vector classes = (Vector) f.get(loader); - for (Class c : classes) { - System.out.println(c.getName()); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - */ - - -// static protected boolean isCandidate(File potential, final ContributionType type) { -// return (potential.isDirectory() && -// new File(potential, type.getFolderName()).exists()); -// } -// -// -// /** -// * Return a list of directories that have the necessary subfolder for this -// * contribution type. For instance, a list of folders that have a 'mode' -// * subfolder if this is a ModeContribution. -// */ -// static protected File[] listCandidates(File folder, final ContributionType type) { -// return folder.listFiles(new FileFilter() { -// public boolean accept(File potential) { -// return isCandidate(potential, type); -// } -// }); -// } -// -// -// /** -// * Return the first directory that has the necessary subfolder for this -// * contribution type. For instance, the first folder that has a 'mode' -// * subfolder if this is a ModeContribution. -// */ -// static protected File findCandidate(File folder, final ContributionType type) { -// File[] folders = listCandidates(folder, type); -// -// if (folders.length == 0) { -// return null; -// -// } else if (folders.length > 1) { -// Base.log("More than one " + type.toString() + " found inside " + folder.getAbsolutePath()); -// } -// return folders[0]; -// } - - - LocalContribution copyAndLoad(Base base, - boolean confirmReplace, - StatusPanel status) { -// NOTE: null status => function is called on startup when Editor objects, et al. aren't ready - - String contribFolderName = getFolder().getName(); - - File contribTypeFolder = getType().getSketchbookFolder(); - File contribFolder = new File(contribTypeFolder, contribFolderName); - - if (status != null) { // when status != null, install is not occurring on startup - - Editor editor = base.getActiveEditor(); - - ArrayList oldContribs = - getType().listContributions(editor); - - // In case an update marker exists, and the user wants to install, delete the update marker - if (contribFolder.exists() && !contribFolder.isDirectory()) { - contribFolder.delete(); - contribFolder = new File(contribTypeFolder, contribFolderName); - } - - for (LocalContribution oldContrib : oldContribs) { - if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(contribFolder)) || - (oldContrib.getId() != null && oldContrib.getId().equals(getId()))) { - - if (oldContrib.getType().requiresRestart()) { - // XXX: We can't replace stuff, soooooo.... do something different - if (!oldContrib.backup(editor, false, status)) { - return null; - } - } else { - int result = 0; - boolean doBackup = Preferences.getBoolean("contribution.backup.on_install"); - if (confirmReplace) { - if (doBackup) { - result = Base.showYesNoQuestion(editor, "Replace", - "Replace pre-existing \"" + oldContrib.getName() + "\" library?", - "A pre-existing copy of the \"" + oldContrib.getName() + "\" library
"+ - "has been found in your sketchbook. Clicking “Yes”
"+ - "will move the existing library to a backup folder
" + - "in libraries/old before replacing it."); - if (result != JOptionPane.YES_OPTION || !oldContrib.backup(editor, true, status)) { - return null; - } - } else { - result = Base.showYesNoQuestion(editor, "Replace", - "Replace pre-existing \"" + oldContrib.getName() + "\" library?", - "A pre-existing copy of the \"" + oldContrib.getName() + "\" library
"+ - "has been found in your sketchbook. Clicking “Yes”
"+ - "will permanently delete this library and all of its contents
"+ - "before replacing it."); - if (result != JOptionPane.YES_OPTION || !oldContrib.getFolder().delete()) { - return null; - } - } - } else { - if ((doBackup && !oldContrib.backup(editor, true, status)) || - (!doBackup && !oldContrib.getFolder().delete())) { - return null; - } - } - } - } - } - - // At this point it should be safe to replace this fella - if (contribFolder.exists()) { - Base.removeDir(contribFolder); - } - - } - else { - // This if should ideally never happen, since this function is to be called only when restarting on update - if (contribFolder.exists() && contribFolder.isDirectory()) { - Base.removeDir(contribFolder); - } - else if (contribFolder.exists()) { - contribFolder.delete(); - contribFolder = new File(contribTypeFolder, contribFolderName); - } - } - - File oldFolder = getFolder(); - - try { - Base.copyDir(oldFolder, contribFolder); - } catch (IOException e) { - status.setErrorMessage("Could not copy " + getTypeName() + - " \"" + getName() + "\" to the sketchbook."); - e.printStackTrace(); - return null; - } - - - /* - if (!getFolder().renameTo(contribFolder)) { - status.setErrorMessage("Could not move " + getTypeName() + - " \"" + getName() + "\" to the sketchbook."); - return null; - } - */ - - return getType().load(base, contribFolder); - } - - - /** - * Moves the given contribution to a backup folder. - * @param deleteOriginal - * true if the file should be moved to the directory, false if it - * should instead be copied, leaving the original in place - */ - boolean backup(Editor editor, boolean deleteOriginal, StatusPanel status) { - File backupFolder = getType().createBackupFolder(status); - - boolean success = false; - if (backupFolder != null) { - String libFolderName = getFolder().getName(); - String prefix = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); - final String backupName = prefix + " " + libFolderName; - File backupSubFolder = - ContributionManager.getUniqueName(backupFolder, backupName); - - if (deleteOriginal) { - success = getFolder().renameTo(backupSubFolder); - } else { - try { - Base.copyDir(getFolder(), backupSubFolder); - success = true; - } catch (IOException e) { } - } - if (!success) { - status.setErrorMessage("Could not move contribution to backup folder."); - } - } - return success; - } - - - /** - * Non-blocking call to remove a contribution in a new thread. - */ - void removeContribution(final Editor editor, - final ProgressMonitor pm, - final StatusPanel status) { - new Thread(new Runnable() { - public void run() { - remove(editor, - pm, - status, - ContributionListing.getInstance()); - } - }, "Contribution Uninstaller").start(); - } - - - void remove(final Editor editor, - final ProgressMonitor pm, - final StatusPanel status, - final ContributionListing contribListing) { - pm.startTask("Removing", ProgressMonitor.UNKNOWN); - - boolean doBackup = Preferences.getBoolean("contribution.backup.on_remove"); -// if (getType().requiresRestart()) { -// if (!doBackup || (doBackup && backup(editor, false, status))) { -// if (setDeletionFlag(true)) { -// contribListing.replaceContribution(this, this); -// } -// } -// } else { - boolean success = false; - if (getType() == ContributionType.MODE) { - boolean isModeActive = false; - ModeContribution m = (ModeContribution) this; - Iterator iter = editor.getBase().getEditors().iterator(); - while (iter.hasNext()) { - Editor e = iter.next(); - if (e.getMode().equals(m.getMode())) { - isModeActive = true; - break; - } - } - if (!isModeActive) - m.clearClassLoader(editor.getBase()); - else { - pm.cancel(); - Base.showMessage("Mode Manager", - "Please save your Sketch and change the Mode of all Editor\nwindows that have " - + this.name + " as the active Mode."); - return; - } - } - - if (getType() == ContributionType.TOOL) { - ToolContribution t = (ToolContribution) this; - Iterator iter = editor.getBase().getEditors().iterator(); - while (iter.hasNext()) { - Editor ed = iter.next(); - ed.clearToolMenu(); - } - t.clearClassLoader(editor.getBase()); - } - - if (doBackup) { - success = backup(editor, true, status); - } else { - Base.removeDir(getFolder()); - success = !getFolder().exists(); - } - - if (success) { - if (getType() == ContributionType.TOOL) { - editor.removeTool(); - } - - Contribution advertisedVersion = contribListing - .getAvailableContribution(this); - - if (advertisedVersion == null) { - contribListing.removeContribution(this); - } else { - contribListing.replaceContribution(this, advertisedVersion); - } - } - else { - // There was a failure backing up the folder - if (!doBackup || (doBackup && backup(editor, false, status))) { - if (setDeletionFlag(true)) { - contribListing.replaceContribution(this, this); - } - } - else - status.setErrorMessage("Could not delete the contribution's files"); - } -// } - ContributionManager.refreshInstalled(editor); - if (success) - pm.finished(); - else - pm.cancel(); - } - - - public File getFolder() { - return folder; - } - - - public boolean isInstalled() { - return folder != null; - } - - -// public String getCategory() { -// return category; -// } -// -// -// public String getName() { -// return name; -// } - - - public String getId() { - return id; - } - - -// public String getAuthorList() { -// return authorList; -// } -// -// -// public String getUrl() { -// return url; -// } -// -// -// public String getSentence() { -// return sentence; -// } -// -// -// public String getParagraph() { -// return paragraph; -// } -// -// -// public int getVersion() { -// return version; -// } - - - public int getLatestVersion() { - return latestVersion; - } - - -// public String getPrettyVersion() { -// return prettyVersion; -// } -// -// -// public String getTypeName() { -// return getType().toString(); -// } - - - /* - static protected String findClassInZipFileList(String base, File[] fileList) { - for (File file : fileList) { - String found = findClassInZipFile(base, file); - if (found != null) { - return found; - } - } - return null; - } - */ - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - boolean setDeletionFlag(boolean flag) { - return setFlag(DELETION_FLAG, flag); - } - - - boolean isDeletionFlagged() { - return isDeletionFlagged(getFolder()); - } - - - static boolean isDeletionFlagged(File folder) { - return isFlagged(folder, DELETION_FLAG); - } - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - boolean setUpdateFlag(boolean flag) { - return setFlag(UPDATE_FLAGGED, flag); - } - - - boolean isUpdateFlagged() { - return isUpdateFlagged(getFolder()); - } - - - static boolean isUpdateFlagged(File folder) { - return isFlagged(folder, UPDATE_FLAGGED); - } - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - boolean setRestartFlag() { - //System.out.println("setting restart flag for " + folder); - return setFlag(RESTART_FLAG, true); - } - - - @Override - boolean isRestartFlagged() { - //System.out.println("checking for restart inside LocalContribution for " + getName()); - return isFlagged(getFolder(), RESTART_FLAG); - } - - - static void clearRestartFlags(File folder) { - File restartFlag = new File(folder, RESTART_FLAG); - if (restartFlag.exists()) { - restartFlag.delete(); - } - } - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - private boolean setFlag(String flagFilename, boolean flag) { - if (flag) { - // Only returns false if the file already exists, so we can - // ignore the return value. - try { - new File(getFolder(), flagFilename).createNewFile(); - return true; - } catch (IOException e) { - return false; - } - } else { - return new File(getFolder(), flagFilename).delete(); - } - } - - - static private boolean isFlagged(File folder, String flagFilename) { - return new File(folder, flagFilename).exists(); - } - - - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - - /** - * - * @param base name of the class, with or without the package - * @param file - * @return name of class (with full package name) or null if not found - */ - static protected String findClassInZipFile(String base, File file) { - // Class file to search for - String classFileName = "/" + base + ".class"; - - try { - ZipFile zipFile = new ZipFile(file); - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = (ZipEntry) entries.nextElement(); - - if (!entry.isDirectory()) { - String name = entry.getName(); -// System.out.println("entry: " + name); - - if (name.endsWith(classFileName)) { - //int slash = name.lastIndexOf('/'); - //String packageName = (slash == -1) ? "" : name.substring(0, slash); - // Remove .class and convert slashes to periods. - zipFile.close(); - return name.substring(0, name.length() - 6).replace('/', '.'); - } - } - } - zipFile.close(); - } catch (IOException e) { - //System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")"); - e.printStackTrace(); - } - return null; - } - - - static protected class IgnorableException extends Exception { - public IgnorableException(String msg) { - super(msg); - } - } -} +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2011-12 Ben Fry and Casey Reas + + 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.contrib; + +import java.io.*; +import java.net.URL; +import java.net.URLClassLoader; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.zip.*; + +import javax.swing.JOptionPane; + +import processing.app.*; +import processing.core.PApplet; + + +/** + * A contribution that has been downloaded to the disk, and may or may not + * be installed. + */ +public abstract class LocalContribution extends Contribution { + static public final String DELETION_FLAG = "marked_for_deletion"; + static public final String UPDATE_FLAGGED = "marked_for_update"; + static public final String RESTART_FLAG = "requires_restart"; + + protected String id; // 1 (unique id for this library) + protected int latestVersion; // 103 + protected File folder; + protected HashMap properties; + protected ClassLoader loader; + + + public LocalContribution(File folder) { + this.folder = folder; + + // required for contributed modes, but not for built-in core modes + File propertiesFile = new File(folder, getTypeName() + ".properties"); + if (propertiesFile.exists()) { + properties = Base.readSettings(propertiesFile); + + name = properties.get("name"); + id = properties.get("id"); + categories = parseCategories(properties.get("category")); + if (name == null) { + name = folder.getName(); + } + authorList = properties.get("authorList"); + url = properties.get("url"); + sentence = properties.get("sentence"); + paragraph = properties.get("paragraph"); + + try { + version = Integer.parseInt(properties.get("version")); + } catch (NumberFormatException e) { + System.err.println("The version number for the “" + name + "” library is not set properly."); + System.err.println("Please contact the library author to fix it according to the guidelines."); + } + + prettyVersion = properties.get("prettyVersion"); + + try { + lastUpdated = Long.parseLong(properties.get("lastUpdated")); + } catch (NumberFormatException e) { + lastUpdated = 0; + + // Better comment these out till all contribs have a lastUpdated +// System.err.println("The last updated timestamp for the “" + name + "” library is not set properly."); +// System.err.println("Please contact the library author to fix it according to the guidelines."); + } + + String minRev = properties.get("minRevision"); + if (minRev != null) { + minRevision = PApplet.parseInt(minRev, 0); + } + + String maxRev = properties.get("maxRevision"); + if (maxRev != null) { + maxRevision = PApplet.parseInt(maxRev, 0); + } + + } else { + Base.log("No properties file at " + propertiesFile.getAbsolutePath()); + // We'll need this to be set at a minimum. + name = folder.getName(); + categories = defaultCategory(); + } + + if (categories.contains(SPECIAL_CATEGORY_NAME)) + validateSpecial(); + } + + + private void validateSpecial() { + for (AvailableContribution available : ContributionListing.getInstance().advertisedContributions) + if (available.getName().equals(name)) { + if (!available.isSpecial()) + categories.remove(SPECIAL_CATEGORY_NAME); + } + return; + } + + + public String initLoader(String className) throws Exception { + File modeDirectory = new File(folder, getTypeName()); + if (modeDirectory.exists()) { + Base.log("checking mode folder regarding " + className); + // If no class name specified, search the main .jar for the + // full name package and mode name. + if (className == null) { + String shortName = folder.getName(); + File mainJar = new File(modeDirectory, shortName + ".jar"); + if (mainJar.exists()) { + className = findClassInZipFile(shortName, mainJar); + } else { + throw new IgnorableException(mainJar.getAbsolutePath() + " does not exist."); + } + + if (className == null) { + throw new IgnorableException("Could not find " + shortName + + " class inside " + mainJar.getAbsolutePath()); + } + } + + // Add .jar and .zip files from the "mode" folder into the classpath + File[] archives = Base.listJarFiles(modeDirectory); + if (archives != null && archives.length > 0) { + URL[] urlList = new URL[archives.length]; + for (int j = 0; j < urlList.length; j++) { + Base.log("Found archive " + archives[j] + " for " + getName()); + urlList[j] = archives[j].toURI().toURL(); + } +// loader = new URLClassLoader(urlList, Thread.currentThread().getContextClassLoader()); + loader = new URLClassLoader(urlList); + Base.log("loading above JARs with loader " + loader); +// System.out.println("listing classes for loader " + loader); +// listClasses(loader); + } + } + + // If no archives were found, just use the regular ClassLoader + if (loader == null) { + loader = Thread.currentThread().getContextClassLoader(); + } + return className; + } + + + /* + // doesn't work with URLClassLoader, but works with the system CL + static void listClasses(ClassLoader loader) { +// loader = Thread.currentThread().getContextClassLoader(); + try { + Field f = ClassLoader.class.getDeclaredField("classes"); + f.setAccessible(true); + Vector classes = (Vector) f.get(loader); + for (Class c : classes) { + System.out.println(c.getName()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + */ + + +// static protected boolean isCandidate(File potential, final ContributionType type) { +// return (potential.isDirectory() && +// new File(potential, type.getFolderName()).exists()); +// } +// +// +// /** +// * Return a list of directories that have the necessary subfolder for this +// * contribution type. For instance, a list of folders that have a 'mode' +// * subfolder if this is a ModeContribution. +// */ +// static protected File[] listCandidates(File folder, final ContributionType type) { +// return folder.listFiles(new FileFilter() { +// public boolean accept(File potential) { +// return isCandidate(potential, type); +// } +// }); +// } +// +// +// /** +// * Return the first directory that has the necessary subfolder for this +// * contribution type. For instance, the first folder that has a 'mode' +// * subfolder if this is a ModeContribution. +// */ +// static protected File findCandidate(File folder, final ContributionType type) { +// File[] folders = listCandidates(folder, type); +// +// if (folders.length == 0) { +// return null; +// +// } else if (folders.length > 1) { +// Base.log("More than one " + type.toString() + " found inside " + folder.getAbsolutePath()); +// } +// return folders[0]; +// } + + + LocalContribution copyAndLoad(Base base, + boolean confirmReplace, + StatusPanel status) { +// NOTE: null status => function is called on startup when Editor objects, et al. aren't ready + + String contribFolderName = getFolder().getName(); + + File contribTypeFolder = getType().getSketchbookFolder(); + File contribFolder = new File(contribTypeFolder, contribFolderName); + + if (status != null) { // when status != null, install is not occurring on startup + + Editor editor = base.getActiveEditor(); + + ArrayList oldContribs = + getType().listContributions(editor); + + // In case an update marker exists, and the user wants to install, delete the update marker + if (contribFolder.exists() && !contribFolder.isDirectory()) { + contribFolder.delete(); + contribFolder = new File(contribTypeFolder, contribFolderName); + } + + for (LocalContribution oldContrib : oldContribs) { + if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(contribFolder)) || + (oldContrib.getId() != null && oldContrib.getId().equals(getId()))) { + + if (oldContrib.getType().requiresRestart()) { + // XXX: We can't replace stuff, soooooo.... do something different + if (!oldContrib.backup(editor, false, status)) { + return null; + } + } else { + int result = 0; + boolean doBackup = Preferences.getBoolean("contribution.backup.on_install"); + if (confirmReplace) { + if (doBackup) { + result = Base.showYesNoQuestion(editor, "Replace", + "Replace pre-existing \"" + oldContrib.getName() + "\" library?", + "A pre-existing copy of the \"" + oldContrib.getName() + "\" library
"+ + "has been found in your sketchbook. Clicking “Yes”
"+ + "will move the existing library to a backup folder
" + + "in libraries/old before replacing it."); + if (result != JOptionPane.YES_OPTION || !oldContrib.backup(editor, true, status)) { + return null; + } + } else { + result = Base.showYesNoQuestion(editor, "Replace", + "Replace pre-existing \"" + oldContrib.getName() + "\" library?", + "A pre-existing copy of the \"" + oldContrib.getName() + "\" library
"+ + "has been found in your sketchbook. Clicking “Yes”
"+ + "will permanently delete this library and all of its contents
"+ + "before replacing it."); + if (result != JOptionPane.YES_OPTION || !oldContrib.getFolder().delete()) { + return null; + } + } + } else { + if ((doBackup && !oldContrib.backup(editor, true, status)) || + (!doBackup && !oldContrib.getFolder().delete())) { + return null; + } + } + } + } + } + + // At this point it should be safe to replace this fella + if (contribFolder.exists()) { + Base.removeDir(contribFolder); + } + + } + else { + // This if should ideally never happen, since this function is to be called only when restarting on update + if (contribFolder.exists() && contribFolder.isDirectory()) { + Base.removeDir(contribFolder); + } + else if (contribFolder.exists()) { + contribFolder.delete(); + contribFolder = new File(contribTypeFolder, contribFolderName); + } + } + + File oldFolder = getFolder(); + + try { + Base.copyDir(oldFolder, contribFolder); + } catch (IOException e) { + status.setErrorMessage("Could not copy " + getTypeName() + + " \"" + getName() + "\" to the sketchbook."); + e.printStackTrace(); + return null; + } + + + /* + if (!getFolder().renameTo(contribFolder)) { + status.setErrorMessage("Could not move " + getTypeName() + + " \"" + getName() + "\" to the sketchbook."); + return null; + } + */ + + return getType().load(base, contribFolder); + } + + + /** + * Moves the given contribution to a backup folder. + * @param deleteOriginal + * true if the file should be moved to the directory, false if it + * should instead be copied, leaving the original in place + */ + boolean backup(Editor editor, boolean deleteOriginal, StatusPanel status) { + File backupFolder = getType().createBackupFolder(status); + + boolean success = false; + if (backupFolder != null) { + String libFolderName = getFolder().getName(); + String prefix = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + final String backupName = prefix + " " + libFolderName; + File backupSubFolder = + ContributionManager.getUniqueName(backupFolder, backupName); + + if (deleteOriginal) { + success = getFolder().renameTo(backupSubFolder); + } else { + try { + Base.copyDir(getFolder(), backupSubFolder); + success = true; + } catch (IOException e) { } + } + if (!success) { + status.setErrorMessage("Could not move contribution to backup folder."); + } + } + return success; + } + + + /** + * Non-blocking call to remove a contribution in a new thread. + */ + void removeContribution(final Editor editor, + final ProgressMonitor pm, + final StatusPanel status) { + new Thread(new Runnable() { + public void run() { + remove(editor, + pm, + status, + ContributionListing.getInstance()); + } + }, "Contribution Uninstaller").start(); + } + + + void remove(final Editor editor, + final ProgressMonitor pm, + final StatusPanel status, + final ContributionListing contribListing) { + pm.startTask("Removing", ProgressMonitor.UNKNOWN); + + boolean doBackup = Preferences.getBoolean("contribution.backup.on_remove"); +// if (getType().requiresRestart()) { +// if (!doBackup || (doBackup && backup(editor, false, status))) { +// if (setDeletionFlag(true)) { +// contribListing.replaceContribution(this, this); +// } +// } +// } else { + boolean success = false; + if (getType() == ContributionType.MODE) { + boolean isModeActive = false; + ModeContribution m = (ModeContribution) this; + Iterator iter = editor.getBase().getEditors().iterator(); + while (iter.hasNext()) { + Editor e = iter.next(); + if (e.getMode().equals(m.getMode())) { + isModeActive = true; + break; + } + } + if (!isModeActive) + m.clearClassLoader(editor.getBase()); + else { + pm.cancel(); + Base.showMessage("Mode Manager", + "Please save your Sketch and change the Mode of all Editor\nwindows that have " + + this.name + " as the active Mode."); + return; + } + } + + if (getType() == ContributionType.TOOL) { + ToolContribution t = (ToolContribution) this; + Iterator iter = editor.getBase().getEditors().iterator(); + while (iter.hasNext()) { + Editor ed = iter.next(); + ed.clearToolMenu(); + } + t.clearClassLoader(editor.getBase()); + } + + if (doBackup) { + success = backup(editor, true, status); + } else { + Base.removeDir(getFolder()); + success = !getFolder().exists(); + } + + if (success) { + if (getType() == ContributionType.TOOL) { + editor.removeTool(); + } + + Contribution advertisedVersion = contribListing + .getAvailableContribution(this); + + if (advertisedVersion == null) { + contribListing.removeContribution(this); + } else { + contribListing.replaceContribution(this, advertisedVersion); + } + } + else { + // There was a failure backing up the folder + if (!doBackup || (doBackup && backup(editor, false, status))) { + if (setDeletionFlag(true)) { + contribListing.replaceContribution(this, this); + } + } + else + status.setErrorMessage("Could not delete the contribution's files"); + } +// } + ContributionManager.refreshInstalled(editor); + if (success) + pm.finished(); + else + pm.cancel(); + } + + + public File getFolder() { + return folder; + } + + + public boolean isInstalled() { + return folder != null; + } + + +// public String getCategory() { +// return category; +// } +// +// +// public String getName() { +// return name; +// } + + + public String getId() { + return id; + } + + +// public String getAuthorList() { +// return authorList; +// } +// +// +// public String getUrl() { +// return url; +// } +// +// +// public String getSentence() { +// return sentence; +// } +// +// +// public String getParagraph() { +// return paragraph; +// } +// +// +// public int getVersion() { +// return version; +// } + + + public int getLatestVersion() { + return latestVersion; + } + + +// public String getPrettyVersion() { +// return prettyVersion; +// } +// +// +// public String getTypeName() { +// return getType().toString(); +// } + + + /* + static protected String findClassInZipFileList(String base, File[] fileList) { + for (File file : fileList) { + String found = findClassInZipFile(base, file); + if (found != null) { + return found; + } + } + return null; + } + */ + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + boolean setDeletionFlag(boolean flag) { + return setFlag(DELETION_FLAG, flag); + } + + + boolean isDeletionFlagged() { + return isDeletionFlagged(getFolder()); + } + + + static boolean isDeletionFlagged(File folder) { + return isFlagged(folder, DELETION_FLAG); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + boolean setUpdateFlag(boolean flag) { + return setFlag(UPDATE_FLAGGED, flag); + } + + + boolean isUpdateFlagged() { + return isUpdateFlagged(getFolder()); + } + + + static boolean isUpdateFlagged(File folder) { + return isFlagged(folder, UPDATE_FLAGGED); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + boolean setRestartFlag() { + //System.out.println("setting restart flag for " + folder); + return setFlag(RESTART_FLAG, true); + } + + + @Override + boolean isRestartFlagged() { + //System.out.println("checking for restart inside LocalContribution for " + getName()); + return isFlagged(getFolder(), RESTART_FLAG); + } + + + static void clearRestartFlags(File folder) { + File restartFlag = new File(folder, RESTART_FLAG); + if (restartFlag.exists()) { + restartFlag.delete(); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + private boolean setFlag(String flagFilename, boolean flag) { + if (flag) { + // Only returns false if the file already exists, so we can + // ignore the return value. + try { + new File(getFolder(), flagFilename).createNewFile(); + return true; + } catch (IOException e) { + return false; + } + } else { + return new File(getFolder(), flagFilename).delete(); + } + } + + + static private boolean isFlagged(File folder, String flagFilename) { + return new File(folder, flagFilename).exists(); + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + /** + * + * @param base name of the class, with or without the package + * @param file + * @return name of class (with full package name) or null if not found + */ + static protected String findClassInZipFile(String base, File file) { + // Class file to search for + String classFileName = "/" + base + ".class"; + + try { + ZipFile zipFile = new ZipFile(file); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + + if (!entry.isDirectory()) { + String name = entry.getName(); +// System.out.println("entry: " + name); + + if (name.endsWith(classFileName)) { + //int slash = name.lastIndexOf('/'); + //String packageName = (slash == -1) ? "" : name.substring(0, slash); + // Remove .class and convert slashes to periods. + zipFile.close(); + return name.substring(0, name.length() - 6).replace('/', '.'); + } + } + } + zipFile.close(); + } catch (IOException e) { + //System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")"); + e.printStackTrace(); + } + return null; + } + + + static protected class IgnorableException extends Exception { + public IgnorableException(String msg) { + super(msg); + } + } +} diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java index e37c28464..2598ffaee 100644 --- a/app/src/processing/app/contrib/ModeContribution.java +++ b/app/src/processing/app/contrib/ModeContribution.java @@ -1,176 +1,176 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas - - 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.contrib; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.net.URLClassLoader; -import java.util.*; - -import processing.app.Base; -import processing.app.Mode; - - -public class ModeContribution extends LocalContribution { - private Mode mode; - - - static public ModeContribution load(Base base, File folder) { - return load(base, folder, null); - } - - - static public ModeContribution load(Base base, File folder, - String searchName) { - try { - return new ModeContribution(base, folder, searchName); - - } catch (IgnorableException ig) { - Base.log(ig.getMessage()); - - } catch (Throwable err) { - // Throwable to catch Exceptions or UnsupportedClassVersionError et al - if (searchName == null) { - err.printStackTrace(); - } else { - // For the built-in modes, don't print the exception, just log it - // for debugging. This should be impossible for most users to reach, - // but it helps us load experimental mode when it's available. - Base.log("ModeContribution.load() failed for " + searchName, err); - } - } - return null; - } - - - /** - * - * @param base the base object that this will be tied to - * @param folder location inside the sketchbook modes folder or contrib - * @param className name of class and full package, or null to use default - * @throws Exception - */ - private ModeContribution(Base base, File folder, - String className) throws Exception { - super(folder); - - className = initLoader(className); - if (className != null) { - Class modeClass = loader.loadClass(className); - Constructor con = modeClass.getConstructor(Base.class, File.class); - mode = (Mode) con.newInstance(base, folder); - mode.setClassLoader(loader); - if (base != null) { - mode.setupGUI(); - } - } - } - - /** - * Method to close the ClassLoader so that the archives are no longer "locked" - * and a mode can be removed without restart. - */ - public void clearClassLoader(Base base) { - - ArrayList contribModes = base.getModeContribs(); - int botherToRemove = contribModes.indexOf(this); - if (botherToRemove != -1) { // The poor thing isn't even loaded, and we're trying to remove it... - contribModes.remove(botherToRemove); - - try { - ((URLClassLoader) loader).close(); - // The typecast should be safe, since the only case when loader is not of - // type URLClassLoader is when no archives were found in the first - // place... - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - static public void loadMissing(Base base) { - File modesFolder = Base.getSketchbookModesFolder(); - ArrayList contribModes = base.getModeContribs(); - - HashMap existing = new HashMap(); - for (ModeContribution contrib : contribModes) { - existing.put(contrib.getFolder(), contrib); - } - File[] potential = ContributionType.MODE.listCandidates(modesFolder); - // If modesFolder does not exist or is inaccessible (folks might like to - // mess with folders then report it as a bug) 'potential' will be null. - if (potential != null) { - for (File folder : potential) { - if (!existing.containsKey(folder)) { - try { - contribModes.add(new ModeContribution(base, folder, null)); - } catch (IgnorableException ig) { - Base.log(ig.getMessage()); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - } - - // This allows you to build and test your Mode code from Eclipse. - // -Dusemode=com.foo.FrobMode:/path/to/FrobMode - final String useMode = System.getProperty("usemode"); - if (useMode != null) { - final String[] modeInfo = useMode.split(":", 2); - final String modeClass = modeInfo[0]; - final String modeResourcePath = modeInfo[1]; - System.out.println("Attempting to load " + modeClass + " with resources at " + modeResourcePath); - contribModes.add(ModeContribution.load(base, new File(modeResourcePath), modeClass)); - } - } - - - public Mode getMode() { - return mode; - } - - - public ContributionType getType() { - return ContributionType.MODE; - } - - - public boolean equals(Object o) { - if (o == null || !(o instanceof ModeContribution)) { - return false; - } - ModeContribution other = (ModeContribution) o; - return loader.equals(other.loader) && mode.equals(other.getMode()); - } - - -// static protected List discover(File folder) { -// File[] folders = listCandidates(folder, "mode"); -// if (folders == null) { -// return new ArrayList(); -// } else { -// return Arrays.asList(folders); -// } -// } -} +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2011-12 Ben Fry and Casey Reas + + 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.contrib; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.URLClassLoader; +import java.util.*; + +import processing.app.Base; +import processing.app.Mode; + + +public class ModeContribution extends LocalContribution { + private Mode mode; + + + static public ModeContribution load(Base base, File folder) { + return load(base, folder, null); + } + + + static public ModeContribution load(Base base, File folder, + String searchName) { + try { + return new ModeContribution(base, folder, searchName); + + } catch (IgnorableException ig) { + Base.log(ig.getMessage()); + + } catch (Throwable err) { + // Throwable to catch Exceptions or UnsupportedClassVersionError et al + if (searchName == null) { + err.printStackTrace(); + } else { + // For the built-in modes, don't print the exception, just log it + // for debugging. This should be impossible for most users to reach, + // but it helps us load experimental mode when it's available. + Base.log("ModeContribution.load() failed for " + searchName, err); + } + } + return null; + } + + + /** + * + * @param base the base object that this will be tied to + * @param folder location inside the sketchbook modes folder or contrib + * @param className name of class and full package, or null to use default + * @throws Exception + */ + private ModeContribution(Base base, File folder, + String className) throws Exception { + super(folder); + + className = initLoader(className); + if (className != null) { + Class modeClass = loader.loadClass(className); + Constructor con = modeClass.getConstructor(Base.class, File.class); + mode = (Mode) con.newInstance(base, folder); + mode.setClassLoader(loader); + if (base != null) { + mode.setupGUI(); + } + } + } + + /** + * Method to close the ClassLoader so that the archives are no longer "locked" + * and a mode can be removed without restart. + */ + public void clearClassLoader(Base base) { + + ArrayList contribModes = base.getModeContribs(); + int botherToRemove = contribModes.indexOf(this); + if (botherToRemove != -1) { // The poor thing isn't even loaded, and we're trying to remove it... + contribModes.remove(botherToRemove); + + try { + ((URLClassLoader) loader).close(); + // The typecast should be safe, since the only case when loader is not of + // type URLClassLoader is when no archives were found in the first + // place... + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + static public void loadMissing(Base base) { + File modesFolder = Base.getSketchbookModesFolder(); + ArrayList contribModes = base.getModeContribs(); + + HashMap existing = new HashMap(); + for (ModeContribution contrib : contribModes) { + existing.put(contrib.getFolder(), contrib); + } + File[] potential = ContributionType.MODE.listCandidates(modesFolder); + // If modesFolder does not exist or is inaccessible (folks might like to + // mess with folders then report it as a bug) 'potential' will be null. + if (potential != null) { + for (File folder : potential) { + if (!existing.containsKey(folder)) { + try { + contribModes.add(new ModeContribution(base, folder, null)); + } catch (IgnorableException ig) { + Base.log(ig.getMessage()); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + } + + // This allows you to build and test your Mode code from Eclipse. + // -Dusemode=com.foo.FrobMode:/path/to/FrobMode + final String useMode = System.getProperty("usemode"); + if (useMode != null) { + final String[] modeInfo = useMode.split(":", 2); + final String modeClass = modeInfo[0]; + final String modeResourcePath = modeInfo[1]; + System.out.println("Attempting to load " + modeClass + " with resources at " + modeResourcePath); + contribModes.add(ModeContribution.load(base, new File(modeResourcePath), modeClass)); + } + } + + + public Mode getMode() { + return mode; + } + + + public ContributionType getType() { + return ContributionType.MODE; + } + + + public boolean equals(Object o) { + if (o == null || !(o instanceof ModeContribution)) { + return false; + } + ModeContribution other = (ModeContribution) o; + return loader.equals(other.loader) && mode.equals(other.getMode()); + } + + +// static protected List discover(File folder) { +// File[] folders = listCandidates(folder, "mode"); +// if (folders == null) { +// return new ArrayList(); +// } else { +// return Arrays.asList(folders); +// } +// } +} diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java index 978f12447..bb8ca790c 100644 --- a/app/src/processing/app/contrib/ToolContribution.java +++ b/app/src/processing/app/contrib/ToolContribution.java @@ -1,182 +1,182 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas - - 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.contrib; - -import java.io.*; -import java.net.URLClassLoader; -//import java.net.*; -import java.util.*; - -import processing.app.Base; -//import processing.app.Base; -import processing.app.Editor; -import processing.app.tools.Tool; - - -public class ToolContribution extends LocalContribution implements Tool { - private Tool tool; - - private File referenceFile; // shortname/reference/index.html - - static public ToolContribution load(File folder) { - try { - return new ToolContribution(folder); - } catch (IgnorableException ig) { - Base.log(ig.getMessage()); +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2013 The Processing Foundation + Copyright (c) 2011-12 Ben Fry and Casey Reas + + 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.contrib; + +import java.io.*; +import java.net.URLClassLoader; +//import java.net.*; +import java.util.*; + +import processing.app.Base; +//import processing.app.Base; +import processing.app.Editor; +import processing.app.tools.Tool; + + +public class ToolContribution extends LocalContribution implements Tool { + private Tool tool; + + private File referenceFile; // shortname/reference/index.html + + static public ToolContribution load(File folder) { + try { + return new ToolContribution(folder); + } catch (IgnorableException ig) { + Base.log(ig.getMessage()); } catch (VerifyError ve) { // incompatible // avoid the excessive error spew that happens here } catch (Throwable e) { // unknown error e.printStackTrace(); - } - return null; - } - - + } + return null; + } + + private ToolContribution(File folder) throws Throwable { - super(folder); - - String className = initLoader(null); - if (className != null) { - Class toolClass = loader.loadClass(className); - tool = (Tool) toolClass.newInstance(); - } - - referenceFile = new File(folder, "reference/index.html"); - } - - - /** - * Method to close the ClassLoader so that the archives are no longer "locked" and - * a tool can be removed without restart. - */ - public void clearClassLoader(Base base) { - try { - ((URLClassLoader) this.loader).close(); - } catch (IOException e1) { - e1.printStackTrace(); - } - Iterator editorIter = base.getEditors().iterator(); - while (editorIter.hasNext()) { - Editor editor = editorIter.next(); - ArrayList contribTools = editor.contribTools; - for (ToolContribution toolContrib : contribTools) - if (toolContrib.getName().equals(this.name)) { - try { - ((URLClassLoader) toolContrib.loader).close(); - editor.contribTools.remove(toolContrib); - break; - } catch (IOException e) { - e.printStackTrace(); - } -// base.getActiveEditor().rebuildToolMenu(); - } - } - } - - -// static protected List discover(File folder) { -// File[] folders = listCandidates(folder, "tool"); -// if (folders == null) { -// return new ArrayList(); -// } else { -// return Arrays.asList(folders); -// } -// } - - - static public ArrayList loadAll(File toolsFolder) { - File[] list = ContributionType.TOOL.listCandidates(toolsFolder); - ArrayList outgoing = new ArrayList(); - // If toolsFolder does not exist or is inaccessible (stranger things have - // happened, and are reported as bugs) list will come back null. - if (list != null) { - for (File folder : list) { - try { - ToolContribution tc = load(folder); - if (tc != null) { - outgoing.add(tc); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - return outgoing; - } - - -// Editor editor; // used to send error messages - - public void init(Editor editor) { -// try { -// this.editor = editor; - tool.init(editor); -// } catch (NoSuchMethodError nsme) { -// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); -// nsme.printStackTrace(); -// } - } - - - public void run() { -// try { - tool.run(); -// } catch (NoSuchMethodError nsme) { -// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); -// nsme.printStackTrace(); -// } - } - - - public String getMenuTitle() { - return tool.getMenuTitle(); - } - - - public ContributionType getType() { - return ContributionType.TOOL; - } - - - /** - * Returns the object stored in the referenceFile field, which contains an - * instance of the file object representing the index file of the reference - * - * @return referenceFile - */ - public File getReferenceIndexFile() { - return referenceFile; - } - - - /** - * Tests whether the reference's index file indicated by referenceFile exists. - * - * @return true if and only if the file denoted by referenceFile exists; false - * otherwise. - */ - public boolean hasReference() { - return referenceFile.exists(); - } + super(folder); + + String className = initLoader(null); + if (className != null) { + Class toolClass = loader.loadClass(className); + tool = (Tool) toolClass.newInstance(); + } + + referenceFile = new File(folder, "reference/index.html"); + } + + + /** + * Method to close the ClassLoader so that the archives are no longer "locked" and + * a tool can be removed without restart. + */ + public void clearClassLoader(Base base) { + try { + ((URLClassLoader) this.loader).close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + Iterator editorIter = base.getEditors().iterator(); + while (editorIter.hasNext()) { + Editor editor = editorIter.next(); + ArrayList contribTools = editor.contribTools; + for (ToolContribution toolContrib : contribTools) + if (toolContrib.getName().equals(this.name)) { + try { + ((URLClassLoader) toolContrib.loader).close(); + editor.contribTools.remove(toolContrib); + break; + } catch (IOException e) { + e.printStackTrace(); + } +// base.getActiveEditor().rebuildToolMenu(); + } + } + } + + +// static protected List discover(File folder) { +// File[] folders = listCandidates(folder, "tool"); +// if (folders == null) { +// return new ArrayList(); +// } else { +// return Arrays.asList(folders); +// } +// } + + + static public ArrayList loadAll(File toolsFolder) { + File[] list = ContributionType.TOOL.listCandidates(toolsFolder); + ArrayList outgoing = new ArrayList(); + // If toolsFolder does not exist or is inaccessible (stranger things have + // happened, and are reported as bugs) list will come back null. + if (list != null) { + for (File folder : list) { + try { + ToolContribution tc = load(folder); + if (tc != null) { + outgoing.add(tc); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return outgoing; + } + + +// Editor editor; // used to send error messages + + public void init(Editor editor) { +// try { +// this.editor = editor; + tool.init(editor); +// } catch (NoSuchMethodError nsme) { +// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); +// nsme.printStackTrace(); +// } + } + + + public void run() { +// try { + tool.run(); +// } catch (NoSuchMethodError nsme) { +// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); +// nsme.printStackTrace(); +// } + } + + + public String getMenuTitle() { + return tool.getMenuTitle(); + } + + + public ContributionType getType() { + return ContributionType.TOOL; + } + + + /** + * Returns the object stored in the referenceFile field, which contains an + * instance of the file object representing the index file of the reference + * + * @return referenceFile + */ + public File getReferenceIndexFile() { + return referenceFile; + } + + + /** + * Tests whether the reference's index file indicated by referenceFile exists. + * + * @return true if and only if the file denoted by referenceFile exists; false + * otherwise. + */ + public boolean hasReference() { + return referenceFile.exists(); + } } diff --git a/app/src/processing/mode/java/preproc/pde.g b/app/src/processing/mode/java/preproc/pde.g index 4355c2b79..6b2b58fd5 100644 --- a/app/src/processing/mode/java/preproc/pde.g +++ b/app/src/processing/mode/java/preproc/pde.g @@ -1,394 +1,394 @@ -/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -header { -package processing.mode.java.preproc; -} - -class PdeRecognizer extends JavaRecognizer; - -options { - importVocab = Java; - exportVocab = PdePartial; - - //codeGenMakeSwitchThreshold=10; // this is set high for debugging - //codeGenBitsetTestThreshold=10; // this is set high for debugging - - // developers may to want to set this to true for better - // debugging messages, however, doing so disables highlighting errors - // in the editor. - defaultErrorHandler = false; //true; -} - -tokens { - CONSTRUCTOR_CAST; EMPTY_FIELD; -} - -{ - // this clause copied from java15.g! ANTLR does not copy this - // section from the super grammar. - /** - * Counts the number of LT seen in the typeArguments production. - * It is used in semantic predicates to ensure we have seen - * enough closing '>' characters; which actually may have been - * either GT, SR or BSR tokens. - */ - private int ltCounter = 0; - - private PdePreprocessor pp; - public PdeRecognizer(final PdePreprocessor pp, final TokenStream ts) { - this(ts); - this.pp = pp; - } - - private void mixed() throws RecognitionException, TokenStreamException { - throw new RecognitionException("It looks like you're mixing \"active\" and \"static\" modes.", - getFilename(), LT(1).getLine(), LT(1).getColumn()); - } -} - -pdeProgram - : - // Some programs can be equally well interpreted as STATIC or ACTIVE; - // this forces the parser to prefer the STATIC interpretation. - (staticProgram) => staticProgram - { pp.setMode(PdePreprocessor.Mode.STATIC); } - - | (activeProgram) => activeProgram - { pp.setMode(PdePreprocessor.Mode.ACTIVE); } - - | staticProgram - { pp.setMode(PdePreprocessor.Mode.STATIC); } - ; - -// advanced mode is really just a normal java file -javaProgram - : compilationUnit - ; - -activeProgram - : ( - (IDENT LPAREN) => IDENT LPAREN { mixed(); } - | possiblyEmptyField - )+ EOF! - ; - -staticProgram - : ( - statement - )* EOF! - ; - -// copy of the java.g rule with WEBCOLOR_LITERAL added -constant - : NUM_INT - | CHAR_LITERAL - | STRING_LITERAL - | NUM_FLOAT - | NUM_LONG - | NUM_DOUBLE - | webcolor_literal - ; - -// fix bug http://dev.processing.org/bugs/show_bug.cgi?id=1519 -// by altering a syntactic predicate whose sole purpose is to -// emit a useless error with no line numbers. -// These are from Java15.g, with a few lines edited to make nice errors. - -// Type arguments to a class or interface type -typeArguments -{int currentLtLevel = 0;} - : - {currentLtLevel = ltCounter;} - LT! {ltCounter++;} - typeArgument - (options{greedy=true;}: // match as many as possible - {if (! (inputState.guessing !=0 || ltCounter == currentLtLevel + 1)) { - throw new RecognitionException("Maybe too many > characters?", - getFilename(), LT(1).getLine(), LT(1).getColumn()); - }} - COMMA! typeArgument - )* - - ( // turn warning off since Antlr generates the right code, - // plus we have our semantic predicate below - options{generateAmbigWarnings=false;}: - typeArgumentsOrParametersEnd - )? - - // make sure we have gobbled up enough '>' characters - // if we are at the "top level" of nested typeArgument productions - {if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) { - throw new RecognitionException("Maybe too many > characters?", - getFilename(), LT(1).getLine(), LT(1).getColumn()); - }} - - {#typeArguments = #(#[TYPE_ARGUMENTS, "TYPE_ARGUMENTS"], #typeArguments);} - ; - -typeParameters -{int currentLtLevel = 0;} - : - {currentLtLevel = ltCounter;} - LT! {ltCounter++;} - typeParameter (COMMA! typeParameter)* - (typeArgumentsOrParametersEnd)? - - // make sure we have gobbled up enough '>' characters - // if we are at the "top level" of nested typeArgument productions - {if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) { - throw new RecognitionException("Maybe too many > characters?", - getFilename(), LT(1).getLine(), LT(1).getColumn()); - }} - - {#typeParameters = #(#[TYPE_PARAMETERS, "TYPE_PARAMETERS"], #typeParameters);} - ; - - -// this gobbles up *some* amount of '>' characters, and counts how many -// it gobbled. -protected typeArgumentsOrParametersEnd - : GT! {ltCounter-=1;} - | SR! {ltCounter-=2;} - | BSR! {ltCounter-=3;} - ; - -// of the form #cc008f in PDE -webcolor_literal - : w:WEBCOLOR_LITERAL - { if (! (processing.app.Preferences.getBoolean("preproc.web_colors") - && - w.getText().length() == 6)) { - throw new RecognitionException("Web colors must be exactly 6 hex digits. This looks like " + w.getText().length() + ".", - getFilename(), LT(1).getLine(), LT(1).getColumn()); - }} // must be exactly 6 hex digits - ; - -// copy of the java.g builtInType rule -builtInConsCastType - : "void" - | "boolean" - | "byte" - | "char" - | "short" - | "int" - | "float" - | "long" - | "double" - ; - -// our types include the java types and "color". this is separated into two -// rules so that constructor casts can just use the original typelist, since -// we don't want to support the color type as a constructor cast. -// -builtInType - : builtInConsCastType - | "color" // aliased to an int in PDE - { processing.app.Preferences.getBoolean("preproc.color_datatype") }? - ; - -// constructor style casts. -constructorCast! - : t:consCastTypeSpec[true] - LPAREN! - e:expression - RPAREN! - // if this is a string literal, make sure the type we're trying to cast - // to is one of the supported ones - // - { (#e == null) || - ( (#e.getType() != STRING_LITERAL) || - ( #t.getType() == LITERAL_boolean || - #t.getType() == LITERAL_double || - #t.getType() == LITERAL_float || - #t.getType() == LITERAL_int || - #t.getType() == LITERAL_long || - #t.getType() == LITERAL_short )) }? - // create the node - // - {#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);} - ; - -// A list of types that be used as the destination type in a constructor-style -// cast. Ideally, this would include all class types, not just "String". -// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be -// a method call or a constructor cast without have a table of all valid -// types or methods, which requires semantic analysis (eg processing of import -// statements). So we accept the set of built-in types plus "String". -// -consCastTypeSpec[boolean addImagNode] -// : stringTypeSpec[addImagNode] -// | builtInConsCastTypeSpec[addImagNode] - : builtInConsCastTypeSpec[addImagNode] -// trying to remove String() cast [fry] - ; - -//stringTypeSpec[boolean addImagNode] -// : id:IDENT { #id.getText().equals("String") }? -// { -// if ( addImagNode ) { -// #stringTypeSpec = #(#[TYPE,"TYPE"], -// #stringTypeSpec); -// } -// } -// ; - -builtInConsCastTypeSpec[boolean addImagNode] - : builtInConsCastType - { - if ( addImagNode ) { - #builtInConsCastTypeSpec = #(#[TYPE,"TYPE"], - #builtInConsCastTypeSpec); - } - } - ; - -// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule -// that can generate a method call from an expression that starts with this -// token -// -colorMethodCall - : c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color - lp:LPAREN^ {#lp.setType(METHOD_CALL);} - argList - RPAREN! - ; - -// copy of the java.g rule with added constructorCast and colorMethodCall -// alternatives -primaryExpression - : (consCastTypeSpec[false] LPAREN) => constructorCast - { processing.app.Preferences.getBoolean("preproc.enhanced_casting") }? - | identPrimary ( options {greedy=true;} : DOT^ "class" )? - | constant - | "true" - | "false" - | "null" - | newExpression - | "this" - | "super" - | LPAREN! assignmentExpression RPAREN! - | colorMethodCall - // look for int.class and int[].class - | builtInType - ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )* - DOT^ "class" - ; - -// the below variable rule hacks are needed so that it's possible for the -// emitter to correctly output variable declarations of the form "float a, b" -// from the AST. This means that our AST has a somewhat different form in -// these rules than the java one does, and this new form may have its own -// semantic issues. But it seems to fix the comma declaration issues. -// -variableDefinitions![AST mods, AST t] - : vd:variableDeclarator[getASTFactory().dupTree(mods), - getASTFactory().dupTree(t)] - {#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, - t, vd);} - ; -variableDeclarator[AST mods, AST t] - : ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* - v:varInitializer (COMMA!)? )+ - ; - -// java.g builds syntax trees with an inconsistent structure. override one of -// the rules there to fix this. -// -explicitConstructorInvocation! - : (typeArguments)? - t:"this" LPAREN a1:argList RPAREN SEMI - {#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"], - #t, #a1);} - | s:"super" LPAREN a2:argList RPAREN SEMI - {#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL, - "SUPER_CTOR_CALL"], - #s, #a2);} - ; - -// quick-n-dirty hack to the get the advanced class name. we should -// really be getting it from the AST and not forking this rule from -// the java.g copy at all. Since this is a recursive descent parser, we get -// the last class name in the file so that we don't end up with the classname -// of an inner class. If there is more than one "outer" class in a file, -// this heuristic will fail. -// -classDefinition![AST modifiers] - : "class" i:IDENT - // it _might_ have type paramaters - (tp:typeParameters)? - // it _might_ have a superclass... - sc:superClassClause - // it might implement some interfaces... - ic:implementsClause - // now parse the body of the class - cb:classBlock - {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"], - modifiers,i,tp,sc,ic,cb); - pp.setAdvClassName(i.getText());} - ; - -possiblyEmptyField - : classField - | s:SEMI {#s.setType(EMPTY_FIELD);} - ; - -class PdeLexer extends JavaLexer; - -options { - importVocab=PdePartial; - exportVocab=Pde; -} - -// We need to preserve whitespace and commentary instead of ignoring -// like the supergrammar does. Otherwise Jikes won't be able to give -// us error messages that point to the equivalent PDE code. - -// WS, SL_COMMENT, ML_COMMENT are copies of the original productions, -// but with the SKIP assigment removed. - -WS : ( ' ' - | '\t' - | '\f' - // handle newlines - | ( options {generateAmbigWarnings=false;} - : "\r\n" // Evil DOS - | '\r' // Macintosh - | '\n' // Unix (the right way) - ) - { newline(); } - )+ - ; - -// Single-line comments -SL_COMMENT - : "//" - (~('\n'|'\r'))* ('\n'|'\r'('\n')?) - {newline();} - ; - -// multiple-line comments -ML_COMMENT - : "/*" - ( /* '\r' '\n' can be matched in one alternative or by matching - '\r' in one iteration and '\n' in another. I am trying to - handle any flavor of newline that comes in, but the language - that allows both "\r\n" and "\r" and "\n" to all be valid - newline is ambiguous. Consequently, the resulting grammar - must be ambiguous. I'm shutting this warning off. - */ - options { - generateAmbigWarnings=false; - } - : - { LA(2)!='/' }? '*' - | '\r' '\n' {newline();} - | '\r' {newline();} - | '\n' {newline();} - | ~('*'|'\n'|'\r') - )* - "*/" - ; - -WEBCOLOR_LITERAL - : '#'! (HEX_DIGIT)+ - ; - +/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +header { +package processing.mode.java.preproc; +} + +class PdeRecognizer extends JavaRecognizer; + +options { + importVocab = Java; + exportVocab = PdePartial; + + //codeGenMakeSwitchThreshold=10; // this is set high for debugging + //codeGenBitsetTestThreshold=10; // this is set high for debugging + + // developers may to want to set this to true for better + // debugging messages, however, doing so disables highlighting errors + // in the editor. + defaultErrorHandler = false; //true; +} + +tokens { + CONSTRUCTOR_CAST; EMPTY_FIELD; +} + +{ + // this clause copied from java15.g! ANTLR does not copy this + // section from the super grammar. + /** + * Counts the number of LT seen in the typeArguments production. + * It is used in semantic predicates to ensure we have seen + * enough closing '>' characters; which actually may have been + * either GT, SR or BSR tokens. + */ + private int ltCounter = 0; + + private PdePreprocessor pp; + public PdeRecognizer(final PdePreprocessor pp, final TokenStream ts) { + this(ts); + this.pp = pp; + } + + private void mixed() throws RecognitionException, TokenStreamException { + throw new RecognitionException("It looks like you're mixing \"active\" and \"static\" modes.", + getFilename(), LT(1).getLine(), LT(1).getColumn()); + } +} + +pdeProgram + : + // Some programs can be equally well interpreted as STATIC or ACTIVE; + // this forces the parser to prefer the STATIC interpretation. + (staticProgram) => staticProgram + { pp.setMode(PdePreprocessor.Mode.STATIC); } + + | (activeProgram) => activeProgram + { pp.setMode(PdePreprocessor.Mode.ACTIVE); } + + | staticProgram + { pp.setMode(PdePreprocessor.Mode.STATIC); } + ; + +// advanced mode is really just a normal java file +javaProgram + : compilationUnit + ; + +activeProgram + : ( + (IDENT LPAREN) => IDENT LPAREN { mixed(); } + | possiblyEmptyField + )+ EOF! + ; + +staticProgram + : ( + statement + )* EOF! + ; + +// copy of the java.g rule with WEBCOLOR_LITERAL added +constant + : NUM_INT + | CHAR_LITERAL + | STRING_LITERAL + | NUM_FLOAT + | NUM_LONG + | NUM_DOUBLE + | webcolor_literal + ; + +// fix bug http://dev.processing.org/bugs/show_bug.cgi?id=1519 +// by altering a syntactic predicate whose sole purpose is to +// emit a useless error with no line numbers. +// These are from Java15.g, with a few lines edited to make nice errors. + +// Type arguments to a class or interface type +typeArguments +{int currentLtLevel = 0;} + : + {currentLtLevel = ltCounter;} + LT! {ltCounter++;} + typeArgument + (options{greedy=true;}: // match as many as possible + {if (! (inputState.guessing !=0 || ltCounter == currentLtLevel + 1)) { + throw new RecognitionException("Maybe too many > characters?", + getFilename(), LT(1).getLine(), LT(1).getColumn()); + }} + COMMA! typeArgument + )* + + ( // turn warning off since Antlr generates the right code, + // plus we have our semantic predicate below + options{generateAmbigWarnings=false;}: + typeArgumentsOrParametersEnd + )? + + // make sure we have gobbled up enough '>' characters + // if we are at the "top level" of nested typeArgument productions + {if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) { + throw new RecognitionException("Maybe too many > characters?", + getFilename(), LT(1).getLine(), LT(1).getColumn()); + }} + + {#typeArguments = #(#[TYPE_ARGUMENTS, "TYPE_ARGUMENTS"], #typeArguments);} + ; + +typeParameters +{int currentLtLevel = 0;} + : + {currentLtLevel = ltCounter;} + LT! {ltCounter++;} + typeParameter (COMMA! typeParameter)* + (typeArgumentsOrParametersEnd)? + + // make sure we have gobbled up enough '>' characters + // if we are at the "top level" of nested typeArgument productions + {if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) { + throw new RecognitionException("Maybe too many > characters?", + getFilename(), LT(1).getLine(), LT(1).getColumn()); + }} + + {#typeParameters = #(#[TYPE_PARAMETERS, "TYPE_PARAMETERS"], #typeParameters);} + ; + + +// this gobbles up *some* amount of '>' characters, and counts how many +// it gobbled. +protected typeArgumentsOrParametersEnd + : GT! {ltCounter-=1;} + | SR! {ltCounter-=2;} + | BSR! {ltCounter-=3;} + ; + +// of the form #cc008f in PDE +webcolor_literal + : w:WEBCOLOR_LITERAL + { if (! (processing.app.Preferences.getBoolean("preproc.web_colors") + && + w.getText().length() == 6)) { + throw new RecognitionException("Web colors must be exactly 6 hex digits. This looks like " + w.getText().length() + ".", + getFilename(), LT(1).getLine(), LT(1).getColumn()); + }} // must be exactly 6 hex digits + ; + +// copy of the java.g builtInType rule +builtInConsCastType + : "void" + | "boolean" + | "byte" + | "char" + | "short" + | "int" + | "float" + | "long" + | "double" + ; + +// our types include the java types and "color". this is separated into two +// rules so that constructor casts can just use the original typelist, since +// we don't want to support the color type as a constructor cast. +// +builtInType + : builtInConsCastType + | "color" // aliased to an int in PDE + { processing.app.Preferences.getBoolean("preproc.color_datatype") }? + ; + +// constructor style casts. +constructorCast! + : t:consCastTypeSpec[true] + LPAREN! + e:expression + RPAREN! + // if this is a string literal, make sure the type we're trying to cast + // to is one of the supported ones + // + { (#e == null) || + ( (#e.getType() != STRING_LITERAL) || + ( #t.getType() == LITERAL_boolean || + #t.getType() == LITERAL_double || + #t.getType() == LITERAL_float || + #t.getType() == LITERAL_int || + #t.getType() == LITERAL_long || + #t.getType() == LITERAL_short )) }? + // create the node + // + {#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);} + ; + +// A list of types that be used as the destination type in a constructor-style +// cast. Ideally, this would include all class types, not just "String". +// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be +// a method call or a constructor cast without have a table of all valid +// types or methods, which requires semantic analysis (eg processing of import +// statements). So we accept the set of built-in types plus "String". +// +consCastTypeSpec[boolean addImagNode] +// : stringTypeSpec[addImagNode] +// | builtInConsCastTypeSpec[addImagNode] + : builtInConsCastTypeSpec[addImagNode] +// trying to remove String() cast [fry] + ; + +//stringTypeSpec[boolean addImagNode] +// : id:IDENT { #id.getText().equals("String") }? +// { +// if ( addImagNode ) { +// #stringTypeSpec = #(#[TYPE,"TYPE"], +// #stringTypeSpec); +// } +// } +// ; + +builtInConsCastTypeSpec[boolean addImagNode] + : builtInConsCastType + { + if ( addImagNode ) { + #builtInConsCastTypeSpec = #(#[TYPE,"TYPE"], + #builtInConsCastTypeSpec); + } + } + ; + +// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule +// that can generate a method call from an expression that starts with this +// token +// +colorMethodCall + : c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color + lp:LPAREN^ {#lp.setType(METHOD_CALL);} + argList + RPAREN! + ; + +// copy of the java.g rule with added constructorCast and colorMethodCall +// alternatives +primaryExpression + : (consCastTypeSpec[false] LPAREN) => constructorCast + { processing.app.Preferences.getBoolean("preproc.enhanced_casting") }? + | identPrimary ( options {greedy=true;} : DOT^ "class" )? + | constant + | "true" + | "false" + | "null" + | newExpression + | "this" + | "super" + | LPAREN! assignmentExpression RPAREN! + | colorMethodCall + // look for int.class and int[].class + | builtInType + ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )* + DOT^ "class" + ; + +// the below variable rule hacks are needed so that it's possible for the +// emitter to correctly output variable declarations of the form "float a, b" +// from the AST. This means that our AST has a somewhat different form in +// these rules than the java one does, and this new form may have its own +// semantic issues. But it seems to fix the comma declaration issues. +// +variableDefinitions![AST mods, AST t] + : vd:variableDeclarator[getASTFactory().dupTree(mods), + getASTFactory().dupTree(t)] + {#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, + t, vd);} + ; +variableDeclarator[AST mods, AST t] + : ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)* + v:varInitializer (COMMA!)? )+ + ; + +// java.g builds syntax trees with an inconsistent structure. override one of +// the rules there to fix this. +// +explicitConstructorInvocation! + : (typeArguments)? + t:"this" LPAREN a1:argList RPAREN SEMI + {#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"], + #t, #a1);} + | s:"super" LPAREN a2:argList RPAREN SEMI + {#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL, + "SUPER_CTOR_CALL"], + #s, #a2);} + ; + +// quick-n-dirty hack to the get the advanced class name. we should +// really be getting it from the AST and not forking this rule from +// the java.g copy at all. Since this is a recursive descent parser, we get +// the last class name in the file so that we don't end up with the classname +// of an inner class. If there is more than one "outer" class in a file, +// this heuristic will fail. +// +classDefinition![AST modifiers] + : "class" i:IDENT + // it _might_ have type paramaters + (tp:typeParameters)? + // it _might_ have a superclass... + sc:superClassClause + // it might implement some interfaces... + ic:implementsClause + // now parse the body of the class + cb:classBlock + {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"], + modifiers,i,tp,sc,ic,cb); + pp.setAdvClassName(i.getText());} + ; + +possiblyEmptyField + : classField + | s:SEMI {#s.setType(EMPTY_FIELD);} + ; + +class PdeLexer extends JavaLexer; + +options { + importVocab=PdePartial; + exportVocab=Pde; +} + +// We need to preserve whitespace and commentary instead of ignoring +// like the supergrammar does. Otherwise Jikes won't be able to give +// us error messages that point to the equivalent PDE code. + +// WS, SL_COMMENT, ML_COMMENT are copies of the original productions, +// but with the SKIP assigment removed. + +WS : ( ' ' + | '\t' + | '\f' + // handle newlines + | ( options {generateAmbigWarnings=false;} + : "\r\n" // Evil DOS + | '\r' // Macintosh + | '\n' // Unix (the right way) + ) + { newline(); } + )+ + ; + +// Single-line comments +SL_COMMENT + : "//" + (~('\n'|'\r'))* ('\n'|'\r'('\n')?) + {newline();} + ; + +// multiple-line comments +ML_COMMENT + : "/*" + ( /* '\r' '\n' can be matched in one alternative or by matching + '\r' in one iteration and '\n' in another. I am trying to + handle any flavor of newline that comes in, but the language + that allows both "\r\n" and "\r" and "\n" to all be valid + newline is ambiguous. Consequently, the resulting grammar + must be ambiguous. I'm shutting this warning off. + */ + options { + generateAmbigWarnings=false; + } + : + { LA(2)!='/' }? '*' + | '\r' '\n' {newline();} + | '\r' {newline();} + | '\n' {newline();} + | ~('*'|'\n'|'\r') + )* + "*/" + ; + +WEBCOLOR_LITERAL + : '#'! (HEX_DIGIT)+ + ; + diff --git a/app/test/resources/bug1064.expected b/app/test/resources/bug1064.expected index 2fd1f3ef0..d77173b44 100644 --- a/app/test/resources/bug1064.expected +++ b/app/test/resources/bug1064.expected @@ -1,29 +1,29 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1064 extends PApplet { - public void setup() { -// import "; - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1064" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1064 extends PApplet { + public void setup() { +// import "; + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1064" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug136.expected b/app/test/resources/bug136.expected index 3ed7a5fc5..9909098a3 100644 --- a/app/test/resources/bug136.expected +++ b/app/test/resources/bug136.expected @@ -1,41 +1,41 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.Collections; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug136 extends PApplet { - - -java.util.List alist = Collections.synchronizedList(new ArrayList()); - -public void setup() { -size(400, 200); -alist.add("hello"); -} - -public void draw() { -rect(width/4, height/4, width/2, height/2); -synchronized(alist) { -alist.get(0); -} -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug136" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.Collections; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug136 extends PApplet { + + +java.util.List alist = Collections.synchronizedList(new ArrayList()); + +public void setup() { +size(400, 200); +alist.add("hello"); +} + +public void draw() { +rect(width/4, height/4, width/2, height/2); +synchronized(alist) { +alist.get(0); +} +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug136" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1362.expected b/app/test/resources/bug1362.expected index 479feefb6..00c81e622 100644 --- a/app/test/resources/bug1362.expected +++ b/app/test/resources/bug1362.expected @@ -1,29 +1,29 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1362 extends PApplet { - public void setup() { -if (true) {} else { new String(); } - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1362" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1362 extends PApplet { + public void setup() { +if (true) {} else { new String(); } + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1362" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1442.expected b/app/test/resources/bug1442.expected index 1a22ef53a..d48380587 100644 --- a/app/test/resources/bug1442.expected +++ b/app/test/resources/bug1442.expected @@ -1,28 +1,28 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1442 extends PApplet { - -public float a() { - return 1.0f; -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1442" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1442 extends PApplet { + +public float a() { + return 1.0f; +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1442" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1511.expected b/app/test/resources/bug1511.expected index 10a0d155a..ca423630f 100644 --- a/app/test/resources/bug1511.expected +++ b/app/test/resources/bug1511.expected @@ -1,37 +1,37 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.io.StringWriter; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1511 extends PApplet { - public void setup() { -// \u00df - -/** -* a -*/ - - - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1511" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.io.StringWriter; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1511 extends PApplet { + public void setup() { +// \u00df + +/** +* a +*/ + + + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1511" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1512.expected b/app/test/resources/bug1512.expected index 511615729..bb2bd9aa0 100644 --- a/app/test/resources/bug1512.expected +++ b/app/test/resources/bug1512.expected @@ -1,29 +1,29 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1512 extends PApplet { - public void setup() { -println("oi/*"); - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1512" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1512 extends PApplet { + public void setup() { +println("oi/*"); + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1512" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1514a.expected b/app/test/resources/bug1514a.expected index 7596c2745..f53288ca6 100644 --- a/app/test/resources/bug1514a.expected +++ b/app/test/resources/bug1514a.expected @@ -1,35 +1,35 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.io.StringWriter; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1514a extends PApplet { - public void setup() { -//----- \u00e8\u00e9\u00e9\u00e8\u00e8\u00e9\u00e9\u00e9\u00e0\u00e9\u00e9\u00e8\u00e9''\u00e9\u00e9\u00e9 -//---------------------------------------------------------------- -//--- IMPORTS -//---------------------------------------------------------------- - - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1514a" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.io.StringWriter; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1514a extends PApplet { + public void setup() { +//----- \u00e8\u00e9\u00e9\u00e8\u00e8\u00e9\u00e9\u00e9\u00e0\u00e9\u00e9\u00e8\u00e9''\u00e9\u00e9\u00e9 +//---------------------------------------------------------------- +//--- IMPORTS +//---------------------------------------------------------------- + + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1514a" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1514b.expected b/app/test/resources/bug1514b.expected index b7628ef32..49b6a19fd 100644 --- a/app/test/resources/bug1514b.expected +++ b/app/test/resources/bug1514b.expected @@ -1,35 +1,35 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.io.StringWriter; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1514b extends PApplet { - public void setup() { -//----- \u00e8\u00e9\u00e9\u00e8\u00e8\u00e9\u00e9\u00e9\u00e0\u00e9\u00e9\u00e8\u00e9''\u00e9\u00e9 -//---------------------------------------------------------------- -//--- IMPORTS -//---------------------------------------------------------------- - - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1514b" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.io.StringWriter; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1514b extends PApplet { + public void setup() { +//----- \u00e8\u00e9\u00e9\u00e8\u00e8\u00e9\u00e9\u00e9\u00e0\u00e9\u00e9\u00e8\u00e9''\u00e9\u00e9 +//---------------------------------------------------------------- +//--- IMPORTS +//---------------------------------------------------------------- + + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1514b" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1515.expected b/app/test/resources/bug1515.expected index f2d0ae2c4..d883739e3 100644 --- a/app/test/resources/bug1515.expected +++ b/app/test/resources/bug1515.expected @@ -1,32 +1,32 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1515 extends PApplet { - -// a class definition that does something with things that extend PApplet -class Heythere{ -} - -// method definition which can do things with papplet -public void doSomething( T thing ){ -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1515" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1515 extends PApplet { + +// a class definition that does something with things that extend PApplet +class Heythere{ +} + +// method definition which can do things with papplet +public void doSomething( T thing ){ +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1515" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1516.expected b/app/test/resources/bug1516.expected index 15eb348d3..0fbef0c45 100644 --- a/app/test/resources/bug1516.expected +++ b/app/test/resources/bug1516.expected @@ -1,52 +1,52 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Collections; -import java.util.Comparator; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1516 extends PApplet { - - - - - - -public void setup() -{ -List list = new ArrayList(); -list.add("foo"); -list.add("bar"); -list.add("baz"); - -Comparator comparator = new Comparator() -{ -public int compare(final String value0, final String value1) -{ -return value0.compareTo(value1); -} -}; - -Collections.sort(list, comparator); -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1516" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; +import java.util.Comparator; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1516 extends PApplet { + + + + + + +public void setup() +{ +List list = new ArrayList(); +list.add("foo"); +list.add("bar"); +list.add("baz"); + +Comparator comparator = new Comparator() +{ +public int compare(final String value0, final String value1) +{ +return value0.compareTo(value1); +} +}; + +Collections.sort(list, comparator); +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1516" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1517.expected b/app/test/resources/bug1517.expected index b8bac1af2..5af236bb6 100644 --- a/app/test/resources/bug1517.expected +++ b/app/test/resources/bug1517.expected @@ -1,52 +1,52 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Collections; -import java.util.Comparator; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1517 extends PApplet { - - - - - - -Comparator comparator = new Comparator() -{ -public int compare(final String value0, final String value1) -{ -return value0.compareTo(value1); -} -}; - -public void setup() -{ -List list = new ArrayList(); -list.add("foo"); -list.add("bar"); -list.add("baz"); - -Collections.sort(list, comparator); -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1517" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; +import java.util.Comparator; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1517 extends PApplet { + + + + + + +Comparator comparator = new Comparator() +{ +public int compare(final String value0, final String value1) +{ +return value0.compareTo(value1); +} +}; + +public void setup() +{ +List list = new ArrayList(); +list.add("foo"); +list.add("bar"); +list.add("baz"); + +Collections.sort(list, comparator); +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1517" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1518a.expected b/app/test/resources/bug1518a.expected index 55288cc3c..49c81c14c 100644 --- a/app/test/resources/bug1518a.expected +++ b/app/test/resources/bug1518a.expected @@ -1,45 +1,45 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.ArrayList; -import java.util.List; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1518a extends PApplet { - - - - -public void setup() -{ -List list = new ArrayList(); -list.add("foo"); -list.add("bar"); -list.add("baz"); - -binarySearch(list, "bar"); -} - -static int binarySearch(List> list, T -key) { -return 0; -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1518a" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.ArrayList; +import java.util.List; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1518a extends PApplet { + + + + +public void setup() +{ +List list = new ArrayList(); +list.add("foo"); +list.add("bar"); +list.add("baz"); + +binarySearch(list, "bar"); +} + +static int binarySearch(List> list, T +key) { +return 0; +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1518a" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug1518b.expected b/app/test/resources/bug1518b.expected index f4144e7b1..2ca376adf 100644 --- a/app/test/resources/bug1518b.expected +++ b/app/test/resources/bug1518b.expected @@ -1,43 +1,43 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.ArrayList; -import java.util.List; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug1518b extends PApplet { - - - - -public void setup() -{ -List list = new ArrayList(); -list.add("foo"); -list.add("bar"); -list.add("baz"); -} - -static int binarySearch(List> list, T -key) { -return 0; -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug1518b" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.ArrayList; +import java.util.List; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug1518b extends PApplet { + + + + +public void setup() +{ +List list = new ArrayList(); +list.add("foo"); +list.add("bar"); +list.add("baz"); +} + +static int binarySearch(List> list, T +key) { +return 0; +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug1518b" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug281.expected b/app/test/resources/bug281.expected index d6e7f4154..ffc6ea519 100644 --- a/app/test/resources/bug281.expected +++ b/app/test/resources/bug281.expected @@ -1,32 +1,32 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug281 extends PApplet { - public void setup() { -if ( "monopoly".charAt( 3 ) == '(' ) -{ - println("parcheesi"); -} - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug281" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug281 extends PApplet { + public void setup() { +if ( "monopoly".charAt( 3 ) == '(' ) +{ + println("parcheesi"); +} + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug281" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug481.expected b/app/test/resources/bug481.expected index ef2848da3..10d76993b 100644 --- a/app/test/resources/bug481.expected +++ b/app/test/resources/bug481.expected @@ -1,32 +1,32 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.applet.Applet; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug481 extends PApplet { - public void setup() { - -Class[] abc = new Class[]{Applet.class}; - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug481" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.applet.Applet; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug481 extends PApplet { + public void setup() { + +Class[] abc = new Class[]{Applet.class}; + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug481" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug598.expected b/app/test/resources/bug598.expected index 988c1125b..e3c91eef6 100644 --- a/app/test/resources/bug598.expected +++ b/app/test/resources/bug598.expected @@ -1,70 +1,70 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import static java.lang.Math.tanh; -import java.util.concurrent.Callable; -import java.util.List; -import java.util.Comparator; -import java.util.Map; -import java.util.Collection; -import java.util.Arrays; -import java.util.HashSet; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug598 extends PApplet { - -// java 5 torture test - - - - - - - - - - - -private static Comparator rotarapmoc = new Comparator() { - public int compare(final String o1, final String o2) - { - return o1.charAt(o1.length() - 1) - o2.charAt(o2.length() - 1); - } -}; - -final void printClass(T t) { - println(t.getClass()); -} -public final List sortem(final String... strings) { - Arrays.sort(strings, rotarapmoc); - return Arrays.asList(strings); -} - -final Map> -charlesDeGaulle = new HashMap>(); - -public void setup() { - charlesDeGaulle.put("banana", new HashSet()); - charlesDeGaulle.get("banana").add(0); - System.out.println(sortem("aztec", "maya", "spanish", "portuguese")); - printClass(12.d); -} - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug598" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import static java.lang.Math.tanh; +import java.util.concurrent.Callable; +import java.util.List; +import java.util.Comparator; +import java.util.Map; +import java.util.Collection; +import java.util.Arrays; +import java.util.HashSet; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug598 extends PApplet { + +// java 5 torture test + + + + + + + + + + + +private static Comparator rotarapmoc = new Comparator() { + public int compare(final String o1, final String o2) + { + return o1.charAt(o1.length() - 1) - o2.charAt(o2.length() - 1); + } +}; + +final void printClass(T t) { + println(t.getClass()); +} +public final List sortem(final String... strings) { + Arrays.sort(strings, rotarapmoc); + return Arrays.asList(strings); +} + +final Map> +charlesDeGaulle = new HashMap>(); + +public void setup() { + charlesDeGaulle.put("banana", new HashSet()); + charlesDeGaulle.get("banana").add(0); + System.out.println(sortem("aztec", "maya", "spanish", "portuguese")); + printClass(12.d); +} + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug598" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug5a.expected b/app/test/resources/bug5a.expected index 326bd783e..c29588dfc 100644 --- a/app/test/resources/bug5a.expected +++ b/app/test/resources/bug5a.expected @@ -1,30 +1,30 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug5a extends PApplet { - public void setup() { -println("The next line should not cause a failure."); -// no newline after me - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug5a" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug5a extends PApplet { + public void setup() { +println("The next line should not cause a failure."); +// no newline after me + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug5a" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/app/test/resources/bug5b.expected b/app/test/resources/bug5b.expected index 3731e6723..058be9ab3 100644 --- a/app/test/resources/bug5b.expected +++ b/app/test/resources/bug5b.expected @@ -1,30 +1,30 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class bug5b extends PApplet { - public void setup() { -println("The next line should not cause a failure."); -/* no newline after me */ - noLoop(); - } - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "bug5b" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} +import processing.core.*; +import processing.data.*; +import processing.event.*; +import processing.opengl.*; + +import java.util.HashMap; +import java.util.ArrayList; +import java.io.File; +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class bug5b extends PApplet { + public void setup() { +println("The next line should not cause a failure."); +/* no newline after me */ + noLoop(); + } + + static public void main(String[] passedArgs) { + String[] appletArgs = new String[] { "bug5b" }; + if (passedArgs != null) { + PApplet.main(concat(appletArgs, passedArgs)); + } else { + PApplet.main(appletArgs); + } + } +} diff --git a/build/build.xml b/build/build.xml index 53457029f..ce445a9b5 100644 --- a/build/build.xml +++ b/build/build.xml @@ -759,7 +759,7 @@ - diff --git a/build/macosx/jAppleMenuBar.url b/build/macosx/jAppleMenuBar.url index 62dc0f635..2e5268909 100644 --- a/build/macosx/jAppleMenuBar.url +++ b/build/macosx/jAppleMenuBar.url @@ -1,2 +1,2 @@ -[InternetShortcut] -URL=https://github.com/kritzikratzi/jAppleMenuBar +[InternetShortcut] +URL=https://github.com/kritzikratzi/jAppleMenuBar diff --git a/build/shared/lib/fonts/LICENSE.txt b/build/shared/lib/fonts/LICENSE.txt index d154618a7..117733042 100644 --- a/build/shared/lib/fonts/LICENSE.txt +++ b/build/shared/lib/fonts/LICENSE.txt @@ -1,93 +1,93 @@ -Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. - -This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/build/windows/processing.bat b/build/windows/processing.bat index 7f0b9b3ea..64e7291eb 100755 --- a/build/windows/processing.bat +++ b/build/windows/processing.bat @@ -1,3 +1,3 @@ -@echo off - +@echo off + .\java\bin\java -cp lib/pde.jar;core/library/core.jar;lib/jna.jar;lib/antlr.jar;lib/ant.jar;lib/ant-launcher.jar;lib/org-netbeans-swing-outline.jar;lib/com.ibm.icu_4.4.2.v20110823.jar;lib/jdi.jar;lib/jdimodel.jar;lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar processing.app.Base \ No newline at end of file diff --git a/core/README.md b/core/README.md index 70f30dcbc..103563d75 100644 --- a/core/README.md +++ b/core/README.md @@ -20,6 +20,9 @@ We're removing `Applet` as the base class for `PApplet` and redoing the entire r 1. One downside is that you'll no longer be able to just drop a Processing sketch into other Java code, because `PApplet` will no longer subclass `Applet` (and therefore, `Component`). This is a huge downside for a tiny number of users. For the majority of users, re-read the "why" section. We'll try to figure out ways to continue embedding in other Java code, however, since we use this in our own work, and even within Processing itself (the Color Selector). 2. We're still determining how much code we're willing to break due to API changes. Stay tuned. +#### Offscreen rendering +* createGraphics() will create a buffer that's not resizable. `PGraphics.setSize()` is called in `PApplet.makeGraphics()`, and that's the end of the story. No `Surface.setSize()` calls are involved as in a normal rendering situation. + #### Retina/HiDPI/2x drawing and displays * Documentation changes [here](https://github.com/processing/processing-docs/issues/170) ## The Mess diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 06aa33d91..cef795f0d 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -5442,6 +5442,9 @@ public class PApplet implements PConstants { * @see PApplet#createFont(String, float, boolean, char[]) */ public PFont loadFont(String filename) { + if (!filename.toLowerCase().endsWith(".vlw")) { + throw new IllegalArgumentException("loadFont() only works with .vlw font files"); + } try { InputStream input = createInput(filename); return new PFont(input); @@ -9479,7 +9482,7 @@ public class PApplet implements PConstants { //System.out.println("interrupt"); } } - System.out.println("out of default size loop, " + width + " " + height); +// System.out.println("out of default size loop, " + width + " " + height); // convenience to avoid another 'get' from the static main() method return surface; } diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index fa523edaf..46e88033e 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -269,8 +269,17 @@ public class PGraphicsJava2D extends PGraphics { @Override public void beginDraw() { + // TODO this will happen when it's offscreen.. need a better option here + if (image == null || + ((BufferedImage) image).getWidth() != width || + ((BufferedImage) image).getHeight() != height) { + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + } g2 = (Graphics2D) image.getGraphics(); + // Calling getGraphics() seems to nuke the smoothing settings + smooth(quality); + /* // NOTE: Calling image.getGraphics() will create a new Graphics context, // even if it's for the same image that's already had a context created. diff --git a/core/src/processing/core/PSurfaceAWT.java b/core/src/processing/core/PSurfaceAWT.java index 8a854b7cb..d40e2bda3 100644 --- a/core/src/processing/core/PSurfaceAWT.java +++ b/core/src/processing/core/PSurfaceAWT.java @@ -87,7 +87,7 @@ public class PSurfaceAWT implements PSurface { void createCanvas() { canvas = new SmoothCanvas(); - //canvas.setIgnoreRepaint(true); // ?? + canvas.setIgnoreRepaint(true); // ?? // send tab keys through to the PApplet canvas.setFocusTraversalKeysEnabled(false); @@ -278,12 +278,18 @@ public class PSurfaceAWT implements PSurface { // not sure why this was here, can't be good //canvas.setBounds(0, 0, sketch.width, sketch.height); + if (!canvas.isDisplayable()) { +// System.out.println("no peer.. holding"); + return; + } + // System.out.println("render(), canvas bounds are " + canvas.getBounds()); if (canvas.getBufferStrategy() == null) { // whole block [121222] // System.out.println("creating a strategy"); canvas.createBufferStrategy(2); } BufferStrategy strategy = canvas.getBufferStrategy(); +// System.out.println(strategy); if (strategy == null) { return; } @@ -367,7 +373,9 @@ public class PSurfaceAWT implements PSurface { public void blit() { - canvas.repaint(); +// System.out.println("blit"); + ((SmoothCanvas) canvas).render(); // ?? +// canvas.repaint(); /* if (canvas.getGraphicsConfiguration() != null) { GraphicsDevice device = canvas.getGraphicsConfiguration().getDevice(); @@ -671,8 +679,8 @@ public class PSurfaceAWT implements PSurface { /** Resize frame for these sketch (canvas) dimensions. */ private Dimension setFrameSize() { //int sketchWidth, int sketchHeight) { - System.out.format("setting frame size %d %d %n", sketchWidth, sketchHeight); - new Exception().printStackTrace(System.out); +// System.out.format("setting frame size %d %d %n", sketchWidth, sketchHeight); +// new Exception().printStackTrace(System.out); Insets insets = frame.getInsets(); int windowW = Math.max(sketchWidth, MIN_WINDOW_WIDTH) + insets.left + insets.right; @@ -795,13 +803,13 @@ public class PSurfaceAWT implements PSurface { synchronized (pauseObject) { try { pauseObject.wait(); - PApplet.debug("out of wait"); +// PApplet.debug("out of wait"); } catch (InterruptedException e) { // waiting for this interrupt on a start() (resume) call } } } - PApplet.debug("done with pause"); +// PApplet.debug("done with pause"); } @@ -815,17 +823,21 @@ public class PSurfaceAWT implements PSurface { // needs to resize the frame, which will resize the canvas, and so on... public void setSize(int wide, int high) { - System.out.format("frame visible %b, setSize(%d, %d) %n", frame.isVisible(), wide, high); - new Exception().printStackTrace(System.out); +// System.out.format("frame visible %b, setSize(%d, %d) %n", frame.isVisible(), wide, high); +// new Exception().printStackTrace(System.out); sketchWidth = wide; sketchHeight = high; // canvas.setSize(wide, high); // frame.setSize(wide, high); - setFrameSize(); //wide, high); + if (frame != null) { // canvas only + setFrameSize(); //wide, high); + } setCanvasSize(); - frame.setLocationRelativeTo(null); + if (frame != null) { + frame.setLocationRelativeTo(null); + } GraphicsConfiguration gc = canvas.getGraphicsConfiguration(); // If not realized (off-screen, i.e the Color Selector Tool), gc will be null. diff --git a/core/todo.txt b/core/todo.txt index b0e18f38d..4c229ec4b 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,14 +1,59 @@ 0233 (3.0a6) +X remove Applet as base class +X how to name the retina pixel stuff +X hint(ENABLE_RETINA_PIXELS) or hint(ENABLE_HIDPI_PIXELS) +X hint(ENABLE_2X_PIXELS)? +X hidpi is Apple's name as well +X mostly getting away from this + +earlier +X size(640,360 , P3D) doesn't work properly +X https://github.com/processing/processing/issues/2924 +X https://github.com/processing/processing/issues/2925 -graphics -X roll back full screen changes -X https://github.com/processing/processing/issues/2641 +applet/sketch X remove isGL(), is2D(), is3D(), displayable() from PApplet X these were auto-imported from PGraphics X remove pause variable from PApplet (was not documented) X added copy() to PImage (to work like get(), ala PVector) X added getFontRenderContext() to PGraphics +X why doesn't p5 punt when loadFont() is used on an otf? +X is this a GL problem? (example in bug report wasn't GL) +X https://github.com/processing/processing/issues/2876 +X since we don't have any magic number in there, just randomly breaks +X add check to require .vlw extension with loadFont() +_ performance issues on OS X (might be threading due to Applet) +_ https://github.com/processing/processing/issues/2423 +_ clean up requestFocus() stuff +_ make sure it works with retina/canvas/strategy as well +_ requestFocus() method probably needs to be added to PApplet +_ remove sketch path hack from PApplet +_ args[] should be null if none passed (otherwise args == null checks are weird) + + +full screen +X roll back full screen changes +X https://github.com/processing/processing/issues/2641 +o new full screen sometimes causes sketch to temporarily be in the wrong spot +X removed the new stuff since it stank, rolled back to menu bar hiding +X add option to have full screen span across screens +o display=all in cmd line +o sketchDisplay() -> 0 for all, or 1, 2, 3... +X added --span option +X play with improvements to full screen here +_ show warning when display spanning is turned off +_ defaults read com.apple.spaces spans-displays +_ crash on startup when "Mirror Displays" selected (cantfix?) +_ suspect that this is a specific chipset since Oracle didn't reproduce +_ AMD Radeon HD 6770M was in the Oracle bug report +_ https://github.com/processing/processing/issues/2186 +_ https://bugs.openjdk.java.net/browse/JDK-8027391 +_ test with JG's 13" retina laptop + + +graphics +_ how to allocation image object w/ createGraphics() (since no surface) _ add attrib() method _ https://github.com/processing/processing/issues/2963 _ assign this to DXF as well? @@ -16,31 +61,33 @@ _ createGraphics() currently broken in Java2D _ size() command not working to do a resize _ deal with applySettings() change (maybe not a problem?) -_ remove sketch path hack from PApplet python has to use launch() instead of open() map() is bad for Python (and JavaScript?) -_ args[] should be null if none passed (otherwise args == null checks are weird) -_ size(640,360 , P3D) doesn't work properly -_ https://github.com/processing/processing/issues/2924 -_ why doesn't p5 punt when loadFont() is used on an otf? -_ is this a GL problem? -_ show warning when display spanning is turned off -_ defaults read com.apple.spaces spans-displays - -applet/component -_ remove Applet as base class -_ performance issues on OS X (might be threading due to Applet) -_ https://github.com/processing/processing/issues/2423 -_ play with improvements to full screen here -_ new full screen sometimes causes sketch to temporarily be in the wrong spot -_ add option to have full screen span across screens -_ display=all in cmd line -_ sketchDisplay() -> 0 for all, or 1, 2, 3... -_ clean up requestFocus() stuff -_ make sure it works with retina/canvas/strategy as well +under consideration +_ break PUtil out from PApplet +_ break more api with Processing 3? +_ use enums for everything (fixes auto-completion) +_ add chaining operations +_ move to enums instead of PConstants? +_ helps textMode() only accept valid entries +_ really nice for auto-complete +_ prevents hundreds of entries from coming up w/ auto-complete +_ downside: breaks compatibility big time +_ fix the registered methods doc, stop/dispose working +_ Casey needs to nudge people about libraries, so we need to fix this +_ pause(), resume(), start(), stop() clarifications +_ dispose/stop not great w/ libraries yet +_ PShape complete refactoring +_ proper touch events +_ touch event doesn't make sense for mouseMove on desktop, hover on Android +_ probably go with pointer: more universal for touch/mouse +_ high-level touch events (swipe, et al) +_ if Andres is done, they go in, if not then 3.0 +_ move away from loadPixels +_ implement requestXxxx() API processing.data @@ -96,18 +143,20 @@ _ needs to have a way to set width/height properly _ draw(s) doesn't work on the returned PShape -hidpi +retina/hidpi +_ the 2X thing on the renderer name is unnecessary +_ just do pixelFactor() (and pull it during compilation)? +_ add sketchPixelFactor() to handle the scenario? +_ or is it just a boolean, because pixelFactor(2) is the only option? +_ remove retina hint +_ Text looks blurry in GL Retina (andres) +_ https://github.com/processing/processing/issues/2739 +_ check retina with PGraphicsRetina2D _ Text is half size in PGraphicsRetina2D _ https://github.com/processing/processing/issues/2738 _ text not getting the correct font in Retina2D _ https://github.com/processing/processing/issues/2617 _ saveFrame() with retina render is making black images -_ zero alpha values still a problem with retina renderer -_ https://github.com/processing/processing/issues/2030 -_ how to name the retina pixel stuff -_ hint(ENABLE_RETINA_PIXELS) or hint(ENABLE_HIDPI_PIXELS) -_ hint(ENABLE_2X_PIXELS)? -_ hidpi is Apple's name as well _ no high-res display support for OpenGL _ https://github.com/processing/processing/issues/2573 _ https://jogamp.org/bugzilla/show_bug.cgi?id=741 @@ -115,16 +164,10 @@ _ no high-dpi support for core on Windows _ https://github.com/processing/processing/issues/2411 _ retina sketches slow to start _ https://github.com/processing/processing/issues/2357 -_ Text looks blurry in GL Retina -_ https://github.com/processing/processing/issues/2739 - - -cantfix -_ crash on startup when "Mirror Displays" selected -_ suspect that this is a specific chipset since Oracle didn't reproduce -_ https://github.com/processing/processing/issues/2186 -_ test with JG's 13" retina laptop - +_ zero alpha values still a problem with retina renderer +_ https://github.com/processing/processing/issues/2030 +_ NPE when using image() created with createGraphics(PGraphicsRetina2D) +_ https://github.com/processing/processing/issues/2510 decisions/misc _ use enums for constants diff --git a/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs b/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs index d8cc55f4b..2770cf1bf 100644 --- a/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/dxf/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ -#Sat Nov 12 10:56:00 CST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +#Sat Nov 12 10:56:00 CST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs b/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs index 5a822da57..f709eac1e 100644 --- a/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs +++ b/java/libraries/serial/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ -#Sat Nov 12 10:56:44 CST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +#Sat Nov 12 10:56:44 CST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/todo.txt b/todo.txt index 9d3fc0296..4e4c1c7e2 100644 --- a/todo.txt +++ b/todo.txt @@ -13,6 +13,9 @@ X https://github.com/processing/processing/issues/2947 X server.stop produces an error: java.net.SocketException: socket closed X https://github.com/processing/processing/issues/74 X https://github.com/processing/processing/pull/2474 +X NPE when calling Client.ip() after the connection has been closed +X https://github.com/processing/processing/issues/2576 +X https://github.com/processing/processing/pull/2922 joel X Add reference for installed tools and libraries to the Help menu @@ -35,6 +38,10 @@ X http://code.google.com/p/processing/issues/detail?id=75 X these bits need to be checked to ensure that they work on other distros X https://github.com/processing/processing/issues/114 X https://github.com/processing/processing/pull/2972 +X https://github.com/processing/processing/issues/2973 +X https://github.com/processing/processing/pull/2974 +X Replace ColorChooser PApplets with custom Swing components +X https://github.com/processing/processing/pull/2975 _ make examples pull/build automatic during dist @@ -52,6 +59,13 @@ _ https://github.com/processing/processing/issues/2960 _ Add support for localizing contributions _ https://github.com/processing/processing/pull/2833 +from the todo list +_ reas: comments go nasty when auto-formatted +_ reas: code coloring sometimes disappears +_ me: undo not in the correct location +_ implement the new gui +_ drop XP support (but improve Windows 8 support? ouch) + high _ dist needs to do a git pull on processing-docs @@ -395,6 +409,8 @@ _ http://code.google.com/p/processing/issues/detail?id=494 PDE / Editor +_ Undo does not move to the correct location in the editor window +_ https://github.com/processing/processing/issues/707 _ clean up /tmp folders used during build _ https://github.com/processing/processing/issues/1896 _ 'recent' menu doesn't respect examples folder of other p5 versions