Category selector for library manager

This commit is contained in:
pesckal
2011-06-28 23:26:49 +00:00
parent 26555e4ac9
commit 55b112eb6c
3 changed files with 230 additions and 180 deletions

View File

@@ -31,21 +31,27 @@ import javax.swing.text.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.*;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.*;
import processing.app.LibraryListing.LibraryInfo;
import processing.app.LibraryManager.LibraryInstaller;
public class LibraryListPanel extends JPanel implements Scrollable {
HashMap<LibraryInfo, LibraryPanel> libPanelsByInfo;
LibraryListing libraries;
private PreferredViewPositionListener preferredViewPositionListener;
private LibraryManager libraryManager;
LibraryListing libraries;
public LibraryListPanel(LibraryListing libraries) {
public LibraryListPanel(LibraryManager libraryManager) {
super();
preferredViewPositionListener = null;
this.libraries = libraries;
this.libraryManager = libraryManager;
libraries = libraryManager.getLibraryListing(null);
setLayout(new GridBagLayout());
@@ -81,10 +87,10 @@ public class LibraryListPanel extends JPanel implements Scrollable {
}
public void filterLibraries(List<String> filters) {
public void filterLibraries(String category, List<String> filters) {
List<LibraryInfo> hiddenLibraries = libraries.getAllLibararies();
for (LibraryInfo lib : libraries.getFilteredLibraryList(filters)) {
for (LibraryInfo lib : libraries.getFilteredLibraryList(category, filters)) {
libPanelsByInfo.get(lib).setVisible(true);
hiddenLibraries.remove(lib);
}
@@ -326,6 +332,9 @@ public class LibraryListPanel extends JPanel implements Scrollable {
* Panel that expands and gives a brief overview of a library when clicked.
*/
class LibraryPanel extends JPanel {
private static final int BUTTON_WIDTH = 100;
final String unclickedCardId = "unclicked";
final String clickedCardId = "clicked";
@@ -336,7 +345,7 @@ public class LibraryListPanel extends JPanel implements Scrollable {
JPanel headerPanel;
JLabel nameLabel;
// JTextArea briefText;
JPanel infoPanel;
@@ -344,7 +353,7 @@ public class LibraryListPanel extends JPanel implements Scrollable {
JPanel clickedCard;
JTextArea briefText;
JTextArea description;
JButton installOrRemove;
@@ -377,7 +386,7 @@ public class LibraryListPanel extends JPanel implements Scrollable {
} else if (c instanceof LibraryPanel) {
LibraryPanel lp = (LibraryPanel) c;
if (lp.isInfoShown) {
obtainedSpace = lp.briefText.getSize().height;
obtainedSpace = lp.description.getSize().height;
lp.setShowInfo(false);
break;
}
@@ -402,12 +411,39 @@ public class LibraryListPanel extends JPanel implements Scrollable {
headerPanel = new JPanel();
headerPanel.setFocusable(true);
headerPanel.setOpaque(false);
headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.X_AXIS));
nameLabel = new JLabel(libInfo.name);
headerPanel.add(this.nameLabel);
headerPanel.add(Box.createHorizontalGlue());
headerPanel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
c.anchor = GridBagConstraints.WEST;
JLabel nameLabel = new JLabel(libInfo.name);
headerPanel.add(nameLabel, c);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.WEST;
// briefText = new JTextArea(libInfo.brief);
// briefText.setHighlighter(null);
// briefText.setOpaque(false);
// briefText.setEditable(false);
// briefText.setLineWrap(true);
// briefText.setWrapStyleWord(true);
// Font font = briefText.getFont();
// font = font.deriveFont(font.getSize() * 0.85f);
// briefText.setFont(font);
// headerPanel.add(briefText, c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 1;
c.anchor = GridBagConstraints.EAST;
headerPanel.add(Box.createRigidArea(new Dimension(BUTTON_WIDTH, 1)), c);
add(headerPanel);
}
@@ -431,48 +467,50 @@ public class LibraryListPanel extends JPanel implements Scrollable {
unclickedCard.setFocusable(true);
clickedCard.setFocusable(true);
briefText = new JTextArea(libInfo.description);
description = new JTextArea(libInfo.description);
installOrRemove = new JButton();
// installOrRemove = new JButton("Install");
// ActionListener installLibAction = new ActionListener() {
//
// public void actionPerformed(ActionEvent arg) {
// try {
// URL url = new URL(libraryUri.getText());
// // System.out.println("Installing library: " + url);
// File libFile = downloadLibrary(url);
// if (libFile != null) {
// installLibrary(libFile);
// }
// } catch (MalformedURLException e) {
// System.err.println("Malformed URL");
// }
// libraryUri.setText("");
// }
// };
// installOrRemove.addActionListener(installLibAction);
if (libInfo.isInstalled) {
} else {
installOrRemove.setText("Install");
ActionListener installLibAction = new ActionListener() {
public void actionPerformed(ActionEvent arg) {
try {
URL url = new URL(libInfo.link);
libraryManager.installLibraryFromUrl(url, null);
} catch (MalformedURLException e) {
Base.showWarning("Install Failed",
"The link fetched from Processing.org is invalid.\n" +
"You can still intall this library manually by visiting\n" +
"the library's website.", e);
}
}
};
installOrRemove.addActionListener(installLibAction);
}
clickedCard.setLayout(new BoxLayout(clickedCard, BoxLayout.X_AXIS));
briefText.setHighlighter(null);
briefText.setOpaque(false);
briefText.setEditable(false);
briefText.setLineWrap(true);
briefText.setWrapStyleWord(true);
Font font = this.briefText.getFont();
description.setHighlighter(null);
description.setOpaque(false);
description.setEditable(false);
description.setLineWrap(true);
description.setWrapStyleWord(true);
Font font = this.description.getFont();
font = font.deriveFont(font.getSize() * 0.9f);
briefText.setFont(font);
description.setFont(font);
clickedCard.add(briefText);
clickedCard.add(description);
clickedCard.add(Box.createHorizontalGlue());
clickedCard.add(installOrRemove);
installOrRemove.setAlignmentY(Component.BOTTOM_ALIGNMENT);
briefText.setAlignmentY(Component.BOTTOM_ALIGNMENT);
description.setAlignmentY(Component.BOTTOM_ALIGNMENT);
installOrRemove.setText("Install");
Dimension installButtonDimensions = installOrRemove.getPreferredSize();
installButtonDimensions.width = 100;
installButtonDimensions.width = BUTTON_WIDTH;
installOrRemove.setPreferredSize(installButtonDimensions);
infoPanel.add(unclickedCard, unclickedCardId);
@@ -504,14 +542,14 @@ public class LibraryListPanel extends JPanel implements Scrollable {
*/
public void updateSize(int width) {
if (isInfoShown) {
Dimension textDimentions = briefText.getPreferredSize();
Dimension textDimentions = description.getPreferredSize();
textDimentions.width = width - installOrRemove.getPreferredSize().width;
textDimentions.height = calculateHeight(briefText, textDimentions.width);
textDimentions.height = calculateHeight(description, textDimentions.width);
briefText.setMaximumSize(textDimentions);
briefText.setMinimumSize(textDimentions);
briefText.setPreferredSize(textDimentions);
briefText.setSize(textDimentions);
description.setMaximumSize(textDimentions);
description.setMinimumSize(textDimentions);
description.setPreferredSize(textDimentions);
description.setSize(textDimentions);
}
Dimension d;

View File

@@ -69,18 +69,21 @@ public class LibraryListing {
return libinfos;
}
public List<LibraryInfo> getFilteredLibraryList(List<String> filters) {
ArrayList<LibraryInfo> filteredList = new ArrayList<LibraryInfo>();
filteredList.addAll(allLibraries);
public List<LibraryInfo> getFilteredLibraryList(String category, List<String> filters) {
ArrayList<LibraryInfo> filteredList = new ArrayList<LibraryInfo>(allLibraries);
Iterator<LibraryInfo> it = filteredList.iterator();
while (it.hasNext()) {
LibraryInfo libInfo = it.next();
for (String filter : filters) {
if (!matches(libInfo, filter)) {
it.remove();
break;
if (category != null && !category.equals(libInfo.categoryName)) {
it.remove();
} else {
for (String filter : filters) {
if (!matches(libInfo, filter)) {
it.remove();
break;
}
}
}
@@ -161,47 +164,34 @@ public class LibraryListing {
}
public static class LibraryInfo implements Comparable<LibraryInfo> {
public final String categoryName;
public String categoryName;
public final String name;
public final String url;
public final String description;
public String name;
public String url;
public String description;
public final ArrayList<Author> authors;
public ArrayList<Author> authors;
public final String versionId;
public final String link;
public String versionId;
public String link;
final boolean isInstalled;
boolean isInstalled;
public LibraryInfo(String categoryName, String name, String url,
String description, ArrayList<Author> authors,
String versionId, String link) {
this.categoryName = categoryName;
this.name = name;
this.url = url;
this.description = description;
this.authors = authors;
this.versionId = versionId;
this.link = link;
public String brief;
isInstalled = false;
public LibraryInfo() {
authors = new ArrayList<Author>();
}
public static class Author {
public final String name;
public String name;
public final String url;
public Author(String name, String url) {
this.name = name;
this.url = url;
}
public String url;
}
public int compareTo(LibraryInfo o) {
return name.compareTo(o.name);
return name.toLowerCase().compareTo(o.name.toLowerCase());
}
}
@@ -210,25 +200,15 @@ public class LibraryListing {
* Class to parse the libraries xml file
*/
class LibraryXmlParser extends DefaultHandler {
String categoryName;
String currentCategoryName;
String libraryName;
LibraryInfo currentLibInfo;
String libraryUrl;
boolean doingDescription = false;
Author currentAuthor;
String libraryVersionId;
String libraryLink;
String libraryDescription;
boolean doingDescription;
ArrayList<LibraryInfo.Author> authors;
String authorUrl;
boolean doingAuthor;
boolean doingAuthor = false;
LibraryXmlParser(File xmlFile) {
SAXParserFactory spf = SAXParserFactory.newInstance();
@@ -251,44 +231,34 @@ public class LibraryListing {
}
}
private void reset() {
libraryName = null;
libraryUrl = null;
libraryVersionId = null;
libraryLink = null;
libraryDescription = null;
doingDescription = false;
authors = new ArrayList<LibraryInfo.Author>();
authorUrl = null;
doingAuthor = false;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if ("category".equals(qName)) {
categoryName = attributes.getValue("name");
currentCategoryName = attributes.getValue("name");
} else if ("library".equals(qName)) {
reset();
libraryName = attributes.getValue("name");
libraryUrl = attributes.getValue("url");
currentLibInfo = new LibraryInfo();
currentLibInfo.categoryName = currentCategoryName;
currentLibInfo.name = attributes.getValue("name");
currentLibInfo.url = attributes.getValue("url");
} else if ("author".equals(qName)) {
authorUrl = attributes.getValue("url");
currentAuthor = new Author();
currentAuthor.url = attributes.getValue("url");
doingAuthor = true;
} else if ("description".equals(qName)) {
currentLibInfo.brief = attributes.getValue("brief");
doingDescription = true;
} else if ("version".equals(qName)) {
libraryVersionId = attributes.getValue("id");
currentLibInfo.versionId = attributes.getValue("id");
} else if ("location".equals(qName)) {
libraryLink = attributes.getValue("url");
currentLibInfo.link = attributes.getValue("url");
}
}
@@ -297,12 +267,12 @@ public class LibraryListing {
throws SAXException {
if (doingAuthor) {
String authorName = new String(ch, start, length).trim();
authors.add(new LibraryInfo.Author(authorName, authorUrl));
authorUrl = null;
currentAuthor.name = new String(ch, start, length).trim();
currentLibInfo.authors.add(currentAuthor);
currentAuthor = null;
doingAuthor = false;
} else if (doingDescription) {
libraryDescription = new String(ch, start, length).trim();
currentLibInfo.description = new String(ch, start, length).trim();
doingDescription = false;
}
}
@@ -312,22 +282,15 @@ public class LibraryListing {
throws SAXException {
if ("library".equals(qName)) {
// Dump the information we collected and reset the variables
LibraryInfo libInfo = new LibraryInfo(categoryName, libraryName,
libraryUrl, libraryDescription,
authors, libraryVersionId,
libraryLink);
if (librariesByCategory.containsKey(categoryName)) {
librariesByCategory.get(categoryName).add(libInfo);
if (librariesByCategory.containsKey(currentCategoryName)) {
librariesByCategory.get(currentCategoryName).add(currentLibInfo);
} else {
ArrayList<LibraryInfo> libs = new ArrayList<LibraryInfo>();
libs.add(libInfo);
librariesByCategory.put(categoryName, libs);
libs.add(currentLibInfo);
librariesByCategory.put(currentCategoryName, libs);
}
reset();
currentLibInfo = null;
}
}

View File

@@ -29,6 +29,7 @@ import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.zip.*;
import javax.swing.*;
@@ -68,6 +69,7 @@ public class LibraryManager {
"sketchbook. If you wish to add this file to your<br>" +
"sketch instead, click “No” and use <i>Sketch &gt;<br>Add File...</i>";
static final String ANY_CATEGORY = "Any";
/**
* true to use manual URL specification only
* false to use searchable library list
@@ -83,7 +85,7 @@ public class LibraryManager {
JButton installButton;
JProgressBar installProgressBar;
LibraryListing libraryListing;
// Non-simple UI widgets:
FilterField filterField;
@@ -92,10 +94,14 @@ public class LibraryManager {
JComboBox categoryChooser;
String category;
// the calling editor, so updates can be applied
Editor editor;
JProgressBar installProgressBar;
public LibraryManager() {
dialog = new JFrame("Library Manager");
@@ -185,12 +191,7 @@ public class LibraryManager {
libraryUrl.setEnabled(false);
installButton.setEnabled(false);
File libDest = getTemporaryFile(url);
FileDownloader downloader = new FileDownloader(url, libDest, pm);
downloader.setPostOperation(new LibraryInstaller(downloader, pm));
new Thread(downloader).start();
installLibraryFromUrl(url, pm);
} catch (MalformedURLException e) {
System.err.println("Malformed URL");
@@ -247,39 +248,10 @@ public class LibraryManager {
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
filterField = new FilterField();
filterField.getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent e) {
filter();
}
public void insertUpdate(DocumentEvent e) {
filter();
}
public void changedUpdate(DocumentEvent e) {
filter();
}
void filter() {
String filter = filterField.getFilterText();
filter = filter.toLowerCase();
// Replace anything but 0-9 or a-z with a space
filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a]", " ");
libraryListPane.filterLibraries(Arrays.asList(filter.split(" ")));
}
});
pane.add(filterField, c);
LibraryListFetcher llf = new LibraryListFetcher();
llf.fetchLibraryList(null);
while (!llf.isDone()) {
Thread.yield();
}
libraryListPane = new LibraryListPanel(llf.getLibraryListing());
libraryListPane = new LibraryListPanel(this);
c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
@@ -324,13 +296,35 @@ public class LibraryManager {
c.gridx = 1;
c.gridy = 2;
String[] categories = {
"Any", "3D", "Animation", "Compilations", "Computer Vision",
"Data and Protocols", "Geometry", "Graphic Interface",
"Hardware Interface", "Import / Export", "Math", "Simulation", "Sound",
"Tools", "Typography", "Video" };
categoryChooser = new JComboBox(categories);
ArrayList<String> categories = new ArrayList<String>(getLibraryListing(null).getCategories());
Collections.sort(categories);
categories.add(0, ANY_CATEGORY);
categoryChooser = new JComboBox(categories.toArray());
pane.add(categoryChooser, c);
categoryChooser.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
category = (String) categoryChooser.getSelectedItem();
if (ANY_CATEGORY.equals(category)) {
category = null;
}
libraryListPane.filterLibraries(category, filterField.filters);
}
});
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 3;
c.weightx = 1;
c.gridwidth = 2;
installProgressBar = new JProgressBar();
installProgressBar.setString("");
installProgressBar.setStringPainted(true);
installProgressBar.setVisible(false);
pane.add(installProgressBar, c);
dialog.setMinimumSize(new Dimension(400, 400));
}
@@ -374,6 +368,30 @@ public class LibraryManager {
dialog.dispose();
}
public LibraryListing getLibraryListing(ProgressMonitor pm) {
if (libraryListing == null) {
LibraryListFetcher llf = new LibraryListFetcher();
llf.fetchLibraryList(pm);
// This is dumb. Lets make it better.
while (!llf.isDone()) {
Thread.yield();
}
libraryListing = llf.getLibraryListing();
}
return libraryListing;
}
public void installLibraryFromUrl(URL url, JProgressMonitor pm) {
File libDest = getTemporaryFile(url);
FileDownloader downloader = new FileDownloader(url, libDest, pm);
downloader.setPostOperation(new LibraryInstaller(downloader, pm));
new Thread(downloader).start();
}
public int confirmAndInstallLibrary(Editor editor, File libFile) {
this.editor = editor;
@@ -589,14 +607,20 @@ public class LibraryManager {
// }
class FilterField extends JTextField {
final static String filterHint = "Filter your search...";
boolean isShowingHint;
List<String> filters;
public FilterField () {
super(filterHint);
isShowingHint = true;
filters = new ArrayList<String>();
addFocusListener(new FocusListener() {
public void focusLost(FocusEvent focusEvent) {
@@ -616,6 +640,31 @@ public class LibraryManager {
updateStyle();
}
});
getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent e) {
filter();
}
public void insertUpdate(DocumentEvent e) {
filter();
}
public void changedUpdate(DocumentEvent e) {
filter();
}
void filter() {
String filter = filterField.getFilterText();
filter = filter.toLowerCase();
// Replace anything but 0-9 or a-z with a space
filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a]", " ");
filters = Arrays.asList(filter.split(" "));
libraryListPane.filterLibraries(category, filters);
}
});
}
public String getFilterText() {