From c86fecd36f59a7d59261173b73648965f3eb1bd4 Mon Sep 17 00:00:00 2001 From: Daniel Howe Date: Sun, 27 Oct 2013 19:12:43 +0800 Subject: [PATCH] added support for specifying packages to import in library.properties (github issue# 2134) --- app/src/processing/app/Editor.java | 2 +- app/src/processing/app/Mode.java | 29 +- .../app/contrib/LocalContribution.java | 303 +++++++++--------- app/src/processing/mode/java/JavaEditor.java | 66 ++-- 4 files changed, 217 insertions(+), 183 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3463555e0..92c43a80e 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -899,7 +899,7 @@ public abstract class Editor extends JFrame implements RunnerListener { } - abstract public void handleImportLibrary(String jarPath); + abstract public void handleImportLibrary(String name); public JMenu getToolMenu() { diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index 0efa9c72e..c83e24c25 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -448,7 +448,10 @@ public abstract class Mode { for (Library library : coreLibraries) { JMenuItem item = new JMenuItem(library.getName()); item.addActionListener(listener); - item.setActionCommand(library.getJarPath()); + + // changed to library-name to facilitate specification if imports from properties file + item.setActionCommand(library.getName()); + importMenu.add(item); } } @@ -464,7 +467,9 @@ public abstract class Mode { for (Library library : contribLibraries) { JMenuItem item = new JMenuItem(library.getName()); item.addActionListener(listener); - item.setActionCommand(library.getJarPath()); + + // changed to library-name to facilitate specification if imports from properties file + item.setActionCommand(library.getName()); String group = library.getGroup(); if (group != null) { @@ -1033,6 +1038,26 @@ public abstract class Mode { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + /** + * Checks coreLibraries and contribLibraries in 'mode' for a library whose name is 'libName' + * @param mode the mode to check + * @param libName the name of the library + * @return the Library or null if not found + */ + public Library findLibraryByName(String libName) { + + for (Library lib : this.coreLibraries) { + if (libName.equals(lib.getName())) + return lib; + } + + for (Library lib : this.contribLibraries) { + if (libName.equals(lib.getName())) + return lib; + } + + return null; + } /** * Create a fresh applet/application folder if the 'delete target folder' diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java index 03a6e0f31..19dceb0d9 100644 --- a/app/src/processing/app/contrib/LocalContribution.java +++ b/app/src/processing/app/contrib/LocalContribution.java @@ -1,24 +1,24 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* - Part of the Processing project - http://processing.org + Part of the Processing project - http://processing.org - Copyright (c) 2013 The Processing Foundation - Copyright (c) 2011-12 Ben Fry and Casey Reas + 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 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. + 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 -*/ + 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.*; @@ -31,22 +31,28 @@ 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. +/** + * 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 RESTART_FLAG = "requires_restart"; - - protected String id; // 1 (unique id for this library) - protected int latestVersion; // 103 + + protected String id; // 1 (unique id for this library) + + protected int latestVersion; // 103 + protected File folder; + protected HashMap properties; + protected ClassLoader loader; - + + protected List specifiedImports; // "processing.pdf, processing.pdf.util"; public LocalContribution(File folder) { this.folder = folder; @@ -59,6 +65,8 @@ public abstract class LocalContribution extends Contribution { name = properties.get("name"); id = properties.get("id"); categories = parseCategories(properties.get("category")); + specifiedImports = parseImports(properties.get("imports")); + if (name == null) { name = folder.getName(); } @@ -70,11 +78,13 @@ public abstract class LocalContribution extends Contribution { 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."); + 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"); - + } else { Base.log("No properties file at " + propertiesFile.getAbsolutePath()); // We'll need this to be set at a minimum. @@ -83,6 +93,42 @@ public abstract class LocalContribution extends Contribution { } } + /** + * Returns the imports (package-names) for a library, as specified in its library.properties + * (e.g., imports=libname.*,libname.support.*) + * + * @return String[] packageNames (without wildcards) or null if none are specified + */ + public String[] getSpecifiedImports() { + + return specifiedImports != null ? specifiedImports.toArray(new String[0]) : null; + } + + /** + * @return the list of Java imports to be added to the sketch when the library is imported + * or null if none are specified + */ + protected static List parseImports(String importsStr) { + + List outgoing = new ArrayList(); + + if (importsStr != null) { + + String[] listing = PApplet.trim(PApplet.split(importsStr, ',')); + for (String imp : listing) { + + // In case the wildcard is specified, strip it, as it gets added later) + if (imp.endsWith(".*")) { + + imp = imp.substring(0, imp.length() - 2); + } + + outgoing.add(imp); + } + } + + return (outgoing.size() > 0) ? outgoing : null; + } public String initLoader(String className) throws Exception { File modeDirectory = new File(folder, getTypeName()); @@ -96,12 +142,13 @@ public abstract class LocalContribution extends Contribution { if (mainJar.exists()) { className = findClassInZipFile(shortName, mainJar); } else { - throw new IgnorableException(mainJar.getAbsolutePath() + " does not exist."); + throw new IgnorableException(mainJar.getAbsolutePath() + + " does not exist."); } if (className == null) { - throw new IgnorableException("Could not find " + shortName + - " class inside " + mainJar.getAbsolutePath()); + throw new IgnorableException("Could not find " + shortName + + " class inside " + mainJar.getAbsolutePath()); } } @@ -128,24 +175,15 @@ public abstract class LocalContribution extends Contribution { 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(); - } - } - */ - + * // 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() && @@ -183,22 +221,21 @@ public abstract class LocalContribution extends Contribution { // } // return folders[0]; // } - - - LocalContribution copyAndLoad(Editor editor, - boolean confirmReplace, + + LocalContribution copyAndLoad(Editor editor, boolean confirmReplace, StatusPanel status) { - ArrayList oldContribs = - getType().listContributions(editor); - + ArrayList oldContribs = getType() + .listContributions(editor); + String contribFolderName = getFolder().getName(); File contribTypeFolder = getType().getSketchbookFolder(); File 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.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 @@ -207,32 +244,45 @@ public abstract class LocalContribution extends Contribution { } } else { int result = 0; - boolean doBackup = Preferences.getBoolean("contribution.backup.on_install"); + 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)) { + 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()) { + 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())) { + if ((doBackup && !oldContrib.backup(editor, true, status)) + || (!doBackup && !oldContrib.getFolder().delete())) { return null; } } @@ -244,48 +294,44 @@ public abstract class LocalContribution extends Contribution { if (contribFolder.exists()) { Base.removeDir(contribFolder); } - File oldFolder = getFolder(); try { - Base.copyDir(oldFolder, contribFolder); + Base.copyDir(oldFolder, contribFolder); } catch (IOException e) { - status.setErrorMessage("Could not copy " + getTypeName() + - " \"" + getName() + "\" to the sketchbook."); + 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; - } - */ - + * if (!getFolder().renameTo(contribFolder)) { + * status.setErrorMessage("Could not move " + getTypeName() + " \"" + + * getName() + "\" to the sketchbook."); return null; } + */ + return getType().load(editor.getBase(), 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); + File backupSubFolder = ContributionManager.getUniqueName(backupFolder, + backupName); if (deleteOriginal) { success = getFolder().renameTo(backupSubFolder); @@ -293,7 +339,8 @@ public abstract class LocalContribution extends Contribution { try { Base.copyDir(getFolder(), backupSubFolder); success = true; - } catch (IOException e) { } + } catch (IOException e) { + } } if (!success) { status.setErrorMessage("Could not move contribution to backup folder."); @@ -302,28 +349,20 @@ public abstract class LocalContribution extends Contribution { return success; } - /** * Non-blocking call to remove a contribution in a new thread. */ - void removeContribution(final Editor editor, - final ProgressMonitor pm, + void removeContribution(final Editor editor, final ProgressMonitor pm, final StatusPanel status) { new Thread(new Runnable() { public void run() { - remove(editor, - pm, - status, - ContributionListing.getInstance()); + remove(editor, pm, status, ContributionListing.getInstance()); } }).start(); } - - - void remove(final Editor editor, - final ProgressMonitor pm, - final StatusPanel status, - final ContributionListing contribListing) { + + 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"); @@ -343,8 +382,8 @@ public abstract class LocalContribution extends Contribution { } if (success) { - Contribution advertisedVersion = - contribListing.getAvailableContribution(this); + Contribution advertisedVersion = contribListing + .getAvailableContribution(this); if (advertisedVersion == null) { contribListing.removeContribution(this); @@ -362,16 +401,13 @@ public abstract class LocalContribution extends Contribution { pm.finished(); } - public File getFolder() { return folder; } - public boolean isInstalled() { return folder != null; } - // public String getCategory() { // return category; @@ -382,12 +418,10 @@ public abstract class LocalContribution extends Contribution { // return name; // } - public String getId() { return id; } - // public String getAuthorList() { // return authorList; // } @@ -412,12 +446,10 @@ public abstract class LocalContribution extends Contribution { // return version; // } - public int getLatestVersion() { return latestVersion; } - // public String getPrettyVersion() { // return prettyVersion; // } @@ -427,54 +459,40 @@ public abstract class LocalContribution extends Contribution { // 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; - } - */ - - + * 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 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()) { @@ -482,10 +500,8 @@ public abstract class LocalContribution extends Contribution { } } - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - private boolean setFlag(String flagFilename, boolean flag) { if (flag) { // Only returns false if the file already exists, so we can @@ -497,22 +513,20 @@ public abstract class LocalContribution extends Contribution { return false; } } else { - return new File(getFolder(), flagFilename).delete(); + return new File(getFolder(), flagFilename).delete(); } } - - + static private boolean isFlagged(File folder, String flagFilename) { - return new File(folder, flagFilename).exists(); + return new File(folder, flagFilename).exists(); } - // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - /** - * - * @param base name of the class, with or without the package + * + * @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 */ @@ -547,7 +561,6 @@ public abstract class LocalContribution extends Contribution { return null; } - static protected class IgnorableException extends Exception { public IgnorableException(String msg) { super(msg); diff --git a/app/src/processing/mode/java/JavaEditor.java b/app/src/processing/mode/java/JavaEditor.java index 676db1272..fc5816733 100644 --- a/app/src/processing/mode/java/JavaEditor.java +++ b/app/src/processing/mode/java/JavaEditor.java @@ -4,12 +4,14 @@ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; +import java.util.Arrays; import javax.swing.*; import javax.swing.border.*; import processing.app.*; import processing.app.Toolkit; +import processing.app.contrib.LocalContribution; import processing.mode.java.runner.Runner; @@ -266,9 +268,7 @@ public class JavaEditor extends Editor { label2.setAlignmentX(Component.LEFT_ALIGNMENT); panel.add(label1); panel.add(label2); - // The longer line is different between Windows and OS X. - int wide = Math.max(label1.getPreferredSize().width, - label2.getPreferredSize().width); + int wide = label1.getPreferredSize().width; panel.add(Box.createVerticalStrut(12)); /* @@ -314,9 +314,6 @@ public class JavaEditor extends Editor { panel.add(platformPanel); */ - //int indent = new JCheckBox().getPreferredSize().width; - int indent = 0; - final JCheckBox showStopButton = new JCheckBox("Show a Stop button"); showStopButton.setSelected(Preferences.getBoolean("export.application.stop")); showStopButton.addItemListener(new ItemListener() { @@ -325,7 +322,7 @@ public class JavaEditor extends Editor { } }); showStopButton.setEnabled(Preferences.getBoolean("export.application.fullscreen")); - showStopButton.setBorder(new EmptyBorder(3, 13 + indent, 6, 13)); + showStopButton.setBorder(new EmptyBorder(3, 13, 6, 13)); final JCheckBox fullScreenButton = new JCheckBox("Full Screen (Present mode)"); fullScreenButton.setSelected(Preferences.getBoolean("export.application.fullscreen")); @@ -338,33 +335,10 @@ public class JavaEditor extends Editor { }); fullScreenButton.setBorder(new EmptyBorder(3, 13, 3, 13)); - boolean embed = Preferences.getBoolean("export.application.embed_java"); - final String embedWarning = "Embedding Java makes larger applications"; - final String nopeWarning = "Users will have to install the latest Java 7"; - final JLabel warningLabel = new JLabel(embed ? embedWarning : nopeWarning); - warningLabel.setBorder(new EmptyBorder(3, 13 + indent, 3, 13)); - - final JCheckBox embedJavaButton = new JCheckBox("Embed Java"); - embedJavaButton.setSelected(embed); - embedJavaButton.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - boolean selected = embedJavaButton.isSelected(); - Preferences.setBoolean("export.application.embed_java", selected); - if (selected) { - warningLabel.setText(embedWarning); - } else { - warningLabel.setText(nopeWarning); - } - } - }); - embedJavaButton.setBorder(new EmptyBorder(3, 13, 3, 13)); - JPanel optionPanel = new JPanel(); optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.Y_AXIS)); optionPanel.add(fullScreenButton); optionPanel.add(showStopButton); - optionPanel.add(embedJavaButton); - optionPanel.add(warningLabel); optionPanel.setBorder(new TitledBorder("Options")); // wide = Math.max(wide, platformPanel.getPreferredSize().width); optionPanel.setAlignmentX(Component.LEFT_ALIGNMENT); @@ -379,7 +353,7 @@ public class JavaEditor extends Editor { // good = new Dimension(wide, platformPanel.getPreferredSize().height); // platformPanel.setMaximumSize(good); good = new Dimension(wide, optionPanel.getPreferredSize().height); -// optionPanel.setMaximumSize(good); + optionPanel.setMaximumSize(good); String[] options = { "Export", "Cancel" }; final JOptionPane optionPane = new JOptionPane(panel, @@ -534,7 +508,17 @@ public class JavaEditor extends Editor { * Add import statements to the current tab for all of packages inside * the specified jar file. */ - public void handleImportLibrary(String jarPath) { + public void handleImportLibrary(String libraryName) { + + Library lib = mode.findLibraryByName(libraryName); + + if (lib == null) { + statusError("Unable to locate library: "+libraryName); + return; + } + + String jarPath = lib.getJarPath(); + // make sure the user didn't hide the sketch folder sketch.ensureExistence(); @@ -542,19 +526,31 @@ public class JavaEditor extends Editor { // if the current code is a .java file, insert into current //if (current.flavor == PDE) { if (mode.isDefaultExtension(sketch.getCurrentCode())) { + sketch.setCurrentCode(0); } // could also scan the text in the file to see if each import // statement is already in there, but if the user has the import // commented out, then this will be a problem. - String[] list = Base.packageListFromClassPath(jarPath); + + String[] libImports = lib.getSpecifiedImports(); // ask the library for its imports + + if (libImports == null) { + + // Default to old behavior and load every package in the primary jar + libImports = Base.packageListFromClassPath(jarPath); + } + + //System.out.println("JavaEditor.packageListFromClassPath("+libraryName+") -> "+Arrays.asList(plcp)); + StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < list.length; i++) { + for (int i = 0; i < libImports.length; i++) { buffer.append("import "); - buffer.append(list[i]); + buffer.append(libImports[i]); buffer.append(".*;\n"); } + buffer.append('\n'); buffer.append(getText()); setText(buffer.toString());