1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-30 16:24:09 +03:00

Library installer UI

This commit is contained in:
Cristian Maglie
2014-05-16 01:11:47 +02:00
committed by Federico Fissore
parent 0b9223c158
commit 0755c7c004
15 changed files with 1314 additions and 166 deletions

View File

@ -0,0 +1,293 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.libraries.contributions.ui;
import static processing.app.I18n._;
import static processing.app.I18n.format;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractCellEditor;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.StyleSheet;
import processing.app.Base;
import cc.arduino.libraries.contributions.ContributedLibrary;
import cc.arduino.libraries.contributions.ui.LibrariesIndexTableModel.ContributedLibraryReleases;
@SuppressWarnings("serial")
public class ContributedLibraryTableCell extends AbstractCellEditor implements
TableCellEditor, TableCellRenderer {
private JPanel panel;
private JTextPane description;
private JButton installButton;
private JButton removeButton;
private Component removeButtonPlaceholder;
private Component installButtonPlaceholder;
public ContributedLibraryTableCell() {
description = new JTextPane();
description.setInheritsPopupMenu(true);
Insets margin = description.getMargin();
margin.bottom = 0;
description.setMargin(margin);
description.setContentType("text/html");
Document doc = description.getDocument();
if (doc instanceof HTMLDocument) {
HTMLDocument html = (HTMLDocument) doc;
StyleSheet stylesheet = html.getStyleSheet();
stylesheet.addRule("body { margin: 0; padding: 0;"
+ "font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;"
+ "font-size: 100%;" + "font-size: 0.95em; }");
}
description.setOpaque(false);
description.setBorder(new EmptyBorder(4, 7, 7, 7));
description.setHighlighter(null);
description.setEditable(false);
description.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
Base.openURL(e.getDescription());
}
}
});
{
installButton = new JButton(_("Install"));
installButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onInstall(editorValue.getSelected());
}
});
int width = installButton.getPreferredSize().width;
installButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1));
}
{
removeButton = new JButton(_("Remove"));
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onRemove(editorValue.getInstalled());
}
});
int width = removeButton.getPreferredSize().width;
removeButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1));
}
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(description);
panel.add(Box.createHorizontalStrut(5));
panel.add(installButton);
panel.add(installButtonPlaceholder);
panel.add(Box.createHorizontalStrut(5));
panel.add(removeButton);
panel.add(removeButtonPlaceholder);
panel.add(Box.createHorizontalStrut(5));
}
protected void onRemove(ContributedLibrary contributedPlatform) {
// Empty
}
protected void onInstall(ContributedLibrary contributedPlatform) {
// Empty
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected,
boolean hasFocus, int row,
int column) {
parentTable = table;
return getUpdatedCellComponent(value, isSelected, row);
}
private ContributedLibraryReleases editorValue;
private JTable parentTable;
@Override
public Object getCellEditorValue() {
return editorValue;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row,
int column) {
parentTable = table;
editorValue = (ContributedLibraryReleases) value;
return getUpdatedCellComponent(value, true, row);
}
private Component getUpdatedCellComponent(Object value, boolean isSelected,
int row) {
ContributedLibraryReleases releases = (ContributedLibraryReleases) value;
ContributedLibrary selectedLib = releases.getSelected();
ContributedLibrary installedLib = releases.getInstalled();
boolean removable, installable, upgradable;
if (installedLib == null) {
installable = true;
removable = false;
upgradable = false;
} else {
installable = false;
removable = !installedLib.isReadOnly();
upgradable = (selectedLib != installedLib);
}
if (installable)
installButton.setText(_("Install"));
if (upgradable)
installButton.setText(_("Upgrade"));
installButton.setVisible(installable || upgradable);
installButtonPlaceholder.setVisible(!(installable || upgradable));
removeButton.setVisible(removable);
removeButtonPlaceholder.setVisible(!removable);
String name = selectedLib.getName();
String author = selectedLib.getAuthor();
// String maintainer = selectedLib.getMaintainer();
String website = selectedLib.getWebsite();
String sentence = selectedLib.getSentence();
String paragraph = selectedLib.getParagraph();
String availableVer = selectedLib.getVersion();
String url = selectedLib.getUrl();
String midcolor = isSelected ? "#000000" : "#888888";
String desc = "<html><body>";
// Library name
desc += format("<b><font size=\"+1\">{0}</font></b>", name);
desc += format("<font color=\"{0}\">", midcolor);
if (author != null && !author.isEmpty()) {
desc += format(" by <a href=\"{0}\">{1}</a>", website, author);
}
desc += "<br />";
if (sentence != null) {
desc += format("<b>{0}</b><br />", sentence);
if (paragraph != null && !paragraph.isEmpty())
desc += format("{0}<br />", paragraph);
desc += "<br />";
}
desc += "</font>"; // close midcolor
// If the selected lib is available from repository...
if (url != null) {
desc += format(_("Available version: <b>{0}</b>"), availableVer);
removeButton.setText(_("Remove"));
} else {
removeButton.setText(_("Delete"));
}
desc += "<br />";
if (installedLib != null) {
String installedVer = installedLib.getVersion();
if (installedVer == null)
installedVer = "Legacy";
desc += format(_("Installed version: <b>{0}</b>"), installedVer);
if (installedLib.isReadOnly())
desc += " " + _("(Bundled)");
}
desc += "<br />";
desc += "</body></html>";
description.setText(desc);
description.setBackground(Color.WHITE);
try {
// for modelToView to work, the text area has to be sized. It doesn't
// matter if it's visible or not.
// See:
// http://stackoverflow.com/questions/3081210/how-to-set-jtextarea-to-have-height-that-matches-the-size-of-a-text-it-contains
int width = parentTable.getBounds().width;
width -= installButtonPlaceholder.getPreferredSize().width;
width -= removeButtonPlaceholder.getPreferredSize().width;
Dimension minimalSize = new Dimension(width, 10);
description.setPreferredSize(minimalSize);
description.setSize(minimalSize);
Rectangle r = description.modelToView(description.getDocument()
.getLength());
r.height += description.modelToView(0).y; // add margins
Dimension d = new Dimension(minimalSize.width, r.y + r.height);
description.setPreferredSize(d);
} catch (BadLocationException e) {
e.printStackTrace();
}
if (isSelected) {
panel.setBackground(parentTable.getSelectionBackground());
panel.setForeground(parentTable.getSelectionForeground());
} else {
panel.setBackground(parentTable.getBackground());
panel.setForeground(parentTable.getForeground());
}
return panel;
}
void setEnabled(boolean enabled) {
installButton.setEnabled(enabled);
removeButton.setEnabled(enabled);
}
public void invalidate() {
panel.invalidate();
}
}

View File

@ -0,0 +1,278 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.libraries.contributions.ui;
import static cc.arduino.packages.contributions.VersionComparator.VERSION_COMPARATOR;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import cc.arduino.libraries.contributions.ContributedLibrary;
import cc.arduino.libraries.contributions.LibrariesIndexer;
import cc.arduino.packages.contributions.ContributedPackage;
import cc.arduino.packages.contributions.ContributedPlatform;
@SuppressWarnings("serial")
public class LibrariesIndexTableModel extends AbstractTableModel {
public final static int DESCRIPTION_COL = 0;
public static class ContributedLibraryReleases implements
Comparable<ContributedLibraryReleases> {
public ContributedPackage packager;
public String name;
public List<ContributedLibrary> releases = new ArrayList<ContributedLibrary>();
public List<String> versions = new ArrayList<String>();
public ContributedLibrary selected = null;
public ContributedLibraryReleases(ContributedLibrary library) {
name = library.getName();
add(library);
}
public boolean shouldContain(ContributedLibrary lib) {
if (!lib.getName().equals(name))
return false;
return true;
}
public void add(ContributedLibrary library) {
releases.add(library);
versions.add(library.getVersion());
selected = getLatest();
}
public ContributedLibrary getInstalled() {
for (ContributedLibrary lib : releases)
if (lib.isInstalled())
return lib;
return null;
}
public ContributedLibrary getLatest() {
ContributedLibrary latest = null;
for (ContributedLibrary lib : releases) {
if (latest == null)
latest = lib;
// TODO a better version compare
if (VERSION_COMPARATOR.compare(lib.getVersion(), latest.getVersion()) > 0)
latest = lib;
}
return latest;
}
public ContributedLibrary getSelected() {
return selected;
}
public void selectVersion(String version) {
for (ContributedLibrary lib : releases) {
if (lib.getVersion().equals(version)) {
selected = lib;
return;
}
}
}
public void select(ContributedLibrary value) {
for (ContributedLibrary plat : releases) {
if (plat == value) {
selected = plat;
return;
}
}
}
@Override
public int compareTo(ContributedLibraryReleases o) {
return name.compareToIgnoreCase(o.name);
}
}
private List<ContributedLibraryReleases> contributions = new ArrayList<ContributedLibraryReleases>();
private String[] columnNames = { "Description" };
private Class<?>[] columnTypes = { ContributedPlatform.class };
private LibrariesIndexer indexer;
public void setIndexer(LibrariesIndexer _index) {
indexer = _index;
}
String selectedCategory = null;
String selectedFilters[] = null;
public void updateIndexFilter(String category, String filters[]) {
selectedCategory = category;
selectedFilters = filters;
update();
}
/**
* Check if <b>string</b> contains all the substrings in <b>set</b>. The
* compare is case insensitive.
*
* @param string
* @param set
* @return <b>true<b> if all the strings in <b>set</b> are contained in
* <b>string</b>.
*/
private boolean stringContainsAll(String string, String set[]) {
if (set == null)
return true;
for (String s : set) {
if (!string.toLowerCase().contains(s.toLowerCase()))
return false;
}
return true;
}
private void addContribution(ContributedLibrary lib) {
for (ContributedLibraryReleases contribution : contributions) {
if (!contribution.shouldContain(lib))
continue;
contribution.add(lib);
return;
}
contributions.add(new ContributedLibraryReleases(lib));
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return contributions.size();
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Class<?> getColumnClass(int colum) {
return columnTypes[colum];
}
@Override
public void setValueAt(Object value, int row, int col) {
if (col == DESCRIPTION_COL) {
fireTableCellUpdated(row, col);
}
}
@Override
public Object getValueAt(int row, int col) {
ContributedLibraryReleases contribution = contributions.get(row);
if (col == DESCRIPTION_COL) {
return contribution;// .getSelected();
}
return null;
}
@Override
public boolean isCellEditable(int row, int col) {
return col == DESCRIPTION_COL;
}
public List<String> getReleasesVersions(int row) {
return contributions.get(row).versions;
}
public ContributedLibraryReleases getReleases(int row) {
return contributions.get(row);
}
public ContributedLibrary getSelectedRelease(int row) {
return contributions.get(row).getSelected();
}
public void update() {
updateContributions();
fireTableDataChanged();
}
private void applyFilterToLibrary(ContributedLibrary lib) {
if (selectedCategory != null && !selectedCategory.isEmpty()) {
if (lib.getCategory() == null ||
!lib.getCategory().equals(selectedCategory))
return;
}
if (!stringContainsAll(lib.getName(), selectedFilters))
return;
addContribution(lib);
}
public void updateLibrary(ContributedLibrary lib) {
// Find the row interested in the change
int row = -1;
for (ContributedLibraryReleases releases : contributions) {
if (releases.shouldContain(lib))
row = contributions.indexOf(releases);
}
updateContributions();
// If the library is found in the list send update event
// or insert event on the specific row...
for (ContributedLibraryReleases releases : contributions) {
if (releases.shouldContain(lib)) {
if (row == -1) {
row = contributions.indexOf(releases);
fireTableRowsInserted(row, row);
} else {
fireTableRowsUpdated(row, row);
}
return;
}
}
// ...otherwise send a row deleted event
fireTableRowsDeleted(row, row);
}
private void updateContributions() {
contributions.clear();
for (ContributedLibrary l : indexer.getIndex().getLibraries())
applyFilterToLibrary(l);
for (ContributedLibrary l : indexer.getInstalledLibraries())
applyFilterToLibrary(l);
Collections.sort(contributions);
}
}

View File

@ -0,0 +1,145 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.libraries.contributions.ui;
import static processing.app.I18n._;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import processing.app.helpers.FileUtils;
import cc.arduino.libraries.contributions.ContributedLibrary;
import cc.arduino.libraries.contributions.LibrariesIndexer;
import cc.arduino.packages.contributions.DownloadableContributionsDownloader;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
import cc.arduino.utils.Progress;
public class LibraryInstaller {
private LibrariesIndexer indexer;
private File stagingFolder;
private DownloadableContributionsDownloader downloader;
public LibraryInstaller(LibrariesIndexer _indexer) {
indexer = _indexer;
stagingFolder = _indexer.getStagingFolder();
downloader = new DownloadableContributionsDownloader(stagingFolder) {
@Override
protected void onProgress(Progress progress) {
LibraryInstaller.this.onProgress(progress);
};
};
}
public void updateIndex() throws Exception {
final MultiStepProgress progress = new MultiStepProgress(2);
// Step 1: Download index
URL url = new URL("http://arduino.cc/library_index.json");
File outputFile = indexer.getIndexFile();
File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp");
try {
downloader.download(url, tmpFile, progress,
_("Downloading libraries index..."));
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
}
progress.stepDone();
// TODO: Check downloaded index
// Replace old index with the updated one
if (outputFile.exists())
outputFile.delete();
if (!tmpFile.renameTo(outputFile))
throw new Exception(
_("An error occurred while updating libraries index!"));
// Step 2: Rescan index
rescanLibraryIndex(progress);
}
public void install(ContributedLibrary lib) throws Exception {
if (lib.isInstalled())
throw new Exception(_("Library is already installed!"));
final MultiStepProgress progress = new MultiStepProgress(3);
// Step 1: Download library
try {
downloader.download(lib, progress, _("Downloading library."));
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
}
// TODO: Extract to temporary folders and move to the final destination only
// once everything is successfully unpacked. If the operation fails remove
// all the temporary folders and abort installation.
// Step 2: Unpack library on the correct location
progress.setStatus(_("Installing library..."));
onProgress(progress);
File destFolder = new File(indexer.getSketchbookLibrariesFolder(), lib.getName());
destFolder.mkdirs();
ArchiveExtractor.extract(lib.getDownloadedFile(), destFolder, 1);
progress.stepDone();
// Step 3: Rescan index
rescanLibraryIndex(progress);
}
public void remove(ContributedLibrary lib) throws IOException {
final MultiStepProgress progress = new MultiStepProgress(2);
// Step 1: Remove library
progress.setStatus(_("Removing library..."));
onProgress(progress);
FileUtils.recursiveDelete(lib.getInstalledFolder());
progress.stepDone();
// Step 2: Rescan index
rescanLibraryIndex(progress);
}
private void rescanLibraryIndex(MultiStepProgress progress)
throws IOException {
progress.setStatus(_("Updating list of installed libraries"));
onProgress(progress);
indexer.rescanLibraries();
progress.stepDone();
}
protected void onProgress(Progress progress) {
// Empty
}
}

View File

@ -0,0 +1,381 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.libraries.contributions.ui;
import static cc.arduino.packages.contributions.ui.ContributionIndexTableModel.DESCRIPTION_COL;
import static processing.app.I18n._;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import processing.app.Theme;
import cc.arduino.libraries.contributions.ContributedLibrary;
import cc.arduino.libraries.contributions.LibrariesIndexer;
import cc.arduino.ui.FilterJTextField;
import cc.arduino.ui.ProgressJProgressBar;
import cc.arduino.utils.Progress;
@SuppressWarnings("serial")
public class LibraryManagerUI extends JDialog {
private FilterJTextField filterField;
private JLabel categoryLabel;
private JComboBox categoryChooser;
private Component categoryStrut1;
private Component categoryStrut2;
private Component categoryStrut3;
private LibrariesIndexTableModel contribModel = new LibrariesIndexTableModel();
private JTable contribTable;
private ProgressJProgressBar progressBar;
private Box progressBox;
private Box updateBox;
private ContributedLibraryTableCell cellEditor;
// Currently selected category and filters
private String category;
private String[] filters;
public LibraryManagerUI(Frame parent) {
super(parent, "Library Manager", Dialog.ModalityType.APPLICATION_MODAL);
setResizable(true);
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
{
categoryStrut1 = Box.createHorizontalStrut(5);
categoryStrut2 = Box.createHorizontalStrut(5);
categoryStrut3 = Box.createHorizontalStrut(5);
categoryLabel = new JLabel(_("Category:"));
categoryChooser = new JComboBox();
categoryChooser.setMaximumRowCount(20);
categoryChooser.setEnabled(false);
filterField = new FilterJTextField(_("Filter your search...")) {
@Override
protected void onFilter(String[] _filters) {
filters = _filters;
cellEditor.stopCellEditing();
contribModel.updateIndexFilter(category, filters);
}
};
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(categoryStrut1);
panel.add(categoryLabel);
panel.add(categoryStrut2);
panel.add(categoryChooser);
panel.add(categoryStrut3);
panel.add(filterField);
panel.setBorder(new EmptyBorder(7, 7, 7, 7));
pane.add(panel, BorderLayout.NORTH);
}
contribTable = new JTable(contribModel);
contribTable.setTableHeader(null);
contribTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
contribTable.setColumnSelectionAllowed(false);
contribTable.setDragEnabled(false);
contribTable.setIntercellSpacing(new Dimension(0, 1));
contribTable.setShowVerticalLines(false);
contribTable.setSelectionBackground(Theme.getColor("status.notice.bgcolor"));
{
TableColumnModel tcm = contribTable.getColumnModel();
TableColumn col = tcm.getColumn(DESCRIPTION_COL);
col.setCellRenderer(new ContributedLibraryTableCell());
cellEditor = new ContributedLibraryTableCell() {
@Override
protected void onInstall(ContributedLibrary selectedPlatform) {
onInstallPressed(selectedPlatform);
}
@Override
protected void onRemove(ContributedLibrary installedPlatform) {
onRemovePressed(installedPlatform);
}
};
col.setCellEditor(cellEditor);
col.setResizable(true);
}
{
JScrollPane s = new JScrollPane();
s.setViewportView(contribTable);
s.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
s.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
pane.add(s, BorderLayout.CENTER);
}
pane.add(Box.createHorizontalStrut(10), BorderLayout.WEST);
pane.add(Box.createHorizontalStrut(10), BorderLayout.EAST);
{
progressBar = new ProgressJProgressBar();
progressBar.setStringPainted(true);
progressBar.setString(" ");
progressBar.setVisible(true);
JButton cancelButton = new JButton(_("Cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
onCancelPressed();
}
});
JButton updateButton = new JButton(_("Update list"));
updateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
onUpdatePressed();
}
});
{
progressBox = Box.createHorizontalBox();
progressBox.add(progressBar);
progressBox.add(Box.createHorizontalStrut(5));
progressBox.add(cancelButton);
updateBox = Box.createHorizontalBox();
updateBox.add(Box.createHorizontalGlue());
updateBox.add(updateButton);
JPanel progressPanel = new JPanel();
progressPanel.setBorder(new EmptyBorder(7, 7, 7, 7));
progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));
progressPanel.add(progressBox);
progressPanel.add(updateBox);
pane.add(progressPanel, BorderLayout.SOUTH);
setProgressVisible(false);
}
}
setMinimumSize(new Dimension(600, 450));
}
private TableModelListener tableModelListener = new TableModelListener() {
@Override
public void tableChanged(final TableModelEvent arg0) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updateCellsHeight(arg0);
}
});
}
};
public void setIndexer(LibrariesIndexer indexer) {
contribModel.removeTableModelListener(tableModelListener);
categoryChooser.removeActionListener(categoryChooserActionListener);
contribModel.setIndexer(indexer);
category = null;
categoryChooser.removeAllItems();
contribModel.addTableModelListener(tableModelListener);
categoryChooser.addActionListener(categoryChooserActionListener);
// Load categories
Collection<String> categories = indexer.getIndex().getCategories();
categoryChooser.addItem("");
for (String s : categories)
categoryChooser.addItem(s);
// Enable categories combo only if there are two or more choices
int count = categoryChooser.getItemCount();
categoryChooser.setEnabled(count > 1);
filterField.setEnabled(contribModel.getRowCount() > 0);
// Create LibrariesInstaller tied with the provided index
installer = new LibraryInstaller(indexer) {
@Override
public void onProgress(Progress progress) {
setProgress(progress);
}
};
}
ActionListener categoryChooserActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
String selected = (String) categoryChooser.getSelectedItem();
if (category == null || !category.equals(selected)) {
category = selected;
cellEditor.stopCellEditing();
contribModel.updateIndexFilter(category, filters);
}
}
};
public void setProgressVisible(boolean visible) {
progressBox.setVisible(visible);
filterField.setEnabled(!visible);
categoryChooser.setEnabled(!visible);
contribTable.setEnabled(!visible);
updateBox.setVisible(!visible);
updateBox.setEnabled(!visible);
cellEditor.setEnabled(!visible);
if (visible && contribTable.isEditing()) {
TableCellEditor editor = contribTable.getCellEditor();
if (editor != null)
editor.stopCellEditing();
}
}
private void updateCellsHeight(TableModelEvent e) {
int first = e.getFirstRow();
int last = Math.min(e.getLastRow(), contribTable.getRowCount() - 1);
for (int row = first; row <= last; row++) {
TableCellRenderer editor = new ContributedLibraryTableCell();
Component comp = contribTable.prepareRenderer(editor, row, 0);
int height = comp.getPreferredSize().height;
contribTable.setRowHeight(row, height);
}
}
public void setProgress(Progress progress) {
progressBar.setValue(progress);
}
/*
* Installer methods follows
*/
private LibraryInstaller installer;
private Thread installerThread = null;
public void onCancelPressed() {
if (installerThread != null)
installerThread.interrupt();
}
public void onUpdatePressed() {
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true);
installer.updateIndex();
onIndexesUpdated();
} catch (Exception e) {
// TODO Show ERROR
e.printStackTrace();
} finally {
setProgressVisible(false);
}
}
});
installerThread.start();
}
public void onInstallPressed(final ContributedLibrary lib) {
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true);
installer.install(lib);
contribModel.updateLibrary(lib);
} catch (Exception e) {
// TODO Show ERROR
e.printStackTrace();
} finally {
setProgressVisible(false);
}
}
});
installerThread.start();
}
public void onRemovePressed(final ContributedLibrary lib) {
installerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
setProgressVisible(true);
installer.remove(lib);
contribModel.updateLibrary(lib);
} catch (Exception e) {
// TODO Show ERROR
e.printStackTrace();
} finally {
setProgressVisible(false);
}
}
});
installerThread.start();
}
protected void onIndexesUpdated() throws Exception {
// Empty
}
}

View File

@ -48,7 +48,6 @@ import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
@ -65,6 +64,9 @@ import javax.swing.table.TableColumnModel;
import cc.arduino.packages.contributions.ContributedPlatform;
import cc.arduino.packages.contributions.ContributionInstaller;
import cc.arduino.packages.contributions.ContributionsIndexer;
import cc.arduino.ui.FilterJTextField;
import cc.arduino.ui.ProgressJProgressBar;
import cc.arduino.utils.Progress;
@SuppressWarnings("serial")
public class ContributionManagerUI extends JDialog {
@ -79,7 +81,7 @@ public class ContributionManagerUI extends JDialog {
private ContributionIndexTableModel contribModel = new ContributionIndexTableModel();
private JTable contribTable;
private JProgressBar progressBar;
private ProgressJProgressBar progressBar;
private Box progressBox;
private Box updateBox;
@ -169,7 +171,7 @@ public class ContributionManagerUI extends JDialog {
pane.add(Box.createHorizontalStrut(10), BorderLayout.EAST);
{
progressBar = new JProgressBar();
progressBar = new ProgressJProgressBar();
progressBar.setStringPainted(true);
progressBar.setString(" ");
progressBar.setVisible(true);
@ -249,13 +251,12 @@ public class ContributionManagerUI extends JDialog {
categoryChooser.addItem(s);
// Create ConstributionInstaller tied with the provided index
installer = new ContributionInstaller(indexer);
installer.setListener(new ContributionInstaller.Listener() {
installer = new ContributionInstaller(indexer) {
@Override
public void onProgress(double progress, String message) {
setProgress((int) progress, message);
public void onProgress(Progress progress) {
setProgress(progress);
}
});
};
}
ActionListener categoryChooserActionListener = new ActionListener() {
@ -298,10 +299,8 @@ public class ContributionManagerUI extends JDialog {
}
}
public void setProgress(int progress, String text) {
public void setProgress(Progress progress) {
progressBar.setValue(progress);
if (text != null)
progressBar.setString(text);
}
/*

View File

@ -26,7 +26,7 @@
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.packages.contributions.ui;
package cc.arduino.ui;
import java.awt.Color;
import java.awt.Font;

View File

@ -22,15 +22,7 @@
package processing.app;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import cc.arduino.libraries.contributions.LibrariesIndexer;
import cc.arduino.libraries.contributions.ui.LibraryManagerUI;
import cc.arduino.packages.DiscoveryManager;
import cc.arduino.packages.contributions.ui.ContributionManagerUI;
import cc.arduino.view.SplashScreenHelper;
@ -43,7 +35,6 @@ import processing.app.helpers.filefilters.OnlyFilesWithExtension;
import processing.app.javax.swing.filechooser.FileNameExtensionFilter;
import processing.app.legacy.PApplet;
import processing.app.macosx.ThinkDifferent;
import processing.app.legacy.PConstants;
import processing.app.packages.LibraryList;
import processing.app.packages.UserLibrary;
import processing.app.tools.MenuScroller;
@ -1020,9 +1011,7 @@ public class Base {
}
public LibraryList getIDELibs() {
if (getLibraries() == null)
return new LibraryList();
LibraryList res = new LibraryList(getLibraries());
LibraryList res = new LibraryList(BaseNoGui.librariesIndexer.getInstalledLibraries());
res.removeAll(getUserLibs());
return res;
}
@ -1036,16 +1025,13 @@ public class Base {
return;
importMenu.removeAll();
JMenuItem addLibraryMenuItem = new JMenuItem(_("Add Library..."));
addLibraryMenuItem.addActionListener(new ActionListener() {
JMenuItem menu = new JMenuItem(_("Manage libraries..."));
menu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.this.handleAddLibrary();
Base.this.onBoardOrPortChange();
Base.this.rebuildImportMenu(Editor.importMenu);
Base.this.rebuildExamplesMenu(Editor.examplesMenu);
openManageLibrariesDialog();
}
});
importMenu.add(addLibraryMenuItem);
importMenu.add(menu);
importMenu.addSeparator();
// Split between user supplied libraries and IDE libraries
@ -1116,6 +1102,27 @@ public class Base {
editor.onBoardOrPortChange();
}
private void openManageLibrariesDialog() {
@SuppressWarnings("serial")
LibraryManagerUI managerUI = new LibraryManagerUI(activeEditor) {
@Override
protected void onIndexesUpdated() throws Exception {
BaseNoGui.initPackages();
rebuildBoardsMenu();
onBoardOrPortChange();
setIndexer(BaseNoGui.librariesIndexer);
}
};
managerUI.setIndexer(BaseNoGui.librariesIndexer);
managerUI.setVisible(true);
// Manager dialog is modal, waits here until closed
//handleAddLibrary();
onBoardOrPortChange();
rebuildImportMenu(Editor.importMenu);
rebuildExamplesMenu(Editor.examplesMenu);
}
private void openInstallBoardDialog() {
// Create dialog for contribution manager
@SuppressWarnings("serial")
@ -1693,8 +1700,9 @@ public class Base {
}
// XXX: Remove this method and make librariesIndexer non-static
static public LibraryList getLibraries() {
return BaseNoGui.getLibraries();
return BaseNoGui.librariesIndexer.getInstalledLibraries();
}