mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Merge branch 'master' of github.com:processing/processing
This commit is contained in:
@@ -33,7 +33,7 @@ import processing.core.PApplet;
|
||||
/**
|
||||
* A class to hold information about a Contribution that can be downloaded.
|
||||
*/
|
||||
class AvailableContribution extends Contribution {
|
||||
public class AvailableContribution extends Contribution {
|
||||
protected final ContributionType type; // Library, tool, etc.
|
||||
protected final String link; // Direct link to download the file
|
||||
|
||||
@@ -44,6 +44,7 @@ class AvailableContribution extends Contribution {
|
||||
|
||||
//category = ContributionListing.getCategory(params.get("category"));
|
||||
categories = parseCategories(params.get("category"));
|
||||
specifiedImports = parseImports(params.get("imports"));
|
||||
name = params.get("name");
|
||||
authorList = params.get("authorList");
|
||||
url = params.get("url");
|
||||
@@ -251,6 +252,20 @@ class AvailableContribution extends Contribution {
|
||||
category = sb.toString();
|
||||
}
|
||||
|
||||
String specifiedImport = "";
|
||||
List<String> importsList = parseImports(properties.get("imports"));
|
||||
if (importsList == null || importsList.isEmpty()) {
|
||||
specifiedImport = getImportStr();
|
||||
} else {
|
||||
StringBuilder sbImport = new StringBuilder();
|
||||
for (String it : specifiedImports) {
|
||||
sbImport.append(it);
|
||||
sbImport.append(',');
|
||||
}
|
||||
sbImport.deleteCharAt(sbImport.length() - 1);
|
||||
specifiedImport = sbImport.toString();
|
||||
}
|
||||
|
||||
String authorList = properties.get("authorList");
|
||||
if (authorList == null || authorList.isEmpty()) {
|
||||
authorList = getAuthorList();
|
||||
@@ -336,6 +351,9 @@ class AvailableContribution extends Contribution {
|
||||
writer.println("lastUpdated=" + lastUpdated);
|
||||
writer.println("minRevision=" + minRev);
|
||||
writer.println("maxRevision=" + maxRev);
|
||||
if (getType() == ContributionType.LIBRARY) {
|
||||
writer.println("imports=" + specifiedImport);
|
||||
}
|
||||
if (getType() == ContributionType.EXAMPLES) {
|
||||
writer.println("compatibleModesList=" + compatibleContribsList);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ abstract public class Contribution {
|
||||
protected long lastUpdated; // 1402805757
|
||||
protected int minRevision; // 0
|
||||
protected int maxRevision; // 227
|
||||
protected List<String> specifiedImports; // pdf.export.*,pdf.convert.common.*
|
||||
|
||||
|
||||
// "Sound"
|
||||
@@ -81,6 +82,37 @@ abstract public class Contribution {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// pdf.export.*,pdf.convert.common.*
|
||||
protected List<String> getImports() {
|
||||
return specifiedImports;
|
||||
}
|
||||
|
||||
|
||||
protected String getImportStr() {
|
||||
if (specifiedImports == null || specifiedImports.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String importName : specifiedImports) {
|
||||
sb.append(importName);
|
||||
sb.append(',');
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1); // delete last comma
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected boolean hasImport(String importName) {
|
||||
if (specifiedImports != null && importName != null) {
|
||||
for (String c : specifiedImports) {
|
||||
if (importName.equalsIgnoreCase(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,4 +260,20 @@ abstract public class Contribution {
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the list of imports that this contribution (library) contains.
|
||||
*/
|
||||
static List<String> parseImports(String importStr) {
|
||||
List<String> outgoing = new ArrayList<String>();
|
||||
|
||||
if (importStr != null) {
|
||||
String[] importList = PApplet.trim(PApplet.split(importStr, ','));
|
||||
for (String importName : importList) {
|
||||
outgoing.add(importName);
|
||||
}
|
||||
}
|
||||
return (outgoing.size() > 0) ? outgoing : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class ContributionListing {
|
||||
ArrayList<ContributionChangeListener> listeners;
|
||||
ArrayList<AvailableContribution> advertisedContributions;
|
||||
Map<String, List<Contribution>> librariesByCategory;
|
||||
public Map<String, Contribution> librariesByImportHeader;
|
||||
ArrayList<Contribution> allContributions;
|
||||
boolean hasDownloadedLatestList;
|
||||
boolean hasListDownloadFailed;
|
||||
@@ -53,6 +54,7 @@ public class ContributionListing {
|
||||
listeners = new ArrayList<ContributionChangeListener>();
|
||||
advertisedContributions = new ArrayList<AvailableContribution>();
|
||||
librariesByCategory = new HashMap<String, List<Contribution>>();
|
||||
librariesByImportHeader = new HashMap<String, Contribution>();
|
||||
allContributions = new ArrayList<Contribution>();
|
||||
downloadingListingLock = new ReentrantLock();
|
||||
|
||||
@@ -64,7 +66,7 @@ public class ContributionListing {
|
||||
}
|
||||
|
||||
|
||||
static ContributionListing getInstance() {
|
||||
public static ContributionListing getInstance() {
|
||||
if (singleInstance == null) {
|
||||
synchronized (ContributionListing.class) {
|
||||
if (singleInstance == null) {
|
||||
@@ -119,6 +121,12 @@ public class ContributionListing {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldLib.getImports() != null) {
|
||||
for (String importName : oldLib.getImports()) {
|
||||
librariesByImportHeader.replace(importName, newLib);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < allContributions.size(); i++) {
|
||||
if (allContributions.get(i) == oldLib) {
|
||||
allContributions.set(i, newLib);
|
||||
@@ -131,6 +139,11 @@ public class ContributionListing {
|
||||
|
||||
|
||||
private void addContribution(Contribution contribution) {
|
||||
if (contribution.getImports() != null) {
|
||||
for (String importName : contribution.getImports()) {
|
||||
librariesByImportHeader.put(importName, contribution);
|
||||
}
|
||||
}
|
||||
for (String category : contribution.getCategories()) {
|
||||
if (librariesByCategory.containsKey(category)) {
|
||||
List<Contribution> list = librariesByCategory.get(category);
|
||||
@@ -155,6 +168,11 @@ public class ContributionListing {
|
||||
librariesByCategory.get(category).remove(contribution);
|
||||
}
|
||||
}
|
||||
if (contribution.getImports() != null) {
|
||||
for (String importName : contribution.getImports()) {
|
||||
librariesByImportHeader.remove(importName);
|
||||
}
|
||||
}
|
||||
allContributions.remove(contribution);
|
||||
notifyRemove(contribution);
|
||||
}
|
||||
|
||||
@@ -110,8 +110,9 @@ public class ContributionManager {
|
||||
// Hiding stack trace. An error has been shown where needed.
|
||||
// ioe.printStackTrace();
|
||||
}
|
||||
if (progress != null)
|
||||
if (progress != null) {
|
||||
progress.finished();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -154,8 +155,9 @@ public class ContributionManager {
|
||||
contribListing.replaceContribution(ad, contribution);
|
||||
if (contribution.getType() == ContributionType.MODE) {
|
||||
ArrayList<ModeContribution> contribModes = editor.getBase().getModeContribs();
|
||||
if (!contribModes.contains(contribution))
|
||||
if (!contribModes.contains(contribution)) {
|
||||
contribModes.add((ModeContribution) contribution);
|
||||
}
|
||||
}
|
||||
refreshInstalled(editor);
|
||||
}
|
||||
@@ -197,7 +199,10 @@ public class ContributionManager {
|
||||
|
||||
/**
|
||||
* Non-blocking call to download and install a contribution in a new thread.
|
||||
*
|
||||
* Used when information about the progress of the download and install
|
||||
* procedure is not of importance, such as if a contribution has to be
|
||||
* installed at startup time.
|
||||
*
|
||||
* @param url
|
||||
* Direct link to the contribution.
|
||||
* @param ad
|
||||
@@ -229,8 +234,9 @@ public class ContributionManager {
|
||||
contribModes.add((ModeContribution) contribution);
|
||||
}
|
||||
}
|
||||
if (base.getActiveEditor() != null)
|
||||
if (base.getActiveEditor() != null) {
|
||||
refreshInstalled(base.getActiveEditor());
|
||||
}
|
||||
}
|
||||
|
||||
contribZip.delete();
|
||||
@@ -240,13 +246,12 @@ public class ContributionManager {
|
||||
} catch (Exception e) {
|
||||
// Chuck the stack trace. The user might have no idea why it is appearing, or what (s)he did wrong...
|
||||
// e.printStackTrace();
|
||||
System.out.println("Error during download and install of "
|
||||
+ ad.getName());
|
||||
String arg = "contrib.startup.errors.download_install";
|
||||
System.err.println(Language.interpolate(arg, ad.getName()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err
|
||||
.println("Could not write to temporary directory during download and install of "
|
||||
+ ad.getName());
|
||||
String arg = "contrib.startup.errors.temp_dir";
|
||||
System.err.println(Language.interpolate(arg, ad.getName()));
|
||||
}
|
||||
}
|
||||
}, "Contribution Installer").start();
|
||||
@@ -285,13 +290,112 @@ public class ContributionManager {
|
||||
} catch (IOException e) {
|
||||
// Again, forget about the stack trace. The user ain't done wrong
|
||||
// e.printStackTrace();
|
||||
System.err.println("The unupdated contribution marker seems to not like "
|
||||
+ ac.getName() + ". You may have to install it manually to update...");
|
||||
String arg = "contrib.startup.errors.new_marker";
|
||||
System.err.println(Language.interpolate(arg, ac.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Blocking call to download and install a set of libraries. Used when a list
|
||||
* of libraries have to be installed while forcing the user to not modify
|
||||
* anything and providing feedback via the console status area, such as when
|
||||
* the user tries to run a sketch that imports uninstaled libraries.
|
||||
*
|
||||
* @param aList
|
||||
* The list of AvailableContributions to be downloaded and installed.
|
||||
*/
|
||||
public static void downloadAndInstallOnImport(final Base base,
|
||||
final ArrayList<AvailableContribution> aList) {
|
||||
|
||||
// To avoid the user from modifying stuff, since this function is only called
|
||||
// during pre-processing
|
||||
base.getActiveEditor().getTextArea().setEditable(false);
|
||||
base.getActiveEditor().getConsole().clear();
|
||||
|
||||
ArrayList<String> installedLibList = new ArrayList<String>();
|
||||
|
||||
// boolean variable to check if previous lib was installed successfully,
|
||||
// to give the user an idea about progress being made.
|
||||
boolean isPrevDone = false;
|
||||
|
||||
for (AvailableContribution ad : aList) {
|
||||
if (ad.getType() != ContributionType.LIBRARY) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
URL url = new URL(ad.link);
|
||||
String filename = url.getFile();
|
||||
filename = filename.substring(filename.lastIndexOf('/') + 1);
|
||||
try {
|
||||
|
||||
File contribZip = File.createTempFile("download", filename);
|
||||
contribZip.setWritable(true);
|
||||
|
||||
try {
|
||||
// Use the console to let the user know what's happening
|
||||
// The slightly complex if-else is required to let the user know when
|
||||
// one install is completed and the next download has begun without
|
||||
// interfereing with occur status messages that may arise in the meanwhile
|
||||
String statusMsg = base.getActiveEditor().getStatusMessage();
|
||||
if (isPrevDone) {
|
||||
String status = statusMsg + " "
|
||||
+ Language.interpolate("contrib.import.progress.download", ad.name);
|
||||
base.getActiveEditor().statusNotice(status);
|
||||
}
|
||||
else {
|
||||
String arg = "contrib.import.progress.download";
|
||||
String status = Language.interpolate(arg, ad.name);
|
||||
base.getActiveEditor().statusNotice(status);
|
||||
}
|
||||
|
||||
isPrevDone = false;
|
||||
|
||||
download(url, contribZip, null);
|
||||
|
||||
String arg = "contrib.import.progress.install";
|
||||
base.getActiveEditor().statusNotice(Language.interpolate(arg,ad.name));
|
||||
LocalContribution contribution = ad.install(base, contribZip,
|
||||
false, null);
|
||||
|
||||
if (contribution != null) {
|
||||
contribListing.replaceContribution(ad, contribution);
|
||||
if (base.getActiveEditor() != null) {
|
||||
refreshInstalled(base.getActiveEditor());
|
||||
}
|
||||
}
|
||||
|
||||
contribZip.delete();
|
||||
|
||||
installedLibList.add(ad.name);
|
||||
isPrevDone = true;
|
||||
|
||||
arg = "contrib.import.progress.done";
|
||||
base.getActiveEditor().statusNotice(Language.interpolate(arg,ad.name));
|
||||
|
||||
} catch (Exception e) {
|
||||
String arg = "contrib.startup.errors.download_install";
|
||||
System.err.println(Language.interpolate(arg, ad.getName()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
String arg = "contrib.startup.errors.temp_dir";
|
||||
System.err.println(Language.interpolate(arg,ad.getName()));
|
||||
}
|
||||
} catch (MalformedURLException e1) {
|
||||
System.err.println(Language.interpolate("contrib.import.errors.link",
|
||||
ad.getName()));
|
||||
}
|
||||
}
|
||||
base.getActiveEditor().getTextArea().setEditable(true);
|
||||
base.getActiveEditor().statusEmpty();
|
||||
System.out.println(Language.text("contrib.import.progress.final_list"));
|
||||
for (String l : installedLibList) {
|
||||
System.out.println(" * " + l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public void refreshInstalled(Editor e) {
|
||||
|
||||
Iterator<Editor> iter = e.getBase().getEditors().iterator();
|
||||
|
||||
@@ -48,7 +48,6 @@ public abstract class LocalContribution extends Contribution {
|
||||
protected File folder;
|
||||
protected Map<String, String> properties;
|
||||
protected ClassLoader loader;
|
||||
protected List<String> specifiedImports; // mylib,mylib.util;
|
||||
|
||||
public LocalContribution(File folder) {
|
||||
this.folder = folder;
|
||||
|
||||
@@ -338,8 +338,9 @@ delete.messages.is_read_only.description = Some files are marked \"read-only\",
|
||||
|
||||
|
||||
# ---------------------------------------
|
||||
# Contribution Panel
|
||||
# Contributions
|
||||
|
||||
# Contribution Panel
|
||||
contrib = Contribution Manager
|
||||
contrib.manager_title.update = Update Manager
|
||||
contrib.manager_title.mode = Mode Manager
|
||||
@@ -384,6 +385,20 @@ contrib.progress.downloading = Downloading
|
||||
contrib.download_error = An error occured while downloading the contribution.
|
||||
contrib.unsupported_operating_system = Your operating system does not appear to be supported. You should visit the %s\'s library for more info.
|
||||
|
||||
# Install on Startup
|
||||
contrib.startup.errors.download_install = Error during download and install of %s
|
||||
contrib.startup.errors.temp_dir = Could not write to temporary directory during download and install of %s
|
||||
contrib.startup.errors.new_marker = The unupdated contribution marker seems to not like %s. You may have to install it manually to update...
|
||||
|
||||
# Install on Import
|
||||
contrib.import.dialog.title = Missing Libraries Available
|
||||
contrib.import.dialog.primary_text = The following imported libraries are available for download, but have not been installed.
|
||||
contrib.import.dialog.secondary_text = Would you like to install them now?
|
||||
contrib.import.progress.download = Downloading %s...
|
||||
contrib.import.progress.install = Installing %s...
|
||||
contrib.import.progress.done = %s has been installed.
|
||||
contrib.import.progress.final_list = The following libraries have been installed:
|
||||
contrib.import.errors.link = Error: The library %s has a strange looking download link.
|
||||
|
||||
# ---------------------------------------
|
||||
# Warnings
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -22,6 +23,10 @@ import org.eclipse.jdt.core.compiler.IProblem;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.Toolkit;
|
||||
import processing.app.contrib.AvailableContribution;
|
||||
import processing.app.contrib.Contribution;
|
||||
import processing.app.contrib.ContributionListing;
|
||||
import processing.app.contrib.ContributionManager;
|
||||
import processing.app.contrib.ToolContribution;
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
import processing.app.syntax.PdeTextAreaDefaults;
|
||||
@@ -32,6 +37,7 @@ import processing.mode.java.debug.LineID;
|
||||
import processing.mode.java.pdex.ErrorCheckerService;
|
||||
import processing.mode.java.pdex.ErrorMarker;
|
||||
import processing.mode.java.pdex.ErrorMessageSimplifier;
|
||||
import processing.mode.java.pdex.ImportStatement;
|
||||
import processing.mode.java.pdex.JavaTextArea;
|
||||
import processing.mode.java.pdex.Problem;
|
||||
import processing.mode.java.pdex.XQConsoleToggle;
|
||||
@@ -1845,8 +1851,93 @@ public class JavaEditor extends Editor {
|
||||
public void prepareRun() {
|
||||
autoSave();
|
||||
super.prepareRun();
|
||||
downloadImports();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Downloads libraries that have been imported, that aren't available as a
|
||||
* LocalContribution, but that have an AvailableContribution associated with
|
||||
* them.
|
||||
*/
|
||||
protected void downloadImports() {
|
||||
String importRegex = errorCheckerService.importRegexp;
|
||||
String tabCode;
|
||||
for (SketchCode sc : sketch.getCode()) {
|
||||
if (sc.isExtension("pde")) {
|
||||
tabCode = sc.getProgram();
|
||||
|
||||
String[][] pieces = PApplet.matchAll(tabCode, importRegex);
|
||||
|
||||
if (pieces != null) {
|
||||
ArrayList<String> importHeaders = new ArrayList<String>();
|
||||
for (String[] importStatement : pieces) {
|
||||
importHeaders.add(importStatement[2]);
|
||||
}
|
||||
ArrayList<AvailableContribution> installLibsHeaders = getNotInstalledAvailableLibs(importHeaders);
|
||||
if (!installLibsHeaders.isEmpty()) {
|
||||
StringBuilder libList = new StringBuilder("Would you like to install them now?");
|
||||
for (AvailableContribution ac : installLibsHeaders) {
|
||||
libList.append("\n • " + ac.getName());
|
||||
}
|
||||
int option = Base.showYesNoQuestion(this,
|
||||
Language.text("contrib.import.dialog.title"),
|
||||
Language.text("contrib.import.dialog.primary_text"),
|
||||
libList.toString());
|
||||
|
||||
if (option == JOptionPane.YES_OPTION) {
|
||||
ContributionManager.downloadAndInstallOnImport(base,
|
||||
installLibsHeaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of AvailableContributions of those libraries that the user
|
||||
* wants imported, but that are not installed.
|
||||
*
|
||||
* @param importHeaders
|
||||
*/
|
||||
private ArrayList<AvailableContribution> getNotInstalledAvailableLibs(ArrayList<String> importHeadersList) {
|
||||
Map<String, Contribution> importMap = ContributionListing.getInstance().librariesByImportHeader;
|
||||
ArrayList<AvailableContribution> libList = new ArrayList<AvailableContribution>();
|
||||
for (String importHeaders : importHeadersList) {
|
||||
int dot = importHeaders.lastIndexOf('.');
|
||||
String entry = (dot == -1) ? importHeaders : importHeaders.substring(0,
|
||||
dot);
|
||||
|
||||
if (entry.startsWith("java.") || entry.startsWith("javax.")
|
||||
|| entry.startsWith("processing.")) {
|
||||
continue;// null;
|
||||
}
|
||||
|
||||
Library library = null;
|
||||
try {
|
||||
library = this.getMode().getLibrary(entry);
|
||||
if (library == null) {
|
||||
Contribution c = importMap.get(importHeaders);
|
||||
if (c != null && c instanceof AvailableContribution) {
|
||||
libList.add((AvailableContribution) c);// System.out.println(importHeaders
|
||||
// + "not found");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Not gonna happen (hopefully)
|
||||
Contribution c = importMap.get(importHeaders);
|
||||
if (c != null && c instanceof AvailableContribution) {
|
||||
libList.add((AvailableContribution) c);// System.out.println(importHeaders
|
||||
// + "not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
return libList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays a JDialog prompting the user to save when the user hits
|
||||
* run/present/etc.
|
||||
|
||||
Reference in New Issue
Block a user