Install/remove for library compilations.

This commit is contained in:
pesckal
2011-07-15 20:48:04 +00:00
parent cf8af7fa8a
commit 4c306f5d14
7 changed files with 435 additions and 253 deletions

View File

@@ -0,0 +1,87 @@
package processing.app;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import processing.app.Contribution.ContributionInfo.Author;
public abstract class Contribution {
abstract ContributionInfo getInfo();
abstract File getFolder();
public static void readProperties(HashMap<String, String> propTable,
ContributionInfo info) {
info.category = "Unknown";
info.name = propTable.get("name");
String authors = propTable.get("authorList");
info.authorList = new ArrayList<Author>();
if (authors != null) {
String[] authorNames = authors.split(";");
for (String authorName : authorNames) {
Author author = new Author();
author.name = authorName.trim();
info.authorList.add(author);
}
}
info.url = propTable.get("url");
info.sentence = propTable.get("sentence");
info.paragraph = propTable.get("paragraph");
try {
info.version = Integer.parseInt(propTable.get("version"));
} catch (NumberFormatException e) {
}
info.prettyVersion = propTable.get("prettyVersion");
}
public static abstract class ContributionInfo implements Comparable<ContributionInfo> {
protected String category; // "Sound"
protected String name; // "pdf" or "PDF Export"
protected List<Author> authorList; // Ben Fry
protected String url; // http://processing.org
protected String sentence; // Write graphics to PDF files.
protected String paragraph; // <paragraph length description for site>
protected int version; // 102
protected String prettyVersion; // "1.0.2"
protected String link = "";
public static class Author {
public String name;
public String url;
}
public int compareTo(ContributionInfo o) {
return name.toLowerCase().compareTo(o.name.toLowerCase());
}
public abstract ContributionType getType();
public static enum ContributionType {
LIBRARY, LIBRARY_COMPILATION, TOOL, MODE;
}
public abstract boolean isInstalled();
/**
* @return the contribution associated with this data, or null if it is not
* installed
*/
public abstract Contribution getContribution();
}
}

View File

@@ -1,37 +0,0 @@
package processing.app;
import java.util.List;
public abstract class ContributionInfo implements Comparable<ContributionInfo> {
protected String category; // "Sound"
protected String name; // "pdf" or "PDF Export"
protected List<Author> authorList; // Ben Fry
protected String url; // http://processing.org
protected String sentence; // Write graphics to PDF files.
protected String paragraph; // <paragraph length description for site>
protected int version; // 102
protected String prettyVersion; // "1.0.2"
protected String link = "";
public static class Author {
public String name;
public String url;
}
public int compareTo(ContributionInfo o) {
return name.toLowerCase().compareTo(o.name.toLowerCase());
}
public abstract ContributionType getType();
public static enum ContributionType {
LIBRARY, LIBRARY_COMPILATION, TOOL, MODE;
}
public abstract boolean isInstalled();
}

View File

@@ -37,11 +37,12 @@ import java.awt.*;
import java.net.*;
import java.text.*;
import processing.app.Library.LibraryCompilationInfo;
import processing.app.Library.LibraryInfo;
import processing.app.ContributionInfo.Author;
import processing.app.ContributionInfo.ContributionType;
import processing.app.Contribution.ContributionInfo;
import processing.app.Contribution.ContributionInfo.Author;
import processing.app.Contribution.ContributionInfo.ContributionType;
import processing.app.ContributionListing.ContributionChangeListener;
import processing.app.Library.LibraryInfo;
import processing.app.LibraryCompilation.LibraryCompilationInfo;
public class ContributionListPanel extends JPanel implements Scrollable, ContributionChangeListener {
@@ -130,6 +131,10 @@ public class ContributionListPanel extends JPanel implements Scrollable, Contrib
public void contributionAdded(ContributionInfo contributionInfo) {
if (setupProgressBar.isVisible()) {
setupProgressBar.setVisible(false);
}
ContributionPanel newPanel = null;
if (contributionInfo.getType() == ContributionType.LIBRARY) {
newPanel = new LibraryPanel((LibraryInfo) contributionInfo);
@@ -452,14 +457,6 @@ public class ContributionListPanel extends JPanel implements Scrollable, Contrib
return (LibraryCompilationInfo) info;
}
protected ActionListener createRemoveAction() {
return new ActionListener() {
public void actionPerformed(ActionEvent event) {
}
};
}
protected ActionListener createInstallAction() {
return new ActionListener() {
@@ -504,33 +501,6 @@ public class ContributionListPanel extends JPanel implements Scrollable, Contrib
super(libInfo);
}
private LibraryInfo getInfo() {
return (LibraryInfo) info;
}
protected ActionListener createRemoveAction() {
return new ActionListener() {
public void actionPerformed(ActionEvent arg) {
installOrRemove.setEnabled(false);
installProgressBar.setVisible(true);
contributionManager.removeLibrary(getInfo().library,
new JProgressMonitor(installProgressBar) {
public void finishedAction() {
// Finished uninstalling the library
resetInstallProgressBarState();
installOrRemove.setEnabled(true);
}
}
);
}
};
}
protected ActionListener createInstallAction() {
return new ActionListener() {
@@ -694,7 +664,28 @@ public class ContributionListPanel extends JPanel implements Scrollable, Contrib
protected abstract ActionListener createInstallAction();
protected abstract ActionListener createRemoveAction();
protected ActionListener createRemoveAction() {
return new ActionListener() {
public void actionPerformed(ActionEvent arg) {
installOrRemove.setEnabled(false);
installProgressBar.setVisible(true);
contributionManager.removeLibrary(info.getContribution(),
new JProgressMonitor(installProgressBar) {
public void finishedAction() {
// Finished uninstalling the library
resetInstallProgressBarState();
installOrRemove.setEnabled(true);
}
}
);
}
};
}
void stripListeners(JEditorPane editorPane) {
for (MouseListener l : editorPane.getMouseListeners()) {

View File

@@ -32,15 +32,17 @@ import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import processing.app.Contribution.ContributionInfo;
import processing.app.Contribution.ContributionInfo.Author;
import processing.app.Contribution.ContributionInfo.ContributionType;
import processing.app.Library.LibraryInfo;
import processing.app.Library.LibraryCompilationInfo;
import processing.app.ContributionInfo.Author;
import processing.app.LibraryCompilation.LibraryCompilationInfo;
public class ContributionListing {
ArrayList<ContributionChangeListener> listeners;
ArrayList<ContributionInfo> advertisedLibraries;
ArrayList<ContributionInfo> advertisedContributions;
Map<String, List<ContributionInfo>> librariesByCategory;
@@ -62,8 +64,8 @@ public class ContributionListing {
hasDownloadedList = true;
ContributionXmlParser xmlParser = new ContributionXmlParser(xmlFile);
advertisedLibraries = xmlParser.getLibraries();
updateList(advertisedLibraries);
advertisedContributions = xmlParser.getLibraries();
updateList(advertisedContributions);
Collections.sort(allLibraries);
@@ -73,11 +75,11 @@ public class ContributionListing {
* 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 updateList(List<ContributionInfo> libraries) {
public void updateList(List<ContributionInfo> contributions) {
// First, record the names of all the libraries in installedLibraries
HashSet<String> installedContributionNames = new HashSet<String>();
for (ContributionInfo libInfo : libraries) {
for (ContributionInfo libInfo : contributions) {
installedContributionNames.add(libInfo.name);
}
@@ -99,7 +101,7 @@ public class ContributionListing {
}
}
for (ContributionInfo libInfo : libraries) {
for (ContributionInfo libInfo : contributions) {
String category = categoriesByName.get(libInfo.name);
if (category != null) {
libInfo.category = category;
@@ -165,11 +167,17 @@ public class ContributionListing {
notifyRemove(info);
}
public ContributionInfo getAdvertisedContribution(String libName) {
for (ContributionInfo advertisedLib : advertisedLibraries) {
if (advertisedLib.name.equals(libName)) {
return advertisedLib;
public ContributionInfo getAdvertisedContribution(String contributionName,
ContributionType contributionType) {
for (ContributionInfo advertised : advertisedContributions) {
if (advertised.getType() == contributionType
&& advertised.name.equals(contributionName)) {
return advertised;
}
}
return null;

View File

@@ -35,6 +35,7 @@ import java.util.zip.*;
import javax.swing.*;
import javax.swing.event.*;
import processing.app.Contribution.ContributionInfo;
import processing.app.ContributionListPanel.*;
import processing.app.ContributionListing.ContributionListFetcher;
@@ -50,11 +51,15 @@ public class ContributionManager {
"sketch instead, click “No” and use <i>Sketch &gt;<br>Add File...</i>";
private static final String DISCOVERY_ERROR_TITLE = "Trouble discovering libraries";
private static final String DISCOVERY_INTERNAL_ERROR_MESSAGE =
"An internal error occured while searching for libraries in the file.\n"
+ "This may be a one time error, so try again.";
private static final String DISCOVERY_NONE_FOUND_ERROR_MESSAGE =
"Maybe it's just us, but it looks like there are no\n"
+ "libraries in the file we just downloaded.\n";
static final String ANY_CATEGORY = "Any";
@@ -75,8 +80,6 @@ public class ContributionManager {
ContributionListing contributionListing;
File backupFolder;
public ContributionManager() {
dialog = new JFrame("Contribution Manager");
@@ -272,20 +275,47 @@ public class ContributionManager {
protected void updateContributionListing() {
ArrayList<Library> libraries = editor.getMode().contribLibraries;
ArrayList<LibraryCompilation> compilations = LibraryCompilation.list(libraries);
for (LibraryCompilation compilation : compilations) {
for (Library lib : compilation.libraries) {
libraries.remove(lib);
}
}
ArrayList<ContributionInfo> infoList = new ArrayList<ContributionInfo>();
for (Library library : libraries) {
infoList.add(library.info);
}
for (LibraryCompilation compilation : compilations) {
infoList.add(compilation.info);
}
contributionListing.updateList(infoList);
}
public void removeLibrary(Library library, JProgressMonitor pm) {
public void removeLibrary(final Contribution library, final JProgressMonitor pm) {
LibraryUninstaller libUninstaller = new LibraryUninstaller(library, pm);
new Thread(libUninstaller).start();
new Thread(new Runnable() {
public void run() {
pm.startTask("Removing", ProgressMonitor.UNKNOWN);
if (library != null) {
if (backupContribution(library)) {
ContributionInfo advertisedVersion = contributionListing
.getAdvertisedContribution(library.getInfo().name, library.getInfo().getType());
if (advertisedVersion == null) {
contributionListing.removeLibrary(library.getInfo());
} else {
contributionListing.replaceLibrary(library.getInfo(), advertisedVersion);
}
}
}
refreshInstalled();
pm.finished();
}
}).start();
}
@@ -335,27 +365,55 @@ public class ContributionManager {
new Installer() {
public boolean install(File f) {
String libName = getFileName(f);
File parentDir = unzipFileToTemp(f, libName);
LibraryCompilation installedCompilation = installLibraryCompilation(f);
String folderName = libPanel.info.name;
File libraryDestination = editor.getBase().getSketchbookLibrariesFolder();
File dest = new File(libraryDestination, folderName);
// XXX: Check for conflicts with other library names, etc.
boolean errorEncountered = false;
if (dest.exists()) {
if (!dest.delete()) {
// Problem
}
if (installedCompilation != null) {
contributionListing.replaceLibrary(libPanel.info, installedCompilation.info);
libPanel.info = installedCompilation.info;
return true;
}
return !errorEncountered && parentDir.renameTo(dest);
return false;
}
});
}
protected LibraryCompilation installLibraryCompilation(File f) {
File parentDir = unzipFileToTemp(f);
LibraryCompilation compilation = LibraryCompilation.create(parentDir);
if (compilation == null) {
Base.showWarning(DISCOVERY_ERROR_TITLE,
DISCOVERY_NONE_FOUND_ERROR_MESSAGE, null);
return null;
}
String folderName = compilation.info.name;
File libraryDestination = editor.getBase().getSketchbookLibrariesFolder();
File dest = new File(libraryDestination, folderName);
// XXX: Check for conflicts with other library names, etc.
boolean errorEncountered = false;
if (dest.exists()) {
if (!dest.delete()) {
// Problem
errorEncountered = true;
}
}
if (!errorEncountered) {
// Install it, return it
if (parentDir.renameTo(dest)) {
compilation.folder = dest;
return compilation;
}
}
return null;
}
public void installLibraryFromUrl(URL url,
final LibraryPanel libPanel,
JProgressMonitor downloadProgressMonitor,
@@ -393,15 +451,27 @@ public class ContributionManager {
}
/**
* Unzips a file to a temporary folder.
* 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.
*
* @return the folder where the zips contents have been unzipped to.
* 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).
*/
private static File unzipFileToTemp(File libFile, String id) {
private static File unzipFileToTemp(File libFile) {
String fileName = getFileName(libFile);
File tmpFolder = null;
try {
tmpFolder = Base.createTempFolder(id, "uncompressed");
tmpFolder = Base.createTempFolder(fileName, "uncompressed");
tmpFolder = new File(tmpFolder, fileName);
tmpFolder.mkdirs();
} catch (IOException e) {
Base.showWarning("Trouble creating temporary folder",
"Could not create a place to store libary's uncompressed contents,\n" +
@@ -456,52 +526,17 @@ public class ContributionManager {
return fileName;
}
/**
* Sometimes library authors place all their folders in the base directory of
* a zip file instead of in single folder as the guidelines suggest. This
* method attempts to find the library, if this is the case, by moving the
* contents to a new subdirectory and then searching it for libraries.
*
* @return A list of discovered libraries (may be empty), or null there was an
* error dealing with the filesystem
*/
private ArrayList<Library> recoverLibrary(File tempDir, String libName)
throws IOException {
// No libraries found. It's okay though, the author might not have not
// read the library guidelines and placed all their folders in the base
// directory of the their zip file. If this is the case, let's help them
// out, rather than complaining about it.
File newLibFolder = getUniqueName(tempDir, libName);
if (newLibFolder.mkdirs()) {
for (File f : tempDir.listFiles()) {
if (!f.equals(newLibFolder)) {
if (!f.renameTo(new File(newLibFolder, f.getName()))) {
// The file wasn't moved for whatever reason
return null;
}
// try {
// FileUtils.moveDirectory(f, new File(newLibFolder, f.getName()));
// } catch (IOException e) {
// errorEncountered = true;
// }
}
}
return Library.list(tempDir);
} else {
// We couldn't make the directory to move the library to
return null;
}
}
protected Library installLibrary(File libFile) {
String libName = getFileName(libFile);
File tempDir = unzipFileToTemp(libFile, libName);
File tempDir = unzipFileToTemp(libFile);
try {
ArrayList<Library> discoveredLibs = Library.list(tempDir);
if (discoveredLibs.isEmpty()) {
discoveredLibs = recoverLibrary(tempDir, libName);
// 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.
discoveredLibs = Library.list(tempDir.getParentFile());
}
if (discoveredLibs != null && discoveredLibs.size() == 1) {
@@ -518,8 +553,7 @@ public class ContributionManager {
DISCOVERY_INTERNAL_ERROR_MESSAGE, null);
} else if (discoveredLibs.isEmpty()) {
Base.showWarning(DISCOVERY_ERROR_TITLE,
"Maybe it's just us, but it looks like there are no\n"
+ "libraries in the file we just downloaded.\n", null);
DISCOVERY_NONE_FOUND_ERROR_MESSAGE, null);
} else {
Base.showWarning("Too many libraries",
"We found more than one library in the library file\n"
@@ -561,7 +595,7 @@ public class ContributionManager {
" in <i>libraries/old</i> before replacing it.");
if (result == JOptionPane.YES_OPTION) {
if (!backupLibrary(oldLib)) {
if (!backupContribution(oldLib)) {
return false;
}
} else {
@@ -596,14 +630,25 @@ public class ContributionManager {
}
/**
* Moves the given library to a backup folder.
* Moves the given contribution to a backup folder.
*/
private boolean backupLibrary(Library lib) {
if (!createBackupFolder()) {
return false;
private boolean backupContribution(Contribution lib) {
File backupFolder = null;
switch (lib.getInfo().getType()) {
case LIBRARY:
case LIBRARY_COMPILATION:
backupFolder = createLibraryBackupFolder();
break;
case MODE:
case TOOL:
break;
}
String libFolderName = lib.folder.getName();
if (backupFolder == null) return false;
String libFolderName = lib.getFolder().getName();
String prefix = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
final String backupName = prefix + "_" + libFolderName;
@@ -612,11 +657,11 @@ public class ContributionManager {
// try {
// FileUtils.moveDirectory(lib.folder, backupFolderForLib);
// return true;
if (lib.folder.renameTo(backupFolderForLib)) {
if (lib.getFolder().renameTo(backupFolderForLib)) {
return true;
} else {
// } catch (IOException e) {
Base.showWarning("Trouble creating backup of old \"" + lib.getName() + "\" library",
Base.showWarning("Trouble creating backup of old \"" + lib.getInfo().name + "\" library",
"Could not move library to backup folder:\n"
+ backupFolderForLib.getAbsolutePath(), null);
return false;
@@ -627,25 +672,24 @@ public class ContributionManager {
* @return false if there was an error creating the backup folder, true if it
* already exists or was created successfully
*/
private boolean createBackupFolder() {
if (backupFolder != null)
return true;
private File createLibraryBackupFolder() {
backupFolder = new File(editor.getBase().getSketchbookLibrariesFolder(),
"old");
if (!backupFolder.exists() || !backupFolder.isDirectory()) {
if (!backupFolder.mkdirs()) {
File libraryBackupFolder = new File(editor.getBase()
.getSketchbookLibrariesFolder(), "old");
if (!libraryBackupFolder.exists() || !libraryBackupFolder.isDirectory()) {
if (!libraryBackupFolder.mkdirs()) {
Base.showWarning("Trouble creating folder to store old libraries in",
"Could not create folder "
+ backupFolder.getAbsolutePath()
+ libraryBackupFolder.getAbsolutePath()
+ ".\n"
+ "That's gonna prevent us from replacing the library.",
null);
return false;
return null;
}
}
return true;
return libraryBackupFolder;
}
/**
@@ -778,37 +822,6 @@ public class ContributionManager {
}
}
class LibraryUninstaller implements Runnable {
Library library;
ProgressMonitor pm;
public LibraryUninstaller(Library library, ProgressMonitor pm) {
this.library = library;
this.pm = pm;
}
public void run() {
pm.startTask("Removing", ProgressMonitor.UNKNOWN);
if (library != null) {
if (backupLibrary(library)) {
ContributionInfo advertisedVersion = contributionListing
.getAdvertisedContribution(library.info.name);
if (advertisedVersion == null) {
contributionListing.removeLibrary(library.info);
} else {
contributionListing.replaceLibrary(library.info, advertisedVersion);
}
}
}
refreshInstalled();
pm.finished();
}
}
}
abstract class JProgressMonitor extends AbstractProgressMonitor {

View File

@@ -4,9 +4,10 @@ import java.io.*;
import java.util.*;
import processing.core.*;
import processing.app.ContributionInfo.Author;
import processing.app.Contribution.ContributionInfo;
import processing.app.Contribution.ContributionInfo.Author;
public class Library {
public class Library extends Contribution {
static final String[] platformNames = PConstants.platformNames;
protected File folder; // /path/to/shortname
@@ -89,34 +90,10 @@ public class Library {
info = new LibraryInfo();
info.library = this;
info.category = "Unknown";
info.name = exportTable.get("name");
readProperties(exportTable, info);
if (info.name == null) {
info.name = folder.getName();
}
String authors = exportTable.get("authorList");
info.authorList = new ArrayList<Author>();
if (authors != null) {
String[] authorNames = authors.split(";");
for (String authorName : authorNames) {
Author author = new Author();
author.name = authorName.trim();
info.authorList.add(author);
}
}
info.url = exportTable.get("url");
info.sentence = exportTable.get("sentence");
info.paragraph = exportTable.get("paragraph");
try {
info.version = Integer.parseInt(exportTable.get("version"));
} catch (NumberFormatException e) {
}
info.prettyVersion = exportTable.get("prettyVersion");
exportList = new HashMap<String, String[]>();
@@ -273,6 +250,11 @@ public class Library {
}
public ContributionInfo getInfo() {
return info;
}
public String getName() {
return info.name;
}
@@ -293,6 +275,11 @@ public class Library {
}
public File getFolder() {
return folder;
}
public String getPath() {
return folder.getAbsolutePath();
}
@@ -477,29 +464,16 @@ public class Library {
protected Library library;
public ContributionType getType() {
return ContributionType.LIBRARY;
}
public boolean isInstalled() {
return library != null;
}
public ContributionType getType() {
return ContributionType.LIBRARY;
}
}
public static class LibraryCompilationInfo extends ContributionInfo {
protected File folder;
protected List<Library> libraries;
protected List<String> libraryNames;
public boolean isInstalled() {
// TODO: Check that the right number of libraries are installed
return libraries != null;
}
public ContributionType getType() {
return ContributionType.LIBRARY_COMPILATION;
public Contribution getContribution() {
return library;
}
}

View File

@@ -0,0 +1,146 @@
package processing.app;
import java.io.*;
import java.util.*;
public class LibraryCompilation extends Contribution {
File folder;
ArrayList<Library> libraries;
/** Properties for this library compilation. */
LibraryCompilationInfo info;
private LibraryCompilation(File folder) throws IOException {
this.folder = folder;
File propertiesFile = new File(folder, "properties.txt");
info = new LibraryCompilationInfo();
info.compilation = this;
HashMap<String,String> propertiesTable = Base.readSettings(propertiesFile);
readProperties(propertiesTable, info);
if (info.name == null) {
info.name = folder.getName();
}
libraries = new ArrayList<Library>();
Library.list(folder, libraries, info.name);
}
/**
*
* @param libraries
* @throws IOException
* @throws IllegalArgumentException
* if libraries is empty, libraries are not all in the same folder
* or group.
*/
private LibraryCompilation(ArrayList<Library> libraries)
throws IllegalArgumentException {
this.libraries = libraries;
if (libraries == null || libraries.isEmpty()) {
throw new IllegalArgumentException("No libraries given");
}
folder = libraries.get(0).folder.getParentFile();
String group = libraries.get(0).group;
for (Library lib : libraries) {
if (!group.equals(lib.group)) {
throw new IllegalArgumentException("Libraries are not all in the same group");
}
if (!folder.equals(lib.folder.getParentFile())) {
throw new IllegalArgumentException("Libraries do not all have the same parent folder");
}
}
File propertiesFile = new File(folder, "properties.txt");
info = new LibraryCompilationInfo();
info.compilation = this;
HashMap<String,String> propertiesTable = Base.readSettings(propertiesFile);
readProperties(propertiesTable, info);
if (info.name == null) {
info.name = group;
}
}
public static ArrayList<LibraryCompilation> list(ArrayList<Library> libraries) {
HashMap<String, ArrayList<Library>> libsByGroup = new HashMap<String, ArrayList<Library>>();
for (Library lib : libraries) {
String group = lib.getGroup();
if (group != null) {
if (!libsByGroup.containsKey(group)) {
ArrayList<Library> libs = new ArrayList<Library>();
libs.add(lib);
libsByGroup.put(group, libs);
} else {
libsByGroup.get(group).add(lib);
}
}
}
ArrayList<LibraryCompilation> compilations = new ArrayList<LibraryCompilation>();
for (ArrayList<Library> libList : libsByGroup.values()) {
try {
compilations.add(new LibraryCompilation(libList));
} catch (IllegalArgumentException e) {
}
}
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;
}
ContributionInfo getInfo() {
return info;
}
File getFolder() {
return folder;
}
public static class LibraryCompilationInfo extends ContributionInfo {
protected LibraryCompilation compilation;
protected List<String> libraryNames;
public ContributionType getType() {
return ContributionType.LIBRARY_COMPILATION;
}
public boolean isInstalled() {
// TODO: Check that the right number of libraries are installed
return compilation != null;
}
public Contribution getContribution() {
return compilation;
}
}
}