diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java index b30723682..046c49678 100644 --- a/app/src/processing/app/contrib/AvailableContribution.java +++ b/app/src/processing/app/contrib/AvailableContribution.java @@ -41,7 +41,8 @@ class AvailableContribution extends Contribution { this.type = type; this.link = params.get("download"); - category = ContributionListing.getCategory(params.get("category")); + //category = ContributionListing.getCategory(params.get("category")); + categories = parseCategories(params.get("category")); name = params.get("name"); authorList = params.get("authorList"); url = params.get("url"); @@ -65,12 +66,11 @@ class AvailableContribution extends Contribution { // 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 = type.getSketchbookFolder(); +// File sketchbookContribFolder = type.getSketchbookFolder(); File tempFolder = null; try { - tempFolder = - Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder); + tempFolder = type.createTempFolder(); } catch (IOException e) { status.setErrorMessage("Could not create a temporary folder to install."); return null; @@ -183,7 +183,7 @@ class AvailableContribution extends Contribution { PrintWriter writer = PApplet.createWriter(propFile); writer.println("name=" + getName()); - writer.println("category=" + getCategory()); + writer.println("category=" + getCategoryStr()); writer.println("authorList=" + getAuthorList()); writer.println("url=" + getUrl()); writer.println("sentence=" + getSentence()); diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java index 759b85537..e09098add 100644 --- a/app/src/processing/app/contrib/Contribution.java +++ b/app/src/processing/app/contrib/Contribution.java @@ -21,9 +21,21 @@ */ package processing.app.contrib; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import processing.core.PApplet; + abstract public class Contribution { - protected String category; // "Sound" + static final List validCategories = + Arrays.asList("3D", "Animation", "Data", "Geometry", "GUI", "Hardware", + "I/O", "Math", "Simulation", "Sound", "Typography", + "Utilities", "Video & Vision", "Other"); + + //protected String category; // "Sound" + protected List categories; // "Sound", "Typography" protected String name; // "pdf" or "PDF Export" protected String authorList; // Ben Fry protected String url; // http://processing.org @@ -34,8 +46,37 @@ abstract public class Contribution { // "Sound" - public String getCategory() { - return category; +// public String getCategory() { +// return category; +// } + + + // "Sound", "Utilities"... see valid list in ContributionListing + protected List getCategories() { + return categories; + } + + + protected String getCategoryStr() { + StringBuilder sb = new StringBuilder(); + for (String category : categories) { + sb.append(category); + sb.append(','); + } + sb.deleteCharAt(sb.length()-1); // delete last comma + return sb.toString(); + } + + + protected boolean hasCategory(String category) { + if (category != null) { + for (String c : categories) { + if (category.equalsIgnoreCase(c)) { + return true; + } + } + } + return false; } @@ -105,4 +146,26 @@ abstract public class Contribution { boolean isDeletionFlagged() { return false; } + + + /** + * @return the list of categories that this contribution is part of + * (e.g. "Typography / Geometry"). "Unknown" if the category null. + */ + static public List parseCategories(String categoryStr) { + List outgoing = new ArrayList(); + + if (categoryStr != null) { + String[] listing = PApplet.trim(PApplet.split(categoryStr, ',')); + for (String category : listing) { + if (validCategories.contains(category)) { + outgoing.add(category); + } + } + } + if (outgoing.size() == 0) { + outgoing.add("Unknown"); + } + return outgoing; + } } diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index f9e211a8c..149cb3fdc 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -31,8 +31,9 @@ import processing.core.PApplet; public class ContributionListing { + // Stable URL that will redirect to wherever we're hosting the file static final String LISTING_URL = - "http://processing.org/contrib_generate/contributions.txt"; + "http://download.processing.org/contributions.txt"; static ContributionListing singleInstance; @@ -44,12 +45,6 @@ public class ContributionListing { boolean hasDownloadedLatestList; ReentrantLock downloadingListingLock; - static final String[] validCategories = { - "3D", "Animation", "Compilations", "Data", "Geometry", "GUI", - "Hardware", "I/O", "Math", "Simulation", "Sound", "Typography", - "Utilities", "Video & Vision" - }; - private ContributionListing() { listeners = new ArrayList(); @@ -103,53 +98,57 @@ public class ContributionListing { protected void replaceContribution(Contribution oldLib, Contribution newLib) { - if (oldLib == null || newLib == null) { - return; - } + if (oldLib != null && newLib != null) { + for (String category : oldLib.getCategories()) { + if (librariesByCategory.containsKey(category)) { + List list = librariesByCategory.get(category); - if (librariesByCategory.containsKey(oldLib.getCategory())) { - List list = librariesByCategory.get(oldLib.getCategory()); - - for (int i = 0; i < list.size(); i++) { - if (list.get(i) == oldLib) { - list.set(i, newLib); + for (int i = 0; i < list.size(); i++) { + if (list.get(i) == oldLib) { + list.set(i, newLib); + } + } } } - } - for (int i = 0; i < allContributions.size(); i++) { - if (allContributions.get(i) == oldLib) { - allContributions.set(i, newLib); + for (int i = 0; i < allContributions.size(); i++) { + if (allContributions.get(i) == oldLib) { + allContributions.set(i, newLib); + } } - } - notifyChange(oldLib, newLib); + notifyChange(oldLib, newLib); + } } private void addContribution(Contribution contribution) { - if (librariesByCategory.containsKey(contribution.getCategory())) { - List list = librariesByCategory.get(contribution.getCategory()); - list.add(contribution); - Collections.sort(list, nameComparator); + for (String category : contribution.getCategories()) { + if (librariesByCategory.containsKey(category)) { + List list = librariesByCategory.get(category); + list.add(contribution); + Collections.sort(list, nameComparator); - } else { - ArrayList list = new ArrayList(); - list.add(contribution); - librariesByCategory.put(contribution.getCategory(), list); + } else { + ArrayList list = new ArrayList(); + list.add(contribution); + librariesByCategory.put(category, list); + } + allContributions.add(contribution); + notifyAdd(contribution); + Collections.sort(allContributions, nameComparator); } - allContributions.add(contribution); - notifyAdd(contribution); - Collections.sort(allContributions, nameComparator); } - protected void removeContribution(Contribution info) { - if (librariesByCategory.containsKey(info.getCategory())) { - librariesByCategory.get(info.getCategory()).remove(info); + protected void removeContribution(Contribution contribution) { + for (String category : contribution.getCategories()) { + if (librariesByCategory.containsKey(category)) { + librariesByCategory.get(category).remove(contribution); + } } - allContributions.remove(info); - notifyRemove(info); + allContributions.remove(contribution); + notifyRemove(contribution); } @@ -209,12 +208,14 @@ public class ContributionListing { protected List getFilteredLibraryList(String category, List filters) { - ArrayList filteredList = new ArrayList(allContributions); + ArrayList filteredList = + new ArrayList(allContributions); Iterator it = filteredList.iterator(); while (it.hasNext()) { Contribution libInfo = it.next(); - if (category != null && !category.equals(libInfo.getCategory())) { + //if (category != null && !category.equals(libInfo.getCategory())) { + if (category != null && !libInfo.hasCategory(category)) { it.remove(); } else { for (String filter : filters) { @@ -254,7 +255,7 @@ public class ContributionListing { return contrib.getAuthorList() != null && contrib.getAuthorList().toLowerCase().matches(filter) || contrib.getSentence() != null && contrib.getSentence().toLowerCase().matches(filter) || contrib.getParagraph() != null && contrib.getParagraph().toLowerCase().matches(filter) - || contrib.getCategory() != null && contrib.getCategory().toLowerCase().matches(filter) + || contrib.hasCategory(filter) || contrib.getName() != null && contrib.getName().toLowerCase().matches(filter); } @@ -396,39 +397,39 @@ public class ContributionListing { } - /** - * @return a lowercase string with all non-alphabetic characters removed - */ - static protected String normalize(String s) { - return s.toLowerCase().replaceAll("^\\p{Lower}", ""); - } +// /** +// * @return a lowercase string with all non-alphabetic characters removed +// */ +// static protected String normalize(String s) { +// 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. - */ - static public String getCategory(String category) { - if (category == null) { - return "Unknown"; - } - String normCatName = normalize(category); - - for (String validCatName : validCategories) { - String normValidCatName = normalize(validCatName); - if (normValidCatName.equals(normCatName)) { - return validCatName; - } - } - return category; - } + +// /** +// * @return the proper, valid name of this category to be displayed in the UI +// * (e.g. "Typography / Geometry"). "Unknown" if the category null. +// */ +// static public String getCategory(String category) { +// if (category == null) { +// return "Unknown"; +// } +// String normCatName = normalize(category); +// +// for (String validCatName : validCategories) { +// String normValidCatName = normalize(validCatName); +// if (normValidCatName.equals(normCatName)) { +// return validCatName; +// } +// } +// return category; +// } ArrayList parseContribList(File file) { ArrayList outgoing = new ArrayList(); if (file != null && file.exists()) { - String lines[] = PApplet.loadStrings(file); + String[] lines = PApplet.loadStrings(file); int start = 0; while (start < lines.length) { diff --git a/app/src/processing/app/contrib/ContributionType.java b/app/src/processing/app/contrib/ContributionType.java index 4c3b69fee..a2a943665 100644 --- a/app/src/processing/app/contrib/ContributionType.java +++ b/app/src/processing/app/contrib/ContributionType.java @@ -23,6 +23,7 @@ package processing.app.contrib; import java.io.File; import java.io.FileFilter; +import java.io.IOException; import java.util.ArrayList; import processing.app.Base; @@ -30,7 +31,6 @@ import processing.app.Editor; import processing.app.Library; public enum ContributionType { -// LIBRARY, LIBRARY_COMPILATION, TOOL, MODE; LIBRARY, TOOL, MODE; @@ -38,8 +38,6 @@ public enum ContributionType { switch (this) { case LIBRARY: return "library"; -// case LIBRARY_COMPILATION: -// return "compilation"; case TOOL: return "tool"; case MODE: @@ -49,7 +47,10 @@ public enum ContributionType { }; - /** Return Mode for mode, Tool for tool, etc. */ + /** + * Get this type name as a purtied up, capitalized version. + * @return Mode for mode, Tool for tool, etc. + */ public String getTitle() { String s = toString(); return Character.toUpperCase(s.charAt(0)) + s.substring(1); @@ -60,8 +61,6 @@ public enum ContributionType { switch (this) { case LIBRARY: return "libraries"; -// case LIBRARY_COMPILATION: -// return "libraries"; case TOOL: return "tools"; case MODE: @@ -69,6 +68,26 @@ public enum ContributionType { } return null; // should be unreachable } + + + public File createTempFolder() throws IOException { + return Base.createTempFolder(toString(), "tmp", getSketchbookFolder()); + } + + + public boolean isTempFolderName(String name) { + return name.startsWith(toString()) && name.endsWith("tmp"); + } + + +// public String getTempPrefix() { +// return toString(); +// } +// +// +// public String getTempSuffix() { +// return "tmp"; +// } // public String getPropertiesName() { @@ -78,16 +97,13 @@ public enum ContributionType { static public ContributionType fromName(String s) { if (s != null) { - if ("library".equals(s.toLowerCase())) { + if ("library".equalsIgnoreCase(s)) { return LIBRARY; } -// if ("compilation".equals(s.toLowerCase())) { -// return LIBRARY_COMPILATION; -// } - if ("tool".equals(s.toLowerCase())) { + if ("tool".equalsIgnoreCase(s)) { return TOOL; } - if ("mode".equals(s.toLowerCase())) { + if ("mode".equalsIgnoreCase(s)) { return MODE; } } @@ -109,7 +125,9 @@ public enum ContributionType { boolean isCandidate(File potential) { - return (potential.isDirectory() && new File(potential, toString()).exists()); + return (potential.isDirectory() && + new File(potential, toString()).exists() && + !isTempFolderName(potential.getName())); } @@ -148,7 +166,8 @@ public enum ContributionType { LocalContribution load(Base base, File folder) { switch (this) { case LIBRARY: - return new Library(folder); + //return new Library(folder); + return Library.load(folder); case TOOL: return ToolContribution.load(folder); case MODE: diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java index 7bf2878aa..20595a7ba 100644 --- a/app/src/processing/app/contrib/LocalContribution.java +++ b/app/src/processing/app/contrib/LocalContribution.java @@ -57,7 +57,7 @@ public abstract class LocalContribution extends Contribution { name = properties.get("name"); id = properties.get("id"); - category = ContributionListing.getCategory(properties.get("category")); + categories = parseCategories(properties.get("category")); if (name == null) { name = folder.getName(); } @@ -71,7 +71,6 @@ public abstract class LocalContribution extends Contribution { } 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."); - //e.printStackTrace(); } prettyVersion = properties.get("prettyVersion"); @@ -185,8 +184,8 @@ public abstract class LocalContribution extends Contribution { LocalContribution copyAndLoad(Editor editor, - boolean confirmReplace, - StatusPanel status) { + boolean confirmReplace, + StatusPanel status) { ArrayList oldContribs = getType().listContributions(editor); @@ -283,7 +282,7 @@ public abstract class LocalContribution extends Contribution { if (backupFolder != null) { String libFolderName = getFolder().getName(); String prefix = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); - final String backupName = prefix + "_" + libFolderName; + final String backupName = prefix + " " + libFolderName; File backupSubFolder = ContributionManager.getUniqueName(backupFolder, backupName); if (deleteOriginal) { @@ -505,7 +504,7 @@ public abstract class LocalContribution extends Contribution { } - class IgnorableException extends Exception { + static protected class IgnorableException extends Exception { public IgnorableException(String msg) { super(msg); } diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java index 44290d006..a55e2f1d8 100644 --- a/app/src/processing/app/contrib/ModeContribution.java +++ b/app/src/processing/app/contrib/ModeContribution.java @@ -94,13 +94,13 @@ public class ModeContribution extends LocalContribution { File[] potential = ContributionType.MODE.listCandidates(modesFolder); 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(); - } + try { + contribModes.add(new ModeContribution(base, folder, null)); + } catch (IgnorableException ig) { + Base.log(ig.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + } } } }