1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-30 19:52:13 +01:00

LibraryManager: better type filtering

This commit is contained in:
Federico Fissore 2015-03-26 17:11:04 +01:00
parent 74a8ccdeb4
commit 6e498ee5b9
14 changed files with 181 additions and 76 deletions

View File

@ -0,0 +1,39 @@
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndex;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import java.util.Collection;
public class InstalledLibraryPredicate implements Predicate<ContributedLibrary> {
private final LibrariesIndex index;
public InstalledLibraryPredicate(LibrariesIndex index) {
this.index = index;
}
@Override
public boolean apply(ContributedLibrary input) {
if (input.isInstalled()) {
return true;
}
Collection<ContributedLibrary> installed = Collections2.filter(index.find(input.getName()), new Predicate<ContributedLibrary>() {
@Override
public boolean apply(ContributedLibrary input) {
return input.isInstalled();
}
});
return !installed.isEmpty();
}
@Override
public boolean equals(Object obj) {
return obj instanceof InstalledLibraryPredicate;
}
}

View File

@ -33,6 +33,7 @@ import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.libraries.ContributedLibrary; import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.ContributedLibraryComparator; import cc.arduino.contributions.libraries.ContributedLibraryComparator;
import cc.arduino.contributions.libraries.filters.BuiltInPredicate; import cc.arduino.contributions.libraries.filters.BuiltInPredicate;
import cc.arduino.contributions.libraries.filters.InstalledLibraryPredicate;
import cc.arduino.contributions.libraries.filters.OnlyUpstreamReleasePredicate; import cc.arduino.contributions.libraries.filters.OnlyUpstreamReleasePredicate;
import cc.arduino.contributions.ui.InstallerTableCell; import cc.arduino.contributions.ui.InstallerTableCell;
import cc.arduino.contributions.ui.listeners.DelegatingKeyListener; import cc.arduino.contributions.ui.listeners.DelegatingKeyListener;
@ -65,6 +66,7 @@ import static processing.app.I18n.format;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class ContributedLibraryTableCell extends InstallerTableCell { public class ContributedLibraryTableCell extends InstallerTableCell {
private final LibraryManagerUI indexer;
private JPanel panel; private JPanel panel;
private JButton installButton; private JButton installButton;
private Component installButtonPlaceholder; private Component installButtonPlaceholder;
@ -75,7 +77,9 @@ public class ContributedLibraryTableCell extends InstallerTableCell {
private JPanel inactiveButtonsPanel; private JPanel inactiveButtonsPanel;
private JLabel statusLabel; private JLabel statusLabel;
public ContributedLibraryTableCell() { public ContributedLibraryTableCell(LibraryManagerUI indexer) {
this.indexer = indexer;
{ {
installButton = new JButton(_("Install")); installButton = new JButton(_("Install"));
installButton.addActionListener(new ActionListener() { installButton.addActionListener(new ActionListener() {

View File

@ -0,0 +1,27 @@
package cc.arduino.contributions.libraries.ui;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.LibrariesIndex;
import cc.arduino.contributions.libraries.filters.InstalledLibraryPredicate;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
import static processing.app.I18n._;
public class DropdownInstalledLibraryItem implements DropdownItem<ContributedLibrary> {
private final LibrariesIndex index;
public DropdownInstalledLibraryItem(LibrariesIndex index) {
this.index = index;
}
public String toString() {
return _("Installed");
}
@Override
public Predicate<ContributedLibrary> getFilterPredicate() {
return new InstalledLibraryPredicate(index);
}
}

View File

@ -39,7 +39,6 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import static processing.app.I18n._; import static processing.app.I18n._;
@ -62,12 +61,12 @@ public class LibraryManagerUI extends InstallerJDialog<ContributedLibrary> {
@Override @Override
protected InstallerTableCell createCellRenderer() { protected InstallerTableCell createCellRenderer() {
return new ContributedLibraryTableCell(); return new ContributedLibraryTableCell(this);
} }
@Override @Override
protected InstallerTableCell createCellEditor() { protected InstallerTableCell createCellEditor() {
return new ContributedLibraryTableCell() { return new ContributedLibraryTableCell(this) {
@Override @Override
protected void onInstall(ContributedLibrary selectedLibrary, ContributedLibrary installedLibrary) { protected void onInstall(ContributedLibrary selectedLibrary, ContributedLibrary installedLibrary) {
if (selectedLibrary.isReadOnly()) { if (selectedLibrary.isReadOnly()) {
@ -150,7 +149,7 @@ public class LibraryManagerUI extends InstallerJDialog<ContributedLibrary> {
typeFilter = null; typeFilter = null;
typeChooser.removeAllItems(); typeChooser.removeAllItems();
typeChooser.addItem(new DropdownAllItem()); typeChooser.addItem(new DropdownAllItem());
typeChooser.addItem(new DropdownInstalledContributionItem()); typeChooser.addItem(new DropdownInstalledLibraryItem(indexer.getIndex()));
Collection<String> types = indexer.getIndex().getTypes(); Collection<String> types = indexer.getIndex().getTypes();
for (String type : types) { for (String type : types) {
typeChooser.addItem(new DropdownLibraryOfTypeItem(type)); typeChooser.addItem(new DropdownLibraryOfTypeItem(type));
@ -169,6 +168,10 @@ public class LibraryManagerUI extends InstallerJDialog<ContributedLibrary> {
}; };
} }
public LibrariesIndexer getIndexer() {
return indexer;
}
public void setProgress(Progress progress) { public void setProgress(Progress progress) {
progressBar.setValue(progress); progressBar.setValue(progress);
} }

View File

@ -1,20 +0,0 @@
package cc.arduino.contributions.ui;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.packages.DownloadableContribution;
import cc.arduino.contributions.ui.DropdownItem;
import com.google.common.base.Predicate;
import static processing.app.I18n._;
public class DropdownInstalledContributionItem implements DropdownItem<DownloadableContribution> {
public String toString() {
return _("Installed");
}
@Override
public Predicate<DownloadableContribution> getFilterPredicate() {
return new InstalledPredicate();
}
}

View File

@ -26,18 +26,32 @@
* invalidate any other reasons why the executable file might be covered by * invalidate any other reasons why the executable file might be covered by
* the GNU General Public License. * the GNU General Public License.
*/ */
package cc.arduino.contributions.libraries; package cc.arduino.contributions.libraries;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import java.util.*; import java.util.*;
public abstract class LibrariesIndex { public abstract class LibrariesIndex {
public abstract List<ContributedLibrary> getLibraries(); public abstract List<ContributedLibrary> getLibraries();
public List<ContributedLibrary> find(final String name) {
return new LinkedList<ContributedLibrary>(Collections2.filter(getLibraries(), new Predicate<ContributedLibrary>() {
@Override
public boolean apply(ContributedLibrary contributedLibrary) {
return name.equals(contributedLibrary.getName());
}
}));
}
public ContributedLibrary find(String name, String version) { public ContributedLibrary find(String name, String version) {
for (ContributedLibrary lib : getLibraries()) { for (ContributedLibrary lib : find(name)) {
if (lib.getName().equals(name) && lib.getVersion().equals(version)) if (lib.getVersion().equals(version)) {
return lib; return lib;
}
} }
return null; return null;
} }

View File

@ -28,14 +28,9 @@
*/ */
package cc.arduino.contributions.libraries; package cc.arduino.contributions.libraries;
import static processing.app.I18n._; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File; import com.fasterxml.jackson.module.mrbean.MrBeanModule;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import processing.app.BaseNoGui; import processing.app.BaseNoGui;
import processing.app.I18n; import processing.app.I18n;
import processing.app.helpers.FileUtils; import processing.app.helpers.FileUtils;
@ -44,9 +39,14 @@ import processing.app.packages.LegacyUserLibrary;
import processing.app.packages.LibraryList; import processing.app.packages.LibraryList;
import processing.app.packages.UserLibrary; import processing.app.packages.UserLibrary;
import com.fasterxml.jackson.databind.DeserializationFeature; import java.io.File;
import com.fasterxml.jackson.databind.ObjectMapper; import java.io.FileInputStream;
import com.fasterxml.jackson.module.mrbean.MrBeanModule; import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import static processing.app.I18n._;
public class LibrariesIndexer { public class LibrariesIndexer {
@ -60,7 +60,7 @@ public class LibrariesIndexer {
public LibrariesIndexer(File preferencesFolder) { public LibrariesIndexer(File preferencesFolder) {
indexFile = new File(preferencesFolder, "library_index.json"); indexFile = new File(preferencesFolder, "library_index.json");
stagingFolder = new File(preferencesFolder, "staging" + File.separator + stagingFolder = new File(preferencesFolder, "staging" + File.separator +
"libraries"); "libraries");
} }
public void parseIndex() throws IOException { public void parseIndex() throws IOException {
@ -109,9 +109,9 @@ public class LibrariesIndexer {
for (File subfolder : list) { for (File subfolder : list) {
if (!BaseNoGui.isSanitaryName(subfolder.getName())) { if (!BaseNoGui.isSanitaryName(subfolder.getName())) {
String mess = I18n.format(_("The library \"{0}\" cannot be used.\n" String mess = I18n.format(_("The library \"{0}\" cannot be used.\n"
+ "Library names must contain only basic letters and numbers.\n" + "Library names must contain only basic letters and numbers.\n"
+ "(ASCII only and no spaces, and it cannot start with a number)"), + "(ASCII only and no spaces, and it cannot start with a number)"),
subfolder.getName()); subfolder.getName());
BaseNoGui.showMessage(_("Ignoring bad library name"), mess); BaseNoGui.showMessage(_("Ignoring bad library name"), mess);
continue; continue;
} }
@ -119,21 +119,18 @@ public class LibrariesIndexer {
try { try {
scanLibrary(subfolder); scanLibrary(subfolder);
} catch (IOException e) { } catch (IOException e) {
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), subfolder, e.getMessage()));
subfolder, e.getMessage()));
} }
} }
} }
private void scanLibrary(File folder) throws IOException { private void scanLibrary(File folder) throws IOException {
boolean readOnly = !FileUtils boolean readOnly = !FileUtils.isSubDirectory(sketchbookLibrariesFolder, folder);
.isSubDirectory(sketchbookLibrariesFolder, folder);
// A library is considered "legacy" if it doesn't contains // A library is considered "legacy" if it doesn't contains
// a file called "library.properties" // a file called "library.properties"
File check = new File(folder, "library.properties"); File check = new File(folder, "library.properties");
if (!check.exists() || !check.isFile()) { if (!check.exists() || !check.isFile()) {
// Create a legacy library and exit // Create a legacy library and exit
LegacyUserLibrary lib = LegacyUserLibrary.create(folder); LegacyUserLibrary lib = LegacyUserLibrary.create(folder);
lib.setReadOnly(readOnly); lib.setReadOnly(readOnly);
@ -148,12 +145,20 @@ public class LibrariesIndexer {
// Check if we can find the same library in the index // Check if we can find the same library in the index
// and mark it as installed // and mark it as installed
String libName = folder.getName(); // XXX: lib.getName()? ContributedLibrary foundLib = index.find(lib.getName(), lib.getVersion());
ContributedLibrary foundLib = index.find(libName, lib.getVersion());
if (foundLib != null) { if (foundLib != null) {
foundLib.setInstalled(true); foundLib.setInstalled(true);
foundLib.setInstalledFolder(folder); foundLib.setInstalledFolder(folder);
foundLib.setReadOnly(readOnly); foundLib.setReadOnly(readOnly);
lib.setTypes(foundLib.getTypes());
}
if (lib.isReadOnly() && lib.getTypes() == null && !lib.getDeclaredTypes().isEmpty()) {
lib.setTypes(lib.getDeclaredTypes());
}
if (lib.getTypes() == null) {
lib.setTypes(Arrays.asList("Contributed"));
} }
} }

View File

@ -28,17 +28,18 @@
*/ */
package processing.app.packages; package processing.app.packages;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.ContributedLibraryReference;
import processing.app.helpers.FileUtils;
import processing.app.helpers.PreferencesMap;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import processing.app.helpers.FileUtils;
import processing.app.helpers.PreferencesMap;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.ContributedLibraryReference;
public class UserLibrary extends ContributedLibrary { public class UserLibrary extends ContributedLibrary {
private String name; private String name;
@ -51,15 +52,17 @@ public class UserLibrary extends ContributedLibrary {
private String category; private String category;
private String license; private String license;
private List<String> architectures; private List<String> architectures;
private List<String> types;
private List<String> declaredTypes;
private static final List<String> MANDATORY_PROPERTIES = Arrays private static final List<String> MANDATORY_PROPERTIES = Arrays
.asList(new String[] { "name", "version", "author", "maintainer", .asList(new String[]{"name", "version", "author", "maintainer",
"sentence", "paragraph", "url" }); "sentence", "paragraph", "url"});
private static final List<String> CATEGORIES = Arrays.asList(new String[] { private static final List<String> CATEGORIES = Arrays.asList(new String[]{
"Display", "Communication", "Signal Input/Output", "Sensors", "Display", "Communication", "Signal Input/Output", "Sensors",
"Device Control", "Timing", "Data Storage", "Data Processing", "Other", "Device Control", "Timing", "Data Storage", "Data Processing", "Other",
"Uncategorized" }); "Uncategorized"});
public static UserLibrary create(File libFolder) throws IOException { public static UserLibrary create(File libFolder) throws IOException {
// Parse metadata // Parse metadata
@ -72,16 +75,16 @@ public class UserLibrary extends ContributedLibrary {
// Compatibility with 1.5 rev.1 libraries: // Compatibility with 1.5 rev.1 libraries:
// "email" field changed to "maintainer" // "email" field changed to "maintainer"
if (!properties.containsKey("maintainer") && if (!properties.containsKey("maintainer") && properties.containsKey("email")) {
properties.containsKey("email"))
properties.put("maintainer", properties.get("email")); properties.put("maintainer", properties.get("email"));
}
// Compatibility with 1.5 rev.1 libraries: // Compatibility with 1.5 rev.1 libraries:
// "arch" folder no longer supported // "arch" folder no longer supported
File archFolder = new File(libFolder, "arch"); File archFolder = new File(libFolder, "arch");
if (archFolder.isDirectory()) if (archFolder.isDirectory())
throw new IOException("'arch' folder is no longer supported! See " throw new IOException("'arch' folder is no longer supported! See "
+ "http://goo.gl/gfFJzU for more information"); + "http://goo.gl/gfFJzU for more information");
// Check mandatory properties // Check mandatory properties
for (String p : MANDATORY_PROPERTIES) for (String p : MANDATORY_PROPERTIES)
@ -99,7 +102,7 @@ public class UserLibrary extends ContributedLibrary {
File utilFolder = new File(libFolder, "utility"); File utilFolder = new File(libFolder, "utility");
if (utilFolder.exists() && utilFolder.isDirectory()) { if (utilFolder.exists() && utilFolder.isDirectory()) {
throw new IOException( throw new IOException(
"Library can't use both 'src' and 'utility' folders."); "Library can't use both 'src' and 'utility' folders.");
} }
} else { } else {
// Layout with source code on library's root and "utility" folders // Layout with source code on library's root and "utility" folders
@ -110,8 +113,7 @@ public class UserLibrary extends ContributedLibrary {
for (File file : libFolder.listFiles()) { for (File file : libFolder.listFiles()) {
if (file.isDirectory()) { if (file.isDirectory()) {
if (FileUtils.isSCCSOrHiddenFile(file)) { if (FileUtils.isSCCSOrHiddenFile(file)) {
System.out.println("WARNING: Spurious " + file.getName() + System.out.println("WARNING: Spurious " + file.getName() + " folder in '" + properties.get("name") + "' library");
" folder in '" + properties.get("name") + "' library");
continue; continue;
} }
} }
@ -131,12 +133,22 @@ public class UserLibrary extends ContributedLibrary {
if (!CATEGORIES.contains(category)) { if (!CATEGORIES.contains(category)) {
category = "Uncategorized"; category = "Uncategorized";
System.out.println("WARNING: Category '" + category + "' in library " + System.out.println("WARNING: Category '" + category + "' in library " +
properties.get("name") + " is not valid. Setting to 'Uncategorized'"); properties.get("name") + " is not valid. Setting to 'Uncategorized'");
} }
String license = properties.get("license"); String license = properties.get("license");
if (license == null) if (license == null) {
license = "Unspecified"; license = "Unspecified";
}
String types = properties.get("types");
if (types == null) {
types = "Contributed";
}
List<String> typesList = new LinkedList<String>();
for (String type : types.split(",")) {
typesList.add(type.trim());
}
UserLibrary res = new UserLibrary(); UserLibrary res = new UserLibrary();
res.setInstalledFolder(libFolder); res.setInstalledFolder(libFolder);
@ -152,6 +164,7 @@ public class UserLibrary extends ContributedLibrary {
res.license = license.trim(); res.license = license.trim();
res.architectures = archs; res.architectures = archs;
res.layout = layout; res.layout = layout;
res.declaredTypes = typesList;
return res; return res;
} }
@ -192,7 +205,11 @@ public class UserLibrary extends ContributedLibrary {
@Override @Override
public List<String> getTypes() { public List<String> getTypes() {
return Arrays.asList("Contributed"); return types;
}
public void setTypes(List<String> types) {
this.types = types;
} }
@Override @Override
@ -244,20 +261,24 @@ public class UserLibrary extends ContributedLibrary {
return null; return null;
} }
public List<String> getDeclaredTypes() {
return declaredTypes;
}
protected enum LibraryLayout { protected enum LibraryLayout {
FLAT, RECURSIVE FLAT, RECURSIVE
}; }
protected LibraryLayout layout; protected LibraryLayout layout;
public File getSrcFolder() { public File getSrcFolder() {
switch (layout) { switch (layout) {
case FLAT: case FLAT:
return getInstalledFolder(); return getInstalledFolder();
case RECURSIVE: case RECURSIVE:
return new File(getInstalledFolder(), "src"); return new File(getInstalledFolder(), "src");
default: default:
return null; // Keep compiler happy :-( return null; // Keep compiler happy :-(
} }
} }

View File

@ -6,3 +6,5 @@ sentence=Enables reading and writing to the permanent board storage. For all Ard
paragraph= paragraph=
url=http://arduino.cc/en/Reference/EEPROM url=http://arduino.cc/en/Reference/EEPROM
architectures=avr architectures=avr
types=Arduino

View File

@ -6,3 +6,5 @@ sentence=Enables the communication with devices that use the Serial Peripheral I
paragraph= paragraph=
url=http://arduino.cc/en/Reference/SPI url=http://arduino.cc/en/Reference/SPI
architectures=avr architectures=avr
types=Arduino

View File

@ -6,3 +6,5 @@ sentence=Enables serial communication on digital pins. For all Arduino boards, B
paragraph= paragraph=
url=http://arduino.cc/en/Reference/SoftwareSerial url=http://arduino.cc/en/Reference/SoftwareSerial
architectures=avr architectures=avr
types=Arduino

View File

@ -6,3 +6,5 @@ sentence=Allows the communication between devices or sensors connected via Two W
paragraph= paragraph=
url=http://arduino.cc/en/Reference/Wire url=http://arduino.cc/en/Reference/Wire
architectures=avr architectures=avr
types=Arduino

View File

@ -6,3 +6,5 @@ sentence=Enables the communication with devices that use the Serial Peripheral I
paragraph= paragraph=
url=http://arduino.cc/en/Reference/SPI url=http://arduino.cc/en/Reference/SPI
architectures=sam architectures=sam
types=Arduino

View File

@ -6,3 +6,5 @@ sentence=Allows the communication between devices or sensors connected via Two W
paragraph= paragraph=
url=http://arduino.cc/en/Reference/Wire url=http://arduino.cc/en/Reference/Wire
architectures=sam architectures=sam
types=Arduino