From 55b112eb6c4116ebe83fdb2ca91daf07017e3a62 Mon Sep 17 00:00:00 2001 From: pesckal Date: Tue, 28 Jun 2011 23:26:49 +0000 Subject: [PATCH] Category selector for library manager --- app/src/processing/app/LibraryListPanel.java | 136 +++++++++++------- app/src/processing/app/LibraryListing.java | 137 +++++++------------ app/src/processing/app/LibraryManager.java | 137 +++++++++++++------ 3 files changed, 230 insertions(+), 180 deletions(-) diff --git a/app/src/processing/app/LibraryListPanel.java b/app/src/processing/app/LibraryListPanel.java index eecf3e965..277e24c77 100644 --- a/app/src/processing/app/LibraryListPanel.java +++ b/app/src/processing/app/LibraryListPanel.java @@ -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 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 filters) { + public void filterLibraries(String category, List filters) { List 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; diff --git a/app/src/processing/app/LibraryListing.java b/app/src/processing/app/LibraryListing.java index 3e83c63e0..e2a05801c 100644 --- a/app/src/processing/app/LibraryListing.java +++ b/app/src/processing/app/LibraryListing.java @@ -69,18 +69,21 @@ public class LibraryListing { return libinfos; } - public List getFilteredLibraryList(List filters) { - ArrayList filteredList = new ArrayList(); - filteredList.addAll(allLibraries); + public List getFilteredLibraryList(String category, List filters) { + ArrayList filteredList = new ArrayList(allLibraries); Iterator 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 { - 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 authors; + public ArrayList 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 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(); } 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 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(); - 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 libs = new ArrayList(); - libs.add(libInfo); - librariesByCategory.put(categoryName, libs); + libs.add(currentLibInfo); + librariesByCategory.put(currentCategoryName, libs); } - reset(); + currentLibInfo = null; } } diff --git a/app/src/processing/app/LibraryManager.java b/app/src/processing/app/LibraryManager.java index f3699419d..555430f2a 100644 --- a/app/src/processing/app/LibraryManager.java +++ b/app/src/processing/app/LibraryManager.java @@ -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
" + "sketch instead, click “No” and use Sketch >
Add File...
"; + 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 categories = new ArrayList(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 filters; + public FilterField () { super(filterHint); isShowingHint = true; + filters = new ArrayList(); + 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() {