mirror of
https://github.com/processing/processing4.git
synced 2026-04-28 15:11:51 +02:00
List for displaying available libraries added to library manager.
List of available libraries is currently a placeholder.
This commit is contained in:
312
app/src/processing/app/LibraryListPanel.java
Normal file
312
app/src/processing/app/LibraryListPanel.java
Normal file
@@ -0,0 +1,312 @@
|
||||
package processing.app;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.awt.font.*;
|
||||
import java.awt.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
import processing.app.LibraryManager.*;
|
||||
|
||||
public class LibraryListPanel extends JPanel {
|
||||
|
||||
/**
|
||||
* Panel that expands and gives a brief overview of a library when clicked.
|
||||
*/
|
||||
class LibraryPanel extends JPanel {
|
||||
final String unclickedCardId = "unclicked";
|
||||
final String clickedCardId = "clicked";
|
||||
final int topAndBottomBorder = 2;
|
||||
|
||||
LibraryInfo libInfo;
|
||||
|
||||
JPanel headerPanel;
|
||||
JLabel nameLabel;
|
||||
|
||||
JPanel infoPanel;
|
||||
JPanel unclickedCard;
|
||||
JPanel clickedCard;
|
||||
JTextArea briefText;
|
||||
JButton installOrRemove;
|
||||
|
||||
boolean isInfoShown;
|
||||
|
||||
private LibraryPanel(LibraryInfo libInfo) {
|
||||
this.libInfo = libInfo;
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
|
||||
setBorder(BorderFactory.createEmptyBorder(topAndBottomBorder, 2, topAndBottomBorder, 2));
|
||||
|
||||
configureHeaderPane();
|
||||
configureInfoPane();
|
||||
|
||||
setShowInfo(false);
|
||||
updateLibraryListSize();
|
||||
addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
for (Component c : LibraryListPanel.this.getComponents()) {
|
||||
if (c != LibraryPanel.this && c instanceof LibraryPanel) {
|
||||
LibraryPanel lp = (LibraryPanel) c;
|
||||
lp.setShowInfo(false);
|
||||
}
|
||||
}
|
||||
setShowInfo(true);
|
||||
updateLibraryListSize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the widgets for the header panel which is visible when the library
|
||||
* panel is not clicked
|
||||
*/
|
||||
private void configureHeaderPane() {
|
||||
headerPanel = new JPanel();
|
||||
headerPanel.setOpaque(false);
|
||||
headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.X_AXIS));
|
||||
|
||||
nameLabel = new JLabel(libInfo.name);
|
||||
headerPanel.add(this.nameLabel);
|
||||
headerPanel.add(Box.createHorizontalGlue());
|
||||
|
||||
add(headerPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the widgets for the info panel which is visible when the library
|
||||
* panel is clicked
|
||||
*/
|
||||
private void configureInfoPane() {
|
||||
infoPanel = new JPanel();
|
||||
infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS));
|
||||
infoPanel.setLayout(new CardLayout());
|
||||
|
||||
unclickedCard = new JPanel();
|
||||
clickedCard = new JPanel();
|
||||
|
||||
infoPanel.setOpaque(false);
|
||||
unclickedCard.setOpaque(false);
|
||||
clickedCard.setOpaque(false);
|
||||
|
||||
briefText = new JTextArea(libInfo.briefOverview);
|
||||
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);
|
||||
|
||||
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();
|
||||
font = font.deriveFont(font.getSize() * 0.9f);
|
||||
briefText.setFont(font);
|
||||
|
||||
clickedCard.add(briefText);
|
||||
clickedCard.add(Box.createHorizontalGlue());
|
||||
clickedCard.add(installOrRemove);
|
||||
|
||||
installOrRemove.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
||||
briefText.setAlignmentY(Component.BOTTOM_ALIGNMENT);
|
||||
|
||||
installOrRemove.setText("Install");
|
||||
Dimension installButtonDimensions = installOrRemove.getPreferredSize();
|
||||
installButtonDimensions.width = 100;
|
||||
installOrRemove.setPreferredSize(installButtonDimensions);
|
||||
|
||||
infoPanel.add(unclickedCard, unclickedCardId);
|
||||
infoPanel.add(clickedCard, clickedCardId);
|
||||
|
||||
add(infoPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on/off the info panel which contains a brief description of the
|
||||
* library and a button to Install/Remove a library.
|
||||
*/
|
||||
public void setShowInfo(boolean doShow) {
|
||||
isInfoShown = doShow;
|
||||
CardLayout cardLayout = (CardLayout) infoPanel.getLayout();
|
||||
|
||||
if (isInfoShown) {
|
||||
setBackground(UIManager.getColor("List.selectionBackground"));
|
||||
cascadeForgroundColor(this, UIManager.getColor("List.selectionForeground"));
|
||||
|
||||
cardLayout.show(infoPanel, clickedCardId);
|
||||
} else {
|
||||
setBackground(UIManager.getColor("List.background"));
|
||||
cascadeForgroundColor(this, UIManager.getColor("List.foreground"));
|
||||
|
||||
cardLayout.show(infoPanel, unclickedCardId);
|
||||
}
|
||||
|
||||
int width = getSize().width;
|
||||
updateSize(width > 0 ? width : 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sizes of components in this panel given width as a constraint
|
||||
*/
|
||||
public void updateSize(int width) {
|
||||
Dimension textDimentions = briefText.getPreferredSize();
|
||||
textDimentions.width = width - installOrRemove.getPreferredSize().width;
|
||||
textDimentions.height = calculateHeight(briefText, textDimentions.width);
|
||||
|
||||
briefText.setMaximumSize(textDimentions);
|
||||
briefText.setMinimumSize(textDimentions);
|
||||
briefText.setPreferredSize(textDimentions);
|
||||
//briefText.setSize(textDimentions);
|
||||
|
||||
Dimension d;
|
||||
if (isInfoShown) {
|
||||
d = headerPanel.getPreferredSize();
|
||||
d.width = width;
|
||||
d.height += clickedCard.getPreferredSize().height + 2 * topAndBottomBorder;
|
||||
} else {
|
||||
d = headerPanel.getPreferredSize();
|
||||
d.width = width;
|
||||
d.height += 2 * topAndBottomBorder;
|
||||
}
|
||||
|
||||
setMaximumSize(d);
|
||||
setMinimumSize(d);
|
||||
setPreferredSize(d);
|
||||
//setSize(d);
|
||||
|
||||
revalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LibraryListPanel(ArrayList<LibraryInfo> libraries) {
|
||||
super();
|
||||
|
||||
setLayout(new GridBagLayout());
|
||||
int row = 0;
|
||||
for (LibraryInfo libInfo : libraries) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1;
|
||||
c.gridx = 0;
|
||||
c.gridy = row++;
|
||||
|
||||
add(new LibraryPanel(libInfo), c);
|
||||
}
|
||||
|
||||
GridBagConstraints verticalFill = new GridBagConstraints();
|
||||
verticalFill.fill = GridBagConstraints.VERTICAL;
|
||||
verticalFill.weighty = 1;
|
||||
verticalFill.gridx = 0;
|
||||
verticalFill.gridy = row++;
|
||||
add(Box.createVerticalGlue(), verticalFill);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the widths of all library panels in this library list.
|
||||
*/
|
||||
public void setWidth(int newWidth) {
|
||||
for (Component c : getComponents()) {
|
||||
if (c instanceof LibraryPanel) {
|
||||
((LibraryPanel) c).updateSize(newWidth);
|
||||
}
|
||||
}
|
||||
|
||||
updateLibraryListSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the width and height of this library list based on the sizes of
|
||||
* the library panes it contains.
|
||||
*/
|
||||
private void updateLibraryListSize() {
|
||||
int height = 0;
|
||||
int width = 0;
|
||||
|
||||
for (Component c : getComponents()) {
|
||||
if (c.isVisible()) {
|
||||
if (c instanceof LibraryListPanel) {
|
||||
Dimension d = c.getSize();
|
||||
if (d.width > width) {
|
||||
width = d.width;
|
||||
}
|
||||
height += d.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPreferredSize(new Dimension(width, height));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the foreground color for a component and all of its subcompenents
|
||||
* recursively.
|
||||
*/
|
||||
private static void cascadeForgroundColor(Component component, Color color) {
|
||||
if (component instanceof Container) {
|
||||
for (Component c : ((Container) component).getComponents()) {
|
||||
cascadeForgroundColor(c, color);
|
||||
}
|
||||
}
|
||||
if (component instanceof JLabel || component instanceof JTextComponent) {
|
||||
component.setForeground(color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the numbers of lines needed to display the text in a JTextArea given
|
||||
* a width as a contained. This assumed that both word wrap and wrap-style
|
||||
* word are enabled for the JTextArea.
|
||||
*/
|
||||
private static int lineCount(JTextArea textArea, int width) {
|
||||
AttributedString text = new AttributedString(textArea.getText());
|
||||
FontRenderContext frc = textArea.getFontMetrics(textArea.getFont())
|
||||
.getFontRenderContext();
|
||||
AttributedCharacterIterator charIt = text.getIterator();
|
||||
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
|
||||
lineMeasurer.setPosition(charIt.getBeginIndex());
|
||||
|
||||
// Get lines from lineMeasurer until the entire
|
||||
// paragraph has been displayed.
|
||||
int noLines = 0;
|
||||
while (lineMeasurer.getPosition() < charIt.getEndIndex()) {
|
||||
lineMeasurer.nextLayout(width);
|
||||
noLines++;
|
||||
}
|
||||
|
||||
return noLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the height in pixels of the text in a JTextArea given a width
|
||||
* as a contained. This assumed that both word wrap and wrap-style word are
|
||||
* enabled for the JTextArea.
|
||||
*/
|
||||
private static int calculateHeight(JTextArea textArea, int width) {
|
||||
Font font = textArea.getFont();
|
||||
FontMetrics fontMetrics = textArea.getFontMetrics(font);
|
||||
int lineHeight = fontMetrics.getAscent() + fontMetrics.getDescent();
|
||||
return lineHeight * lineCount(textArea, width);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,10 @@ import java.util.Iterator;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import processing.app.LibraryListPanel.LibraryPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -40,12 +44,8 @@ public class LibraryManager {
|
||||
|
||||
JFrame dialog;
|
||||
|
||||
JLabel uriLabel;
|
||||
|
||||
JTextField libraryUri;
|
||||
|
||||
JButton installButton;
|
||||
|
||||
LibraryListPanel libraryListPane;
|
||||
|
||||
// the calling editor, so updates can be applied
|
||||
|
||||
Editor editor;
|
||||
@@ -60,44 +60,29 @@ public class LibraryManager {
|
||||
|
||||
Base.setIcon(dialog);
|
||||
|
||||
uriLabel = new JLabel("Library URI:");
|
||||
libraryUri = new JTextField(40);
|
||||
installButton = 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("");
|
||||
}
|
||||
};
|
||||
libraryUri.addActionListener(installLibAction);
|
||||
installButton.addActionListener(installLibAction);
|
||||
|
||||
Container pane = dialog.getContentPane();
|
||||
BoxLayout boxLayout = new BoxLayout(pane, BoxLayout.Y_AXIS);
|
||||
pane.setLayout(boxLayout);
|
||||
|
||||
Box horizontal = Box.createHorizontalBox();
|
||||
horizontal.add(Box.createVerticalStrut(2));
|
||||
horizontal.add(uriLabel);
|
||||
uriLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
horizontal.add(Box.createVerticalStrut(5));
|
||||
|
||||
horizontal.add(libraryUri);
|
||||
horizontal.add(installButton);
|
||||
|
||||
pane.add(horizontal);
|
||||
|
||||
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
|
||||
pane.setBackground(Color.red);
|
||||
|
||||
libraryListPane = new LibraryListPanel(fetchLibraryInfo());
|
||||
|
||||
final JScrollPane scrollPane = new JScrollPane();
|
||||
scrollPane.setViewportView(libraryListPane);
|
||||
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
||||
pane.add(scrollPane);
|
||||
scrollPane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
scrollPane.getViewport().addChangeListener(new ChangeListener() {
|
||||
|
||||
public void stateChanged(ChangeEvent ce) {
|
||||
|
||||
int width = scrollPane.getViewportBorderBounds().width;
|
||||
libraryListPane.setWidth(width);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setMinimumSize(new Dimension(400, 400));
|
||||
dialog.pack();
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
dialog.setLocation((screen.width - dialog.getWidth()) / 2,
|
||||
@@ -284,5 +269,52 @@ public class LibraryManager {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder function which returns a list of information on libraries.
|
||||
*/
|
||||
public ArrayList<LibraryInfo> fetchLibraryInfo() {
|
||||
ArrayList<LibraryInfo> libInfos = new ArrayList<LibraryInfo>();
|
||||
|
||||
LibraryInfo libInfo = new LibraryInfo();
|
||||
libInfo.name = "BlobDetection";
|
||||
libInfo.briefOverview = "Performs the computer vision technique of finding \"blobs\" in an image.";
|
||||
libInfo.isInstalled = true;
|
||||
libInfo.tags.add("blob");
|
||||
libInfo.tags.add("vision");
|
||||
libInfo.tags.add("image");
|
||||
libInfos.add(libInfo);
|
||||
|
||||
libInfo = new LibraryInfo();
|
||||
libInfo.name = "OpenCV";
|
||||
libInfo.briefOverview = "An OpenCV implementation for processing including blob detection, face recognition and more. This library is highly recommended.";
|
||||
libInfo.isInstalled = false;
|
||||
libInfo.tags.add("face");
|
||||
libInfo.tags.add("vision");
|
||||
libInfo.tags.add("image");
|
||||
libInfos.add(libInfo);
|
||||
|
||||
libInfo = new LibraryInfo();
|
||||
libInfo.name = "SQLibrary";
|
||||
libInfo.briefOverview = "A library to facilitate communication with MySQL or SQLite databases.";
|
||||
libInfo.isInstalled = false;
|
||||
libInfo.tags.add("database");
|
||||
libInfos.add(libInfo);
|
||||
|
||||
return libInfos;
|
||||
}
|
||||
|
||||
static class LibraryInfo {
|
||||
String name;
|
||||
String briefOverview;
|
||||
String version;
|
||||
String url;
|
||||
ArrayList<String> tags;
|
||||
boolean isInstalled;
|
||||
|
||||
public LibraryInfo() {
|
||||
tags = new ArrayList<String>();
|
||||
isInstalled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user