working through contrib cleanup and simplification

This commit is contained in:
Ben Fry
2013-02-16 13:41:00 -05:00
parent 08b2496477
commit 13c926eeb4
11 changed files with 552 additions and 634 deletions

View File

@@ -6,6 +6,7 @@ import java.util.*;
import processing.app.contrib.*;
import processing.core.*;
public class Library extends InstalledContribution {
static final String[] platformNames = PConstants.platformNames;
@@ -14,7 +15,10 @@ public class Library extends InstalledContribution {
protected File examplesFolder; // shortname/examples
protected File referenceFile; // shortname/reference/index.html
/** Subfolder for grouping libraries in a menu. */
/**
* Subfolder for grouping libraries in a menu. Basic subfolder support
* is provided so that basic organization can be done in the import menu.
*/
protected String group;
/** Packages provided by this library. */

View File

@@ -0,0 +1,197 @@
package processing.app.contrib;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import processing.app.Base;
import processing.app.Editor;
import processing.core.PApplet;
class AdvertisedContribution implements Contribution {
protected final String name; // "pdf" or "PDF Export"
protected final ContributionType type; // Library, tool, etc.
protected final String category; // "Sound"
protected final String authorList; // [Ben Fry](http://benfry.com/)
protected final String url; // http://processing.org
protected final String sentence; // Write graphics to PDF files.
protected final String paragraph; // <paragraph length description for site>
protected final int version; // 102
protected final String prettyVersion; // "1.0.2"
protected final String link; // Direct link to download the file
public AdvertisedContribution(ContributionType type, HashMap<String, String> exports) {
this.type = type;
name = exports.get("name");
category = ContributionListing.getCategory(exports.get("category"));
authorList = exports.get("authorList");
url = exports.get("url");
sentence = exports.get("sentence");
paragraph = exports.get("paragraph");
int v = 0;
try {
v = Integer.parseInt(exports.get("version"));
} catch (NumberFormatException e) {
}
version = v;
prettyVersion = exports.get("prettyVersion");
this.link = exports.get("download");
}
/**
* @param contribArchive
* a zip file containing the library to install
* @param ad
* the advertised version of this library, if it was downloaded
* through the Contribution Manager. This is used to check the type
* of library being installed, and to replace the .properties file in
* the zip
* @param confirmReplace
* true to open a dialog asking the user to confirm removing/moving
* the library when a library by the same name already exists
* @return
*/
public InstalledContribution install(Editor editor, File contribArchive,
boolean confirmReplace,
ErrorWidget statusBar) {
// Unzip the file into the modes, tools, or libraries folder inside the
// sketchbook. Unzipping to /tmp is problematic because it may be on
// another file system, so move/rename operations will break.
File sketchbookContribFolder =
ContributionManager.getSketchbookContribFolder(editor.getBase(), type);
File tempFolder = null;
try {
tempFolder =
Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder);
} catch (IOException e) {
statusBar.setErrorMessage("Could not create a temporary folder to install.");
return null;
}
ContributionManager.unzip(contribArchive, tempFolder);
// Now go looking for a legit contrib inside what's been unpacked.
File contribFolder = null;
// Sometimes contrib authors place all their folders in the base directory
// of the .zip file instead of in single folder as the guidelines suggest.
if (InstalledContribution.isCandidate(tempFolder, type)) {
contribFolder = tempFolder;
}
if (contribFolder == null) {
// Find the first legitimate looking folder in what we just unzipped
contribFolder = InstalledContribution.findCandidate(tempFolder, type);
}
InstalledContribution outgoing = null;
if (contribFolder == null) {
statusBar.setErrorMessage("Could not find a " + type + " in the downloaded file.");
} else {
File propFile = new File(contribFolder, type + ".properties");
if (writePropertiesFile(propFile)) {
InstalledContribution newContrib =
ContributionManager.load(editor.getBase(), contribFolder, type);
outgoing =
newContrib.install(editor, confirmReplace, statusBar);
} else {
statusBar.setErrorMessage("Error overwriting .properties file.");
}
}
// Remove any remaining boogers
if (tempFolder.exists()) {
Base.removeDir(tempFolder);
}
return outgoing;
}
public boolean isInstalled() {
return false;
}
public ContributionType getType() {
return type;
}
public String getTypeName() {
return type.toString();
}
public String getCategory() {
return category;
}
public String getName() {
return name;
}
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 String getPrettyVersion() {
return prettyVersion;
}
public boolean writePropertiesFile(File propFile) {
try {
if (propFile.delete() && propFile.createNewFile() && propFile.setWritable(true)) {
//BufferedWriter bw = new BufferedWriter(new FileWriter(propFile));
PrintWriter writer = PApplet.createWriter(propFile);
writer.println("name=" + getName());
writer.println("category=" + getCategory());
writer.println("authorList=" + getAuthorList());
writer.println("url=" + getUrl());
writer.println("sentence=" + getSentence());
writer.println("paragraph=" + getParagraph());
writer.println("version=" + getVersion());
writer.println("prettyVersion=" + getPrettyVersion());
writer.flush();
writer.close();
}
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}

View File

@@ -40,7 +40,6 @@ import java.io.File;
import java.net.*;
import processing.app.Base;
import processing.app.contrib.ContributionListing.AdvertisedContribution;
import processing.app.contrib.ContributionListing.ContributionChangeListener;
public class ContributionListPanel extends JPanel implements Scrollable, ContributionChangeListener {

View File

@@ -80,7 +80,7 @@ public class ContributionListing {
listingFile = file;
advertisedContributions.clear();
advertisedContributions.addAll(getLibraries(listingFile));
advertisedContributions.addAll(parseContribList(listingFile));
for (Contribution contribution : advertisedContributions) {
addContribution(contribution);
}
@@ -246,12 +246,13 @@ public class ContributionListing {
// Chances are the person is still typing the property, so rather than
// make the list flash empty (because nothing contains "is:" or "has:",
// just return true.
if (!isProperty(property))
if (!isProperty(property)) {
return true;
}
if ("is".equals(isText) || "has".equals(isText)) {
return hasProperty(contrib, filter.substring(colon + 1));
} else if ("not".equals(isText)) {
} else if ("not".equals(isText)) {
return !hasProperty(contrib, filter.substring(colon + 1));
}
}
@@ -324,6 +325,7 @@ public class ContributionListing {
}
}
public void addContributionListener(ContributionChangeListener listener) {
for (Contribution contrib : allContributions) {
listener.contributionAdded(contrib);
@@ -331,14 +333,17 @@ public class ContributionListing {
listeners.add(listener);
}
public void removeContributionListener(ContributionChangeListener listener) {
listeners.remove(listener);
}
public ArrayList<ContributionChangeListener> getContributionListeners() {
return new ArrayList<ContributionChangeListener>(listeners);
}
/**
* Starts a new thread to download the advertised list of contributions.
* Only one instance will run at a time.
@@ -360,7 +365,7 @@ public class ContributionListing {
}
if (!progressMonitor.isFinished()) {
FileDownloader.downloadFile(url, listingFile, progressMonitor);
download(url, listingFile, progressMonitor);
if (!progressMonitor.isCanceled() && !progressMonitor.isError()) {
hasDownloadedLatestList = true;
setAdvertisedList(listingFile);
@@ -370,6 +375,56 @@ public class ContributionListing {
}
}).start();
}
/**
* 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
* @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();
conn.setConnectTimeout(1000);
conn.setReadTimeout(5000);
// 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("Downloading", fileSize);
InputStream in = conn.getInputStream();
FileOutputStream out = new FileOutputStream(dest);
byte[] b = new byte[8192];
int amount;
int total = 0;
while (!progress.isCanceled() && (amount = in.read(b)) != -1) {
out.write(b, 0, amount);
total += amount;
progress.setProgress(total);
}
out.flush();
out.close();
success = true;
} catch (IOException ioe) {
progress.error(ioe);
ioe.printStackTrace();
}
progress.finished();
return success;
}
public boolean hasUpdates() {
@@ -434,7 +489,7 @@ public class ContributionListing {
}
public ArrayList<AdvertisedContribution> getLibraries(File f) {
public ArrayList<AdvertisedContribution> parseContribList(File f) {
ArrayList<AdvertisedContribution> outgoing = new ArrayList<AdvertisedContribution>();
if (f != null && f.exists()) {
@@ -476,116 +531,6 @@ public class ContributionListing {
}
static class AdvertisedContribution implements Contribution {
protected final String name; // "pdf" or "PDF Export"
protected final ContributionType type; // Library, tool, etc.
protected final String category; // "Sound"
protected final String authorList; // [Ben Fry](http://benfry.com/)
protected final String url; // http://processing.org
protected final String sentence; // Write graphics to PDF files.
protected final String paragraph; // <paragraph length description for site>
protected final int version; // 102
protected final String prettyVersion; // "1.0.2"
protected final String link; // Direct link to download the file
public AdvertisedContribution(ContributionType type, HashMap<String, String> exports) {
this.type = type;
name = exports.get("name");
category = ContributionListing.getCategory(exports.get("category"));
authorList = exports.get("authorList");
url = exports.get("url");
sentence = exports.get("sentence");
paragraph = exports.get("paragraph");
int v = 0;
try {
v = Integer.parseInt(exports.get("version"));
} catch (NumberFormatException e) {
}
version = v;
prettyVersion = exports.get("prettyVersion");
this.link = exports.get("download");
}
public boolean isInstalled() {
return false;
}
public ContributionType getType() {
return type;
}
public String getTypeName() {
return type.toString();
}
public String getCategory() {
return category;
}
public String getName() {
return name;
}
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 String getPrettyVersion() {
return prettyVersion;
}
public boolean writePropertiesFile(File propFile) {
try {
if (propFile.delete() && propFile.createNewFile() && propFile.setWritable(true)) {
//BufferedWriter bw = new BufferedWriter(new FileWriter(propFile));
PrintWriter writer = PApplet.createWriter(propFile);
writer.println("name=" + getName());
writer.println("category=" + getCategory());
writer.println("authorList=" + getAuthorList());
writer.println("url=" + getUrl());
writer.println("sentence=" + getSentence());
writer.println("paragraph=" + getParagraph());
writer.println("version=" + getVersion());
writer.println("prettyVersion=" + getPrettyVersion());
writer.flush();
writer.close();
}
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
public boolean isDownloadingListing() {
return downloadingListingLock.isLocked();
}

View File

@@ -6,13 +6,10 @@ import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.*;
import javax.swing.JOptionPane;
import processing.app.Base;
import processing.app.Editor;
import processing.app.Library;
import processing.app.Preferences;
import processing.app.contrib.ContributionListing.AdvertisedContribution;
interface ErrorWidget {
@@ -102,26 +99,40 @@ public class ContributionManager {
static public void downloadAndInstall(final Editor editor,
final URL url,
final AdvertisedContribution ad,
final JProgressMonitor downloadProgressMonitor,
final JProgressMonitor installProgressMonitor,
final JProgressMonitor downloadProgress,
final JProgressMonitor installProgress,
final ErrorWidget statusBar) {
new Thread(new Runnable() {
public void run() {
final File libArchive = createTemporaryFile(url, statusBar);
FileDownloader.downloadFile(url, libArchive, downloadProgressMonitor);
if (!downloadProgressMonitor.isCanceled() && !downloadProgressMonitor.isError()) {
installProgressMonitor.startTask("Installing", ProgressMonitor.UNKNOWN);
InstalledContribution contribution = null;
contribution = install(editor, libArchive, ad, false, statusBar);
String filename = url.getFile();
filename = filename.substring(filename.lastIndexOf('/') + 1);
try {
File contribZip = File.createTempFile("download", filename);
contribZip.setWritable(true); // necessary?
if (contribution != null) {
contribListing.replaceContribution(ad, contribution);
refreshInstalled(editor);
try {
ContributionListing.download(url, contribZip, downloadProgress);
if (!downloadProgress.isCanceled() && !downloadProgress.isError()) {
installProgress.startTask("Installing", ProgressMonitor.UNKNOWN);
InstalledContribution contribution = null;
contribution = ad.install(editor, contribZip, false, statusBar);
if (contribution != null) {
contribListing.replaceContribution(ad, contribution);
refreshInstalled(editor);
}
installProgress.finished();
}
contribZip.delete();
} catch (Exception e) {
statusBar.setErrorMessage("Error during download and install.");
}
installProgressMonitor.finished();
} catch (IOException e) {
statusBar.setErrorMessage("Could not write to temporary directory.");
}
libArchive.delete();
}
}).start();
}
@@ -133,23 +144,23 @@ public class ContributionManager {
}
/**
* Used after unpacking a contrib download do determine the file contents.
*/
static List<File> discover(ContributionType type, File tempDir) {
switch (type) {
case LIBRARY:
return Library.discover(tempDir);
// case LIBRARY_COMPILATION:
// // XXX Implement
// return null;
case TOOL:
return ToolContribution.discover(tempDir);
case MODE:
return ModeContribution.discover(tempDir);
}
return null;
}
// /**
// * Used after unpacking a contrib download do determine the file contents.
// */
// static List<File> discover(ContributionType type, File tempDir) {
// switch (type) {
// case LIBRARY:
// return Library.discover(tempDir);
//// case LIBRARY_COMPILATION:
//// // XXX Implement
//// return null;
// case TOOL:
// return ToolContribution.discover(tempDir);
// case MODE:
// return ModeContribution.discover(tempDir);
// }
// return null;
// }
// static String getPropertiesFileName(Type type) {
@@ -182,7 +193,7 @@ public class ContributionManager {
}
static InstalledContribution create(Base base, File folder, ContributionType type) {
static InstalledContribution load(Base base, File folder, ContributionType type) {
switch (type) {
case LIBRARY:
return new Library(folder);
@@ -239,31 +250,55 @@ public class ContributionManager {
* the library when a library by the same name already exists
* @return
*/
/*
static public InstalledContribution install(Editor editor, File libFile,
AdvertisedContribution ad,
boolean confirmReplace,
ErrorWidget statusBar) {
ContributionType type = ad.getType();
// Unzip the file into the modes, tools, or libraries folder inside the
// sketchbook. Unzipping to /tmp is problematic because it may be on
// another file system, so move/rename operations will break.
File sketchbookContribFolder =
getSketchbookContribFolder(editor.getBase(), type);
File tempFolder = null;
try {
tempFolder =
Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder);
} catch (IOException e) {
statusBar.setErrorMessage("Could not create a temporary folder to install.");
return null;
}
ContributionManager.unzip(libFile, tempFolder);
File tempDir = ContributionManager.unzipFileToTemp(libFile, statusBar);
List<File> libFolders = ContributionManager.discover(ad.getType(), tempDir);
InstalledContribution outgoing = null;
if (libFolders.isEmpty()) {
// Sometimes library authors place all their folders in the base
// directory of a zip file instead of in single folder as the
// guidelines suggest. If this is the case, we might be able to find the
// library by stepping up a directory and searching for libraries again.
libFolders = ContributionManager.discover(ad.getType(), tempDir.getParentFile());
// Now go looking for a legit contrib inside what's been unpacked.
File contribFolder = null;
// Sometimes contrib authors place all their folders in the base directory
// of the .zip file instead of in single folder as the guidelines suggest.
if (InstalledContribution.isCandidate(tempFolder, type)) {
contribFolder = tempFolder;
}
if (libFolders != null && libFolders.size() == 1) {
File libFolder = libFolders.get(0);
// File propFile = new File(libFolder, getPropertiesFileName(ad.getType()));
File propFile = new File(libFolder, ad.getTypeName() + ".properties");
if (contribFolder == null) {
// Find the first legitimate looking folder in what we just unzipped
contribFolder = InstalledContribution.findCandidate(tempFolder, type);
}
InstalledContribution outgoing = null;
if (contribFolder == null) {
statusBar.setErrorMessage("Could not find a " + type + " in the downloaded file.");
} else {
File propFile = new File(contribFolder, type + ".properties");
if (ad.writePropertiesFile(propFile)) {
InstalledContribution newContrib =
ContributionManager.create(editor.getBase(), libFolder, ad.getType());
ContributionManager.create(editor.getBase(), contribFolder, type);
outgoing = ContributionManager.installContribution(editor, newContrib,
confirmReplace,
@@ -271,24 +306,15 @@ public class ContributionManager {
} else {
statusBar.setErrorMessage("Error overwriting .properties file.");
}
} else {
// Diagnose the problem and notify the user
if (libFolders == null) {
statusBar.setErrorMessage("An internal error occured while searching "
+ "for contributions in the downloaded file.");
} else if (libFolders.isEmpty()) {
statusBar.setErrorMessage("Maybe it's just me, but it looks like " +
"there are no contributions in the file " +
"for \"" + ad.getName() + ".\"");
} else {
statusBar.setErrorMessage("There were multiple libraries in the file, " +
"so we're ignoring it.");
}
}
Base.removeDir(tempDir);
// Remove any remaining boogers
if (tempFolder.exists()) {
Base.removeDir(tempFolder);
}
return outgoing;
}
*/
/**
@@ -297,19 +323,21 @@ public class ContributionManager {
* ask the user if it's okay to replace the library. If false, the
* library is always replaced with the new copy.
*/
/*
static public InstalledContribution installContribution(Editor editor, InstalledContribution newContrib,
boolean confirmReplace, ErrorWidget statusBar) {
ArrayList<InstalledContribution> oldContribs =
getContributions(newContrib.getType(), editor);
String contribFolderName = newContrib.getFolder().getName();
ArrayList<InstalledContribution> oldContribs = getContributions(newContrib.getType(), editor);
String libFolderName = newContrib.getFolder().getName();
File libraryDestination =
ContributionManager.getSketchbookContribFolder(editor.getBase(), newContrib.getType());
File newContribDest = new File(libraryDestination, libFolderName);
File contribTypeFolder =
getSketchbookContribFolder(editor.getBase(), newContrib.getType());
File contribFolder = new File(contribTypeFolder, contribFolderName);
for (InstalledContribution oldContrib : oldContribs) {
if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(newContribDest)) ||
if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(contribFolder)) ||
(oldContrib.getId() != null && oldContrib.getId().equals(newContrib.getId()))) {
if (ContributionManager.requiresRestart(oldContrib)) {
@@ -352,15 +380,15 @@ public class ContributionManager {
}
}
if (newContribDest.exists()) {
Base.removeDir(newContribDest);
if (contribFolder.exists()) {
Base.removeDir(contribFolder);
}
// Move newLib to the sketchbook library folder
if (newContrib.getFolder().renameTo(newContribDest)) {
if (newContrib.getFolder().renameTo(contribFolder)) {
Base base = editor.getBase();
/* InstalledContribution contrib = */
ContributionManager.create(base, newContribDest, newContrib.getType());
// InstalledContribution contrib =
ContributionManager.create(base, contribFolder, newContrib.getType());
// try {
// initialize(contrib, base);
// return contrib;
@@ -391,6 +419,7 @@ public class ContributionManager {
}
return null;
}
*/
/*
@@ -531,52 +560,52 @@ public class ContributionManager {
}
static protected File createTemporaryFile(URL url, ErrorWidget statusBar) {
try {
// //File tmpFolder = Base.createTempFolder("library", "download", Base.getSketchbookLibrariesFolder());
// String[] segments = url.getFile().split("/");
// File libFile = new File(tmpFolder, segments[segments.length - 1]);
String filename = url.getFile();
filename = filename.substring(filename.lastIndexOf('/') + 1);
File libFile = File.createTempFile("download", filename, Base.getSketchbookLibrariesFolder());
libFile.setWritable(true);
return libFile;
} catch (IOException e) {
statusBar.setErrorMessage("Could not create a temp folder for download.");
}
return null;
}
// static protected File createTemporaryFile(URL url, ErrorWidget statusBar) {
// try {
//// //File tmpFolder = Base.createTempFolder("library", "download", Base.getSketchbookLibrariesFolder());
//// String[] segments = url.getFile().split("/");
//// File libFile = new File(tmpFolder, segments[segments.length - 1]);
// String filename = url.getFile();
// filename = filename.substring(filename.lastIndexOf('/') + 1);
// File libFile = File.createTempFile("download", filename, Base.getSketchbookLibrariesFolder());
// libFile.setWritable(true);
// return libFile;
//
// } catch (IOException e) {
// statusBar.setErrorMessage("Could not create a temp folder for download.");
// }
// return null;
// }
/**
* Creates a temporary folder and unzips a file to a subdirectory of the temp
* folder. The subdirectory is the only file of the tempo folder.
*
* e.g. if the contents of foo.zip are /hello and /world, then the resulting
* files will be
* /tmp/foo9432423uncompressed/foo/hello
* /tmp/foo9432423uncompress/foo/world
* ...and "/tmp/id9432423uncompress/foo/" will be returned.
*
* @return the folder where the zips contents have been unzipped to (the
* subdirectory of the temp folder).
*/
static public File unzipFileToTemp(File libFile, ErrorWidget statusBar) {
String fileName = ContributionManager.getFileName(libFile);
File tmpFolder = null;
try {
tmpFolder = Base.createTempFolder(fileName, "uncompressed", Base.getSketchbookLibrariesFolder());
// tmpFolder = new File(tmpFolder, fileName); // don't make another subdirectory
// tmpFolder.mkdirs();
} catch (IOException e) {
statusBar.setErrorMessage("Could not create temp folder to uncompress zip file.");
}
ContributionManager.unzip(libFile, tmpFolder);
return tmpFolder;
}
// /**
// * Creates a temporary folder and unzips a file to a subdirectory of the temp
// * folder. The subdirectory is the only file of the tempo folder.
// *
// * e.g. if the contents of foo.zip are /hello and /world, then the resulting
// * files will be
// * /tmp/foo9432423uncompressed/foo/hello
// * /tmp/foo9432423uncompress/foo/world
// * ...and "/tmp/id9432423uncompress/foo/" will be returned.
// *
// * @return the folder where the zips contents have been unzipped to (the
// * subdirectory of the temp folder).
// */
// static public File unzipFileToTemp(File libFile, ErrorWidget statusBar) {
// String fileName = ContributionManager.getFileName(libFile);
// File tmpFolder = null;
//
// try {
// tmpFolder = Base.createTempFolder(fileName, "uncompressed", Base.getSketchbookLibrariesFolder());
//// tmpFolder = new File(tmpFolder, fileName); // don't make another subdirectory
//// tmpFolder.mkdirs();
// } catch (IOException e) {
// statusBar.setErrorMessage("Could not create temp folder to uncompress zip file.");
// }
//
// ContributionManager.unzip(libFile, tmpFolder);
// return tmpFolder;
// }
/**

View File

@@ -33,6 +33,11 @@ public enum ContributionType {
}
return null; // should be unreachable
}
// public String getPropertiesName() {
// return toString() + ".properties";
// }
static public ContributionType fromName(String s) {

View File

@@ -1,83 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-11 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class FileDownloader {
/**
* 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
* @throws FileNotFoundException
* if an error occurred downloading the file
*/
static public void downloadFile(URL source, File dest,
ProgressMonitor progress) {
try {
// System.out.println("downloading file " + source);
URLConnection conn = source.openConnection();
conn.setConnectTimeout(1000);
conn.setReadTimeout(5000);
// 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("Downloading", fileSize);
InputStream in = conn.getInputStream();
FileOutputStream out = new FileOutputStream(dest);
byte[] b = new byte[8192];
int amount;
int total = 0;
while (!progress.isCanceled() && (amount = in.read(b)) != -1) {
out.write(b, 0, amount);
total += amount;
progress.setProgress(total);
}
out.flush();
out.close();
} catch (IOException ioe) {
progress.error(ioe);
ioe.printStackTrace();
}
progress.finished();
// System.out.println("done downloading");
}
}

View File

@@ -23,17 +23,17 @@
package processing.app.contrib;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.zip.*;
import javax.swing.JOptionPane;
import processing.app.*;
public abstract class InstalledContribution implements Contribution {
protected String name; // "pdf" or "PDF Export"
protected String id; // 1
protected String category; // "Sound"
@@ -112,7 +112,7 @@ public abstract class InstalledContribution implements Contribution {
if (archives != null && archives.length > 0) {
URL[] urlList = new URL[archives.length];
for (int j = 0; j < urlList.length; j++) {
Base.log("found lib: " + archives[j] + " for " + getName());
Base.log("Found archive " + archives[j] + " for " + getName());
urlList[j] = archives[j].toURI().toURL();
}
// loader = new URLClassLoader(urlList, Thread.currentThread().getContextClassLoader());
@@ -131,6 +131,7 @@ public abstract class InstalledContribution implements Contribution {
}
/*
// doesn't work with URLClassLoader, but works with the system CL
static void listClasses(ClassLoader loader) {
// loader = Thread.currentThread().getContextClassLoader();
@@ -145,23 +146,117 @@ public abstract class InstalledContribution implements Contribution {
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 String typeName) {
static protected File[] listCandidates(File folder, final ContributionType type) {
return folder.listFiles(new FileFilter() {
public boolean accept(File potential) {
return (potential.isDirectory() &&
new File(potential, typeName).exists());
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];
}
InstalledContribution install(Editor editor,
boolean confirmReplace,
ErrorWidget statusBar) {
ArrayList<InstalledContribution> oldContribs =
ContributionManager.getContributions(getType(), editor);
String contribFolderName = getFolder().getName();
File contribTypeFolder =
ContributionManager.getSketchbookContribFolder(editor.getBase(), getType());
File contribFolder = new File(contribTypeFolder, contribFolderName);
for (InstalledContribution oldContrib : oldContribs) {
if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(contribFolder)) ||
(oldContrib.getId() != null && oldContrib.getId().equals(getId()))) {
if (ContributionManager.requiresRestart(oldContrib)) {
// XXX: We can't replace stuff, soooooo.... do something different
if (!ContributionManager.backupContribution(editor, oldContrib, false, statusBar)) {
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<br>"+
"has been found in your sketchbook. Clicking “Yes”<br>"+
"will move the existing library to a backup folder<br>" +
" in <i>libraries/old</i> before replacing it.");
if (result != JOptionPane.YES_OPTION || !ContributionManager.backupContribution(editor, oldContrib, true, statusBar)) {
return null;
}
} else {
result = Base.showYesNoQuestion(editor, "Replace",
"Replace pre-existing \"" + oldContrib.getName() + "\" library?",
"A pre-existing copy of the \"" + oldContrib.getName() + "\" library<br>"+
"has been found in your sketchbook. Clicking “Yes”<br>"+
"will permanently delete this library and all of its contents<br>"+
"before replacing it.");
if (result != JOptionPane.YES_OPTION || !oldContrib.getFolder().delete()) {
return null;
}
}
} else {
if ((doBackup && !ContributionManager.backupContribution(editor, oldContrib, true, statusBar)) ||
(!doBackup && !oldContrib.getFolder().delete())) {
return null;
}
}
}
}
}
// At this point it should be safe to replace this fella
if (contribFolder.exists()) {
Base.removeDir(contribFolder);
}
if (!getFolder().renameTo(contribFolder)) {
statusBar.setErrorMessage("Could not move " + getTypeName() +
" \"" + getName() + "\" to the sketchbook.");
return null;
}
return ContributionManager.load(editor.getBase(), contribFolder, getType());
}
public File getFolder() {
return folder;
}

View File

@@ -25,49 +25,22 @@ package processing.app.contrib;
import java.io.File;
//import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import processing.app.Base;
import processing.app.Mode;
public class ModeContribution extends InstalledContribution {
// static final String propertiesFileName = "mode.properties";
/** Class name with package declaration. */
// private String className;
private Mode mode;
// Base base;
// static public Mode getCoreMode(Base base, String className, File folder) {
// try {
// Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(className);
//// Class c = Class.forName(classname);
// Constructor cc = c.getConstructor(Base.class, File.class);
// return (Mode) cc.newInstance(base, folder);
// } catch (Exception e) {
// e.printStackTrace();
// }
// return null;
// }
// static public ModeContribution getContributedMode(Base base, File folder) {
// ModeContribution mode = new ModeContribution(base, folder);
// return mode.isValid() ? mode : null;
// }
// static public ModeContribution load(Base base, File folder) {
static public ModeContribution load(Base base, File folder) {
return load(base, folder, null);
}
// static public ModeContribution load(Base base, File folder, String searchName) {
static public ModeContribution load(Base base, File folder,
String searchName) {
try {
@@ -109,69 +82,30 @@ public class ModeContribution extends InstalledContribution {
mode.setupGUI();
}
}
// // Class name already found above, go ahead and instantiate
// if (className != null) {
//// try {
// System.out.println("instantiating " + className + " using loader " + loader);
//// Class<?> modeClass = Class.forName(className, true, loader);
// modeClass = loader.loadClass(className);
//// return true;
//// } catch (Exception e) {
//// e.printStackTrace();
//// }
//// return false;
//// }
//
// } else { // className == null, might be a built-in fella
// System.out.println("class name null while looking for " + searchName);
//// try {
// // Probably a contributed mode, check to see if it's already available
// if (loader.loadClass(searchName) != null) {
// System.out.println(" found " + searchName + " after all");
// className = searchName;
// }
//// } catch (ClassNotFoundException e) {
//// e.printStackTrace();
//// }
// }
//
// if (modeClass != null) {
// Constructor con = modeClass.getConstructor(Base.class, File.class);
// mode = (Mode) con.newInstance(base, folder);
// mode.setupGUI();
// }
}
// private boolean isValid() {
// return className != null;
// }
static public void loadMissing(Base base) {
File modesFolder = Base.getSketchbookModesFolder();
ArrayList<ModeContribution> contribModes = base.getModeContribs();
// /**
// * Creates an instance of the Mode object. Warning: this makes it impossible
// * (on Windows) to move the files in the mode's classpath without restarting
// * the PDE.
// */
// public boolean instantiateModeClass(Base base) {
// new Exception().printStackTrace(System.out);
// try {
// System.out.println("instantiating " + className + " using loader " + loader);
//// Class<?> modeClass = Class.forName(className, true, loader);
// Class<?> modeClass = loader != null ?
// loader.loadClass(className) :
// Thread.currentThread().getContextClassLoader().loadClass(className);
// Constructor contr = modeClass.getConstructor(Base.class, File.class);
// mode = (Mode) contr.newInstance(base, folder);
// mode.setupGUI();
// return true;
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// return false;
// }
HashMap<File, ModeContribution> existing = new HashMap<File, ModeContribution>();
for (ModeContribution contrib : contribModes) {
existing.put(contrib.getFolder(), contrib);
}
File[] potential = listCandidates(modesFolder, ContributionType.MODE);
for (File folder : potential) {
if (!existing.containsKey(folder)) {
try {
contribModes.add(new ModeContribution(base, folder, null));
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public Mode getMode() {
@@ -189,80 +123,16 @@ public class ModeContribution extends InstalledContribution {
return false;
}
ModeContribution other = (ModeContribution) o;
// return loader.equals(other.loader) && className.equals(other.className);
return loader.equals(other.loader) && mode.equals(other.getMode());
}
static public void loadMissing(Base base) {
File modesFolder = Base.getSketchbookModesFolder();
ArrayList<ModeContribution> contribModes = base.getModeContribs();
HashMap<File, ModeContribution> existing = new HashMap<File, ModeContribution>();
for (ModeContribution contrib : contribModes) {
existing.put(contrib.getFolder(), contrib);
}
File[] potential = listCandidates(modesFolder, "mode");
for (File folder : potential) {
if (!existing.containsKey(folder)) {
try {
contribModes.add(new ModeContribution(base, folder, null));
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// static public ArrayList<ModeContribution> loadAll(Base base, File folder) {
// ArrayList<ModeContribution> modes = new ArrayList<ModeContribution>();
// ArrayList<File> modeFolders = discover(folder);
//
// for (File potentialModeFolder : modeFolders) {
// //ModeContribution contrib = getContributedMode(base, potentialModeFolder);
// ModeContribution contrib = load(base, potentialModeFolder);
// if (contrib != null) {
// modes.add(contrib);
// }
// }
// return modes;
// }
// static protected ArrayList<File> discover(File folder) {
// ArrayList<File> modeFolders = new ArrayList<File>();
//// discover(folder, modeFolders);
//// return modeFolders;
//// }
////
////
//// static protected void discover(File folder, ArrayList<File> modeFolders) {
// static protected List<File> discover(File folder) {
// File[] folders = listCandidates(folder, "mode");
//// File[] folders = folder.listFiles(new FileFilter() {
//// public boolean accept(File potentialModeFolder) {
//// return (potentialModeFolder.isDirectory() &&
//// new File(potentialModeFolder, "mode").exists());
//// }
//// });
//
// if (folders != null && folders.length > 0) {
// for (File potentialModeFolder : folders) {
// modeFolders.add(potentialModeFolder);
// }
// if (folders == null) {
// return new ArrayList<File>();
// } else {
// return Arrays.asList(folders);
// }
// return modeFolders;
// }
static protected List<File> discover(File folder) {
File[] folders = listCandidates(folder, "mode");
if (folders == null) {
return new ArrayList<File>();
} else {
return Arrays.asList(folders);
}
}
}

View File

@@ -33,9 +33,6 @@ import processing.app.tools.Tool;
public class ToolContribution extends InstalledContribution implements Tool {
// static String propertiesFileName = "tool.properties";
// private String className;
private Tool tool;
@@ -59,73 +56,21 @@ public class ToolContribution extends InstalledContribution implements Tool {
Class<?> toolClass = loader.loadClass(className);
tool = (Tool) toolClass.newInstance();
}
// File toolDirectory = new File(folder, "tool");
// // add dir to classpath for .classes
// //urlList.add(toolDirectory.toURL());
//
// // add .jar files to classpath
// File[] archives = Base.listJarFiles(toolDirectory);
//// File[] archives = toolDirectory.listFiles(new FilenameFilter() {
//// public boolean accept(File dir, String name) {
//// return (name.toLowerCase().endsWith(".jar") ||
//// name.toLowerCase().endsWith(".zip"));
//// }
//// });
//
// if (archives != null && archives.length > 0) {
// try {
// URL[] urlList = new URL[archives.length];
// for (int j = 0; j < urlList.length; j++) {
// urlList[j] = archives[j].toURI().toURL();
// }
// loader = new URLClassLoader(urlList);
//
// for (int j = 0; j < archives.length; j++) {
// className = findClassInZipFile(folder.getName(), archives[j]);
// if (className != null) break;
// }
// } catch (MalformedURLException e) { }
// }
//
// /*
// // Alternatively, could use manifest files with special attributes:
// // http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html
// // Example code for loading from a manifest file:
// // http://forums.sun.com/thread.jspa?messageID=3791501
// File infoFile = new File(toolDirectory, "tool.txt");
// if (!infoFile.exists()) continue;
//
// String[] info = PApplet.loadStrings(infoFile);
// //Main-Class: org.poo.shoe.AwesomerTool
// //String className = folders[i].getName();
// String className = null;
// for (int k = 0; k < info.length; k++) {
// if (info[k].startsWith(";")) continue;
//
// String[] pieces = PApplet.splitTokens(info[k], ": ");
// if (pieces.length == 2) {
// if (pieces[0].equals("Main-Class")) {
// className = pieces[1];
// }
// }
// }
// */
}
static protected List<File> discover(File folder) {
File[] folders = listCandidates(folder, "tool");
if (folders == null) {
return new ArrayList<File>();
} else {
return Arrays.asList(folders);
}
}
// static protected List<File> discover(File folder) {
// File[] folders = listCandidates(folder, "tool");
// if (folders == null) {
// return new ArrayList<File>();
// } else {
// return Arrays.asList(folders);
// }
// }
static public ArrayList<ToolContribution> loadAll(File toolsFolder) {
List<File> list = discover(toolsFolder);
File[] list = listCandidates(toolsFolder, ContributionType.TOOL);
ArrayList<ToolContribution> outgoing = new ArrayList<ToolContribution>();
for (File folder : list) {
try {
@@ -141,94 +86,6 @@ public class ToolContribution extends InstalledContribution implements Tool {
}
// /**
// * @return true if a Tool class of the expected name was found in this tool's
// * classpath
// */
// private boolean isValid() {
// return className != null;
// }
// /**
// * Loads the tool, making it impossible (on Windows) to move the files in the
// * classpath without restarting the PDE.
// */
// public void initializeToolClass() throws Exception {
// Class<?> toolClass = Class.forName(className, true, loader);
// tool = (Tool) toolClass.newInstance();
// }
// /**
// * Searches and returns a list of tools found in the immediate children of the
// * given folder.
// * @param doInitializeToolClass
// * true if tools should be initialized before they are returned.
// * Tools that failed to initialize for whatever reason are not
// * returned
// */
// public static ArrayList<ToolContribution> list(File folder, boolean doInitializeToolClass) {
// ArrayList<File> toolsFolders = ToolContribution.discover(folder);
//
// ArrayList<ToolContribution> tools = new ArrayList<ToolContribution>();
// for (File toolFolder : toolsFolders) {
// final ToolContribution tool = ToolContribution.load(toolFolder);
// if (tool != null) {
// try {
// if (doInitializeToolClass) {
// tool.initializeToolClass();
// }
// tools.add(tool);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
// return tools;
// }
// static protected ArrayList<File> discover(File folder) {
// ArrayList<File> tools = new ArrayList<File>();
// discover(folder, tools);
// return tools;
// }
//
//
// static protected void discover(File folder, ArrayList<File> toolFolders) {
// File[] folders = folder.listFiles(new FileFilter() {
// public boolean accept(File folder) {
// if (folder.isDirectory()) {
// //System.out.println("checking " + folder);
// File subfolder = new File(folder, "tool");
// return subfolder.exists();
// }
// return false;
// }
//
//// private boolean toolAlreadyExists(File folder) {
//// boolean exists = true;
//// for (ToolContribution contrib : tools) {
//// if (contrib.getFolder().equals(folder)) {
//// exists = false;
//// }
//// }
//// return exists;
//// }
// });
//
// if (folders != null) {
// for (int i = 0; i < folders.length; i++) {
// Tool tool = ToolContribution.load(folders[i]);
//
// if (tool != null)
// toolFolders.add(folders[i]);
// }
// }
// }
public void init(Editor editor) {
tool.init(editor);
}

View File

@@ -100,7 +100,7 @@ public class JavaMode extends Mode {
public Library getCoreLibrary() {
if (coreLibrary == null) {
File coreFolder = Base.getContentFile("core");
coreLibrary = new Library(coreFolder, null);
coreLibrary = new Library(coreFolder);
}
return coreLibrary;
}