removing library compilations, additional cleanup

This commit is contained in:
Ben Fry
2013-02-16 10:14:09 -05:00
parent 49c6230231
commit 08b2496477
12 changed files with 225 additions and 256 deletions
+29 -25
View File
@@ -365,20 +365,21 @@ public class Base {
libraryManagerFrame = new ContributionManagerDialog("Library Manager",
new ContributionListing.Filter() {
public boolean matches(Contribution contrib) {
return contrib.getType() == Contribution.Type.LIBRARY
|| contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
return contrib.getType() == ContributionType.LIBRARY;
// return contrib.getType() == Contribution.Type.LIBRARY
// || contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
}
});
toolManagerFrame = new ContributionManagerDialog("Tool Manager",
new ContributionListing.Filter() {
public boolean matches(Contribution contrib) {
return contrib.getType() == Contribution.Type.TOOL;
return contrib.getType() == ContributionType.TOOL;
}
});
modeManagerFrame = new ContributionManagerDialog("Mode Manager",
new ContributionListing.Filter() {
public boolean matches(Contribution contrib) {
return contrib.getType() == Contribution.Type.MODE;
return contrib.getType() == ContributionType.MODE;
}
});
updateManagerFrame = new ContributionManagerDialog("Update Manager",
@@ -2465,7 +2466,6 @@ public class Base {
}
/**
* Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #.
@@ -2478,46 +2478,50 @@ public class Base {
}
return outgoing;
}
static public void readSettings(String fileName, String lines[],
HashMap<String, String> exports) {
static public void readSettings(String filename, String lines[],
HashMap<String, String> settings) {
for (int i = 0; i < lines.length; i++) {
int hash = lines[i].indexOf('#');
String line = (hash == -1) ?
String line = (hash == -1) ?
lines[i].trim() : lines[i].substring(0, hash).trim();
if (line.length() == 0) continue;
int equals = line.indexOf('=');
if (equals == -1) {
if (fileName != null)
System.err.println("ignoring illegal line in " + fileName);
System.err.println(" " + line);
continue;
if (line.length() != 0) {
int equals = line.indexOf('=');
if (equals == -1) {
if (filename != null) {
System.err.println("Ignoring illegal line in " + filename);
System.err.println(" " + line);
}
} else {
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
settings.put(attr, valu);
}
}
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
exports.put(attr, valu);
}
}
static public void copyFile(File sourceFile,
File targetFile) throws IOException {
InputStream from =
BufferedInputStream from =
new BufferedInputStream(new FileInputStream(sourceFile));
OutputStream to =
BufferedOutputStream to =
new BufferedOutputStream(new FileOutputStream(targetFile));
byte[] buffer = new byte[16 * 1024];
int bytesRead;
while ((bytesRead = from.read(buffer)) != -1) {
to.write(buffer, 0, bytesRead);
}
to.flush();
from.close(); // ??
from.close();
from = null;
to.close(); // ??
to = null;
to.flush();
to.close();
to = null;
targetFile.setLastModified(sourceFile.lastModified());
}
+8 -3
View File
@@ -416,12 +416,14 @@ public class Library extends InstalledContribution {
}
};
public static ArrayList<File> discover(File folder) {
static public ArrayList<File> discover(File folder) {
ArrayList<File> libraries = new ArrayList<File>();
discover(folder, libraries);
return libraries;
}
static public void discover(File folder, ArrayList<File> libraries) {
String[] list = folder.list(junkFolderFilter);
@@ -456,12 +458,14 @@ public class Library extends InstalledContribution {
}
}
static protected ArrayList<Library> list(File folder) {
ArrayList<Library> libraries = new ArrayList<Library>();
list(folder, libraries);
return libraries;
}
static protected void list(File folder, ArrayList<Library> libraries) {
ArrayList<File> librariesFolders = new ArrayList<File>();
discover(folder, librariesFolders);
@@ -487,7 +491,8 @@ public class Library extends InstalledContribution {
}
}
public Type getType() {
return Type.LIBRARY;
public ContributionType getType() {
return ContributionType.LIBRARY;
}
}
@@ -49,44 +49,7 @@ public interface Contribution {
boolean isInstalled();
Type getType();
ContributionType getType();
String getTypeName();
public static enum Type {
LIBRARY, LIBRARY_COMPILATION, TOOL, MODE;
public String toString() {
switch (this) {
case LIBRARY:
return "library";
case LIBRARY_COMPILATION:
return "compilation";
case TOOL:
return "tool";
case MODE:
return "mode";
}
return "contribution";
};
static public Type toType(String s) {
if (s != null) {
if ("library".equals(s.toLowerCase())) {
return LIBRARY;
}
if ("compilation".equals(s.toLowerCase())) {
return LIBRARY_COMPILATION;
}
if ("tool".equals(s.toLowerCase())) {
return TOOL;
}
if ("mode".equals(s.toLowerCase())) {
return MODE;
}
}
return null;
}
}
}
@@ -31,8 +31,12 @@ import java.util.concurrent.locks.ReentrantLock;
import processing.app.Base;
import processing.core.PApplet;
public class ContributionListing {
public class ContributionListing {
static final String LISTING_URL =
"https://raw.github.com/processing/processing-web/master/contrib_generate/contributions.txt";
File listingFile;
ArrayList<ContributionChangeListener> listeners;
ArrayList<AdvertisedContribution> advertisedContributions;
Map<String, List<Contribution>> librariesByCategory;
@@ -45,15 +49,8 @@ public class ContributionListing {
"I/O", "Math", "Simulation", "Sound", "Utilities", "Typography",
"Video & Vision" };
static Comparator<Contribution> contribComparator = new Comparator<Contribution>() {
public int compare(Contribution o1, Contribution o2) {
return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
}
};
File listingFile;
static ContributionListing singleInstance;
private ContributionListing() {
@@ -72,15 +69,14 @@ public class ContributionListing {
static public ContributionListing getInstance() {
if (singleInstance == null)
if (singleInstance == null) {
singleInstance = new ContributionListing();
}
return singleInstance;
}
void setAdvertisedList(File file) {
listingFile = file;
advertisedContributions.clear();
@@ -90,35 +86,31 @@ public class ContributionListing {
}
Collections.sort(allContributions, contribComparator);
}
public Comparator<? super Contribution> getComparator() {
return contribComparator;
}
/**
* Adds the installed libraries to the listing of libraries, replacing any
* pre-existing libraries by the same name as one in the list.
*/
public void updateInstalledList(List<Contribution> installedContributions) {
for (Contribution contribution : installedContributions) {
Contribution preexistingContribution = getContribution(contribution);
if (preexistingContribution != null) {
replaceContribution(preexistingContribution, contribution);
} else {
addContribution(contribution);
}
}
}
public void replaceContribution(Contribution oldLib, Contribution newLib) {
if (oldLib == null || newLib == null) {
return;
}
@@ -144,21 +136,18 @@ public class ContributionListing {
public void addContribution(Contribution contribution) {
if (librariesByCategory.containsKey(contribution.getCategory())) {
List<Contribution> list = librariesByCategory.get(contribution.getCategory());
list.add(contribution);
Collections.sort(list, contribComparator);
} else {
ArrayList<Contribution> list = new ArrayList<Contribution>();
list.add(contribution);
librariesByCategory.put(contribution.getCategory(), list);
}
allContributions.add(contribution);
notifyAdd(contribution);
Collections.sort(allContributions, contribComparator);
}
@@ -168,7 +157,6 @@ public class ContributionListing {
librariesByCategory.get(info.getCategory()).remove(info);
}
allContributions.remove(info);
notifyRemove(info);
}
@@ -186,18 +174,15 @@ public class ContributionListing {
public AdvertisedContribution getAdvertisedContribution(Contribution info) {
for (AdvertisedContribution advertised : advertisedContributions) {
if (advertised.getType() == info.getType()
&& advertised.getName().equals(info.getName())) {
if (advertised.getType() == info.getType() &&
advertised.getName().equals(info.getName())) {
return advertised;
}
}
return null;
}
public Set<String> getCategories(Filter filter) {
Set<String> outgoing = new HashSet<String>();
@@ -217,10 +202,12 @@ public class ContributionListing {
return outgoing;
}
public List<Contribution> getAllContributions() {
return new ArrayList<Contribution>(allContributions);
}
public List<Contribution> getLibararies(String category) {
ArrayList<Contribution> libinfos =
new ArrayList<Contribution>(librariesByCategory.get(category));
@@ -228,13 +215,13 @@ public class ContributionListing {
return libinfos;
}
public List<Contribution> getFilteredLibraryList(String category, List<String> filters) {
ArrayList<Contribution> filteredList = new ArrayList<Contribution>(allContributions);
Iterator<Contribution> it = filteredList.iterator();
while (it.hasNext()) {
Contribution libInfo = it.next();
if (category != null && !category.equals(libInfo.getCategory())) {
it.remove();
} else {
@@ -245,9 +232,7 @@ public class ContributionListing {
}
}
}
}
return filteredList;
}
@@ -301,18 +286,19 @@ public class ContributionListing {
return contrib.isInstalled();
}
if (property.equals("tool")) {
return contrib.getType() == Contribution.Type.TOOL;
return contrib.getType() == ContributionType.TOOL;
}
if (property.startsWith("lib")) {
return contrib.getType() == Contribution.Type.LIBRARY
|| contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
return contrib.getType() == ContributionType.LIBRARY;
// return contrib.getType() == Contribution.Type.LIBRARY
// || contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
}
if (property.equals("mode")) {
return contrib.getType() == Contribution.Type.MODE;
}
if (property.equals("compilation")) {
return contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
return contrib.getType() == ContributionType.MODE;
}
// if (property.equals("compilation")) {
// return contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
// }
return false;
}
@@ -354,21 +340,20 @@ public class ContributionListing {
}
/**
* Starts a new thread to download the advertised list of contributions. Only
* one instance will run at a time.
* Starts a new thread to download the advertised list of contributions.
* Only one instance will run at a time.
*/
public void getAdvertisedContributions(ProgressMonitor pm) {
final ProgressMonitor progressMonitor = (pm != null) ? pm : new NullProgressMonitor();
final ProgressMonitor progressMonitor =
(pm != null) ? pm : new NullProgressMonitor();
new Thread(new Runnable() {
public void run() {
downloadingListingLock.lock();
URL url = null;
try {
url = new URL("https://raw.github.com/processing/processing-web/master/contrib_generate/contributions.txt");
url = new URL(LISTING_URL);
} catch (MalformedURLException e) {
progressMonitor.error(e);
progressMonitor.finished();
@@ -381,12 +366,12 @@ public class ContributionListing {
setAdvertisedList(listingFile);
}
}
downloadingListingLock.unlock();
}
}).start();
}
public boolean hasUpdates() {
for (Contribution info : allContributions) {
if (hasUpdates(info)) {
@@ -400,29 +385,27 @@ public class ContributionListing {
public boolean hasUpdates(Contribution contribution) {
if (contribution.isInstalled()) {
Contribution advertised = getAdvertisedContribution(contribution);
if (advertised == null)
if (advertised == null) {
return false;
}
return advertised.getVersion() > contribution.getVersion();
}
return false;
}
public boolean hasDownloadedLatestList() {
return hasDownloadedLatestList;
}
public static interface ContributionChangeListener {
public void contributionAdded(Contribution Contribution);
public void contributionRemoved(Contribution Contribution);
public void contributionChanged(Contribution oldLib, Contribution newLib);
}
/**
* @return a lowercase string with all non-alphabetic characters removed
*/
@@ -430,6 +413,7 @@ public class ContributionListing {
return s.toLowerCase().replaceAll("^\\p{Lower}", "");
}
/**
* @return the proper, valid name of this category to be displayed in the UI
* (e.g. "Typography / Geometry"). "Unknown" if the category null.
@@ -438,7 +422,6 @@ public class ContributionListing {
if (category == null) {
return "Unknown";
}
String normCatName = normalize(category);
for (String validCatName : validCategories) {
@@ -447,10 +430,10 @@ public class ContributionListing {
return validCatName;
}
}
return category;
}
public ArrayList<AdvertisedContribution> getLibraries(File f) {
ArrayList<AdvertisedContribution> outgoing = new ArrayList<AdvertisedContribution>();
@@ -459,41 +442,43 @@ public class ContributionListing {
int start = 0;
while (start < lines.length) {
// Only consider 'invalid' lines. These lines contain the type of
// software: library, tool, mode
if (!lines[start].contains("=")) {
String type = lines[start];
// Scan forward for the next blank line
int end = ++start;
while (end < lines.length && !lines[end].equals("")) {
end++;
}
int length = end - start;
String strings[] = new String[length];
System.arraycopy(lines, start, strings, 0, length);
HashMap<String,String> exports = new HashMap<String,String>();
Base.readSettings(null, strings, exports);
Contribution.Type kind = Contribution.Type.toType(type);
outgoing.add(new AdvertisedContribution(kind, exports));
start = end + 1;
} else {
start++;
// // Only consider 'invalid' lines. These lines contain the type of
// // software: library, tool, mode
// if (!lines[start].contains("=")) {
String type = lines[start];
ContributionType contribType = ContributionType.fromName(type);
if (contribType == null) {
System.err.println("Error in contribution listing file on line " + (start+1));
return outgoing;
}
// Scan forward for the next blank line
int end = ++start;
while (end < lines.length && !lines[end].equals("")) {
end++;
}
int length = end - start;
String[] contribLines = new String[length];
System.arraycopy(lines, start, contribLines, 0, length);
HashMap<String,String> contribParams = new HashMap<String,String>();
Base.readSettings(f.getName(), contribLines, contribParams);
outgoing.add(new AdvertisedContribution(contribType, contribParams));
start = end + 1;
// } else {
// start++;
// }
}
}
return outgoing;
}
static class AdvertisedContribution implements Contribution {
protected final String name; // "pdf" or "PDF Export"
protected final Type type; // Library, tool, etc.
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
@@ -503,7 +488,7 @@ public class ContributionListing {
protected final String prettyVersion; // "1.0.2"
protected final String link; // Direct link to download the file
public AdvertisedContribution(Type type, HashMap<String, String> exports) {
public AdvertisedContribution(ContributionType type, HashMap<String, String> exports) {
this.type = type;
name = exports.get("name");
@@ -530,7 +515,7 @@ public class ContributionListing {
return false;
}
public Type getType() {
public ContributionType getType() {
return type;
}
@@ -600,13 +585,20 @@ public class ContributionListing {
}
}
public boolean isDownloadingListing() {
return downloadingListingLock.isLocked();
}
public static interface Filter {
boolean matches(Contribution contrib);
}
static Comparator<Contribution> contribComparator = new Comparator<Contribution>() {
public int compare(Contribution o1, Contribution o2) {
return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
}
};
}
@@ -12,7 +12,6 @@ import processing.app.Base;
import processing.app.Editor;
import processing.app.Library;
import processing.app.Preferences;
import processing.app.contrib.Contribution.Type;
import processing.app.contrib.ContributionListing.AdvertisedContribution;
@@ -137,13 +136,13 @@ public class ContributionManager {
/**
* Used after unpacking a contrib download do determine the file contents.
*/
static List<File> discover(Contribution.Type type, File tempDir) {
static List<File> discover(ContributionType type, File tempDir) {
switch (type) {
case LIBRARY:
return Library.discover(tempDir);
case LIBRARY_COMPILATION:
// XXX Implement
return null;
// case LIBRARY_COMPILATION:
// // XXX Implement
// return null;
case TOOL:
return ToolContribution.discover(tempDir);
case MODE:
@@ -169,10 +168,10 @@ public class ContributionManager {
// }
static File getSketchbookContribFolder(Base base, Type type) {
static File getSketchbookContribFolder(Base base, ContributionType type) {
switch (type) {
case LIBRARY:
case LIBRARY_COMPILATION:
// case LIBRARY_COMPILATION:
return Base.getSketchbookLibrariesFolder();
case TOOL:
return Base.getSketchbookToolsFolder();
@@ -183,12 +182,12 @@ public class ContributionManager {
}
static InstalledContribution create(Base base, File folder, Type type) {
static InstalledContribution create(Base base, File folder, ContributionType type) {
switch (type) {
case LIBRARY:
return new Library(folder);
case LIBRARY_COMPILATION:
return LibraryCompilation.create(folder);
// case LIBRARY_COMPILATION:
// return LibraryCompilation.create(folder);
case TOOL:
return ToolContribution.load(folder);
case MODE:
@@ -198,15 +197,15 @@ public class ContributionManager {
}
static ArrayList<InstalledContribution> getContributions(Type type, Editor editor) {
static ArrayList<InstalledContribution> getContributions(ContributionType type, Editor editor) {
ArrayList<InstalledContribution> contribs = new ArrayList<InstalledContribution>();
switch (type) {
case LIBRARY:
contribs.addAll(editor.getMode().contribLibraries);
break;
case LIBRARY_COMPILATION:
contribs.addAll(LibraryCompilation.list(editor.getMode().contribLibraries));
break;
// case LIBRARY_COMPILATION:
// contribs.addAll(LibraryCompilation.list(editor.getMode().contribLibraries));
// break;
case TOOL:
contribs.addAll(editor.contribTools);
break;
@@ -380,8 +379,8 @@ public class ContributionManager {
case LIBRARY:
errorMsg = "Could not move library \"" + newContrib.getName() + "\" to sketchbook.";
break;
case LIBRARY_COMPILATION:
break;
// case LIBRARY_COMPILATION:
// break;
case TOOL:
errorMsg = "Could not move tool \"" + newContrib.getName() + "\" to sketchbook.";
break;
@@ -441,7 +440,7 @@ public class ContributionManager {
switch (contribution.getType()) {
case LIBRARY:
case LIBRARY_COMPILATION:
// case LIBRARY_COMPILATION:
backupFolder = createLibraryBackupFolder(editor, statusBar);
break;
case MODE:
@@ -643,7 +642,7 @@ public class ContributionManager {
/** Returns true if the type of contribution requires the PDE to restart
* when being removed. */
static public boolean requiresRestart(Contribution contrib) {
return contrib.getType() == Type.TOOL || contrib.getType() == Type.MODE;
return contrib.getType() == ContributionType.TOOL || contrib.getType() == ContributionType.MODE;
}
@@ -306,23 +306,23 @@ public class ContributionManagerDialog {
return;
ArrayList<Library> libraries = new ArrayList<Library>(editor.getMode().contribLibraries);
ArrayList<LibraryCompilation> compilations = LibraryCompilation.list(libraries);
// Remove libraries from the list that are part of a compilations
for (LibraryCompilation compilation : compilations) {
Iterator<Library> it = libraries.iterator();
while (it.hasNext()) {
Library current = it.next();
if (compilation.getFolder().equals(current.getFolder().getParentFile())) {
it.remove();
}
}
}
// ArrayList<LibraryCompilation> compilations = LibraryCompilation.list(libraries);
//
// // Remove libraries from the list that are part of a compilations
// for (LibraryCompilation compilation : compilations) {
// Iterator<Library> it = libraries.iterator();
// while (it.hasNext()) {
// Library current = it.next();
// if (compilation.getFolder().equals(current.getFolder().getParentFile())) {
// it.remove();
// }
// }
// }
ArrayList<Contribution> contributions = new ArrayList<Contribution>();
contributions.addAll(editor.contribTools);
contributions.addAll(libraries);
contributions.addAll(compilations);
// contributions.addAll(compilations);
contribListing.updateInstalledList(contributions);
}
@@ -0,0 +1,60 @@
package processing.app.contrib;
public enum ContributionType {
// LIBRARY, LIBRARY_COMPILATION, TOOL, MODE;
LIBRARY, TOOL, MODE;
public String toString() {
switch (this) {
case LIBRARY:
return "library";
// case LIBRARY_COMPILATION:
// return "compilation";
case TOOL:
return "tool";
case MODE:
return "mode";
}
return null; // should be unreachable
};
public String getFolderName() {
switch (this) {
case LIBRARY:
return "libraries";
// case LIBRARY_COMPILATION:
// return "libraries";
case TOOL:
return "tools";
case MODE:
return "modes";
}
return null; // should be unreachable
}
static public ContributionType fromName(String s) {
if (s != null) {
if ("library".equals(s.toLowerCase())) {
return LIBRARY;
}
// if ("compilation".equals(s.toLowerCase())) {
// return LIBRARY_COMPILATION;
// }
if ("tool".equals(s.toLowerCase())) {
return TOOL;
}
if ("mode".equals(s.toLowerCase())) {
return MODE;
}
}
return null;
}
// static public boolean validName(String s) {
// return "library".equals(s) || "tool".equals(s) || "mode".equals(s);
// }
}
@@ -1,68 +0,0 @@
package processing.app.contrib;
import java.io.*;
import java.util.*;
import processing.app.Library;
public class LibraryCompilation extends InstalledContribution {
ArrayList<Library> libraries;
static String propertiesFileName = "compilation.properties";
private LibraryCompilation(File folder) throws IOException {
super(folder);
libraries = new ArrayList<Library>();
ArrayList<File> librariesFolders = new ArrayList<File>();
Library.discover(folder, librariesFolders);
for (File baseFolder : librariesFolders) {
libraries.add(new Library(baseFolder, name));
}
}
public static ArrayList<LibraryCompilation> list(ArrayList<Library> libraries) {
HashMap<String, File> folderByGroup = new HashMap<String, File>();
// Find each file that is in a group, and record what directory it is in.
// This makes the assumption that all libraries that are grouped are
// contained in the same folder.
for (Library lib : libraries) {
String group = lib.getGroup();
if (group != null) {
folderByGroup.put(group, lib.getFolder().getParentFile());
}
}
ArrayList<LibraryCompilation> compilations = new ArrayList<LibraryCompilation>();
for (File folder : folderByGroup.values()) {
try {
compilations.add(new LibraryCompilation(folder));
} catch (IOException e) {
e.printStackTrace();
}
}
return compilations;
}
public static LibraryCompilation create(File folder) {
try {
LibraryCompilation compilation = new LibraryCompilation(folder);
if (compilation.libraries.isEmpty()) {
return null;
}
return compilation;
} catch (IOException e) {
}
return null;
}
public Type getType() {
return Type.LIBRARY_COMPILATION;
}
}
@@ -179,8 +179,8 @@ public class ModeContribution extends InstalledContribution {
}
public Type getType() {
return Type.MODE;
public ContributionType getType() {
return ContributionType.MODE;
}
@@ -244,7 +244,7 @@ public class ToolContribution extends InstalledContribution implements Tool {
}
public Type getType() {
return Type.TOOL;
public ContributionType getType() {
return ContributionType.TOOL;
}
}
+1 -2
View File
@@ -150,6 +150,7 @@ o Dict and List could be interfaces?
_ JSONObject.has(key) vs XML.hasAttribute(attr) vs HashMap.containsKey()
_ and how it should be handled with hash/dict
_ right now using hasKey().. in JSONObject
_ add() to add things to lists, sum() for the math (sum is used less after all)
_ add mouse wheel support to 2.0 event system
_ http://code.google.com/p/processing/issues/detail?id=1423
@@ -389,8 +390,6 @@ _ y2 position of rectangles not same as y2 position of lines
_ happens when the rectangle is flipped on the x or y axis
_ probably a hack that draws the "last" point differently
_ add() to add things to lists, sum() for the math (sum is used less after all)
_ add inputPath() and outputPath() -> sketch folder or sd card
_ or should this just be a change to sketchPath() on Android?
_ also because input/output won't be different (since not data folder)
+15
View File
@@ -92,6 +92,11 @@ o if sketch was open, then restart by dragging the .pde to p5.app
https://processing-js.lighthouseapp.com/
library changes
_ remove netscape.javascript stuff
_ move minim out to its own contrib section
_ move arduino out to its own library
_ add Iterator as an import?
_ remove sketch.properties when moving back to the default?
@@ -110,6 +115,7 @@ _ boogers still being left around
_ Add Mode is also reporting that it's a library that contains multiple
_ Add Tool is having problems
_ http://code.google.com/p/processing/issues/detail?id=1569
_ https://github.com/processing/processing/issues/1607
_ make already installed libraries distinguishable in the list
_ http://code.google.com/p/processing/issues/detail?id=1212
_ excessive CPU usage of PDE after using library manager
@@ -128,6 +134,9 @@ _ and the rest would happen automatically.
_ alternating blue/white backgrounds aren't updated after changing filter
_ remove PdeKeyListener, roll it into the Java InputHandler for JEditTextArea
_ move Java-specific InputHandler to its own subclass
_ ExceptionInitializerError on startup in ContributionListing, line 50
_ https://github.com/processing/processing/issues/1601
_ problem is a proxy server requirement
2.0 FINAL / new interface
@@ -265,6 +274,12 @@ _ temporary files (for sketches and logs) are not deleted
_ http://code.google.com/p/processing/issues/detail?id=562
_ proxy server requirement causes problems
_ contrib manager, update checks are broken
_ https://github.com/processing/processing/issues/1476
X http://code.google.com/p/processing/issues/detail?id=1438
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .