From 373a6259031d2e39119f2234f1501be336aacc4b Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 16 May 2014 00:56:22 +0200 Subject: [PATCH] GUI for platform installer, first draft --- .../ContributedPlatformTableCellRenderer.java | 121 +++++++ .../ui/ContributionIndexTableModel.java | 194 +++++++++++ .../ui/JContributionManagerDialog.java | 318 ++++++++++++++++++ .../JContributionManagerDialogListener.java | 41 +++ .../ui/VersionInstalledTableCellEditor.java | 112 ++++++ .../ui/VersionInstalledTableCellRenderer.java | 92 +++++ .../ui/VersionSelectorTableCellEditor.java | 145 ++++++++ .../ui/VersionSelectorTableCellRenderer.java | 120 +++++++ app/src/processing/app/Base.java | 44 ++- .../contributions/ContributionsIndexer.java | 12 + .../src/processing/app/BaseNoGui.java | 5 +- 11 files changed, 1199 insertions(+), 5 deletions(-) create mode 100644 app/src/cc/arduino/packages/contributions/ui/ContributedPlatformTableCellRenderer.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/ContributionIndexTableModel.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellEditor.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellRenderer.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellEditor.java create mode 100644 app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellRenderer.java diff --git a/app/src/cc/arduino/packages/contributions/ui/ContributedPlatformTableCellRenderer.java b/app/src/cc/arduino/packages/contributions/ui/ContributedPlatformTableCellRenderer.java new file mode 100644 index 000000000..25b566826 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/ContributedPlatformTableCellRenderer.java @@ -0,0 +1,121 @@ +/* + * 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.packages.contributions.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Insets; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTextPane; +import javax.swing.border.EmptyBorder; +import javax.swing.table.TableCellRenderer; +import javax.swing.text.Document; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.StyleSheet; + +import cc.arduino.packages.contributions.ContributedBoard; +import cc.arduino.packages.contributions.ContributedPlatform; + +@SuppressWarnings("serial") +public class ContributedPlatformTableCellRenderer extends JPanel implements + TableCellRenderer { + + private JTextPane description; + + public ContributedPlatformTableCellRenderer() { + super(); + + // Align contents to the left + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setAlignmentX(Component.LEFT_ALIGNMENT); + + description = new JTextPane(); + description.setInheritsPopupMenu(true); + Insets margin = description.getMargin(); + margin.bottom = 0; + description.setMargin(margin); + description.setContentType("text/html"); + setTextStyle(description); + description.setOpaque(false); + description.setBorder(new EmptyBorder(4, 7, 7, 7)); + description.setHighlighter(null); + add(description); + } + + static void setTextStyle(JTextPane textPane) { + Document doc = textPane.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; }"); + } + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) { + ContributedPlatform contrib = (ContributedPlatform) value; + + String descriptionText = "" + contrib.getName() + ""; + String authorList = "arduino"; // contrib.getAuthorList(); + if (authorList != null && !authorList.isEmpty()) { + descriptionText += " by Arduino"; + } + descriptionText += "

"; + + descriptionText += "Boards contributed in this package:
"; + for (ContributedBoard board : contrib.getBoards()) + descriptionText += "- " + board.getName() + "
"; + // descriptionText += "
Available version: 1.5.5
"; + // descriptionText += "Installed version: 1.5.4
"; + descriptionText += ""; + description.setText(descriptionText); + description.setBackground(Color.WHITE); + description.setVisible(true); + + int h = getPreferredSize().height; + if (table.getRowHeight(row) != h) + table.setRowHeight(row, h); + + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + return this; + } +} diff --git a/app/src/cc/arduino/packages/contributions/ui/ContributionIndexTableModel.java b/app/src/cc/arduino/packages/contributions/ui/ContributionIndexTableModel.java new file mode 100644 index 000000000..0999480a5 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/ContributionIndexTableModel.java @@ -0,0 +1,194 @@ +/* + * 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.packages.contributions.ui; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.table.AbstractTableModel; + +import cc.arduino.packages.contributions.ContributedPackage; +import cc.arduino.packages.contributions.ContributedPlatform; +import cc.arduino.packages.contributions.ContributionsIndex; + +@SuppressWarnings("serial") +public class ContributionIndexTableModel extends AbstractTableModel { + + public final static int DESCRIPTION_COL = 0; + public final static int VERSION_COL = 1; + public final static int INSTALLED_COL = 2; + + public static class ContributedPlatformReleases { + public ContributedPackage packager; + public String arch; + public List releases = new ArrayList(); + public List versions = new ArrayList(); + public ContributedPlatform selected = null; + + public ContributedPlatformReleases(ContributedPlatform platform) { + packager = platform.getParentPackage(); + arch = platform.getArchitecture(); + add(platform); + } + + public boolean shouldContain(ContributedPlatform platform) { + if (platform.getParentPackage() != packager) + return false; + if (!platform.getArchitecture().equals(arch)) + return false; + return true; + } + + public void add(ContributedPlatform platform) { + releases.add(platform); + versions.add(platform.getVersion()); + selected = getLatest(); + } + + public ContributedPlatform getInstalled() { + for (ContributedPlatform plat : releases) + if (plat.isInstalled()) + return plat; + return null; + } + + public ContributedPlatform getLatest() { + ContributedPlatform latest = null; + for (ContributedPlatform plat : releases) { + if (latest == null) + latest = plat; + if (plat.getVersion().compareTo(latest.getVersion()) > 0) + latest = plat; + } + return latest; + } + + public ContributedPlatform getSelected() { + return selected; + } + + public void selectVersion(String version) { + for (ContributedPlatform plat : releases) { + if (plat.getVersion().equals(version)) { + selected = plat; + return; + } + } + } + } + + private List contributions = new ArrayList(); + + private String[] m_colNames = { "Description", "Available", "Installed" }; + + private Class[] m_colTypes = { ContributedPlatform.class, Object[].class, + String.class }; + + public void updateIndex(ContributionsIndex index) { + contributions.clear(); + for (ContributedPackage pack : index.getPackages()) { + for (ContributedPlatform platform : pack.getPlatforms()) { + addContribution(platform); + } + } + } + + private void addContribution(ContributedPlatform platform) { + for (ContributedPlatformReleases contribution : contributions) { + if (!contribution.shouldContain(platform)) + continue; + contribution.add(platform); + return; + } + + contributions.add(new ContributedPlatformReleases(platform)); + } + + @Override + public int getColumnCount() { + return m_colNames.length; + } + + @Override + public int getRowCount() { + return contributions.size(); + } + + @Override + public String getColumnName(int column) { + return m_colNames[column]; + } + + @Override + public Class getColumnClass(int col) { + return m_colTypes[col]; + } + + @Override + public void setValueAt(Object value, int row, int col) { + if (col == VERSION_COL) { + contributions.get(row).selectVersion((String) value); + fireTableCellUpdated(row, col); + } + } + + @Override + public Object getValueAt(int row, int col) { + ContributedPlatformReleases contribution = contributions.get(row); + ContributedPlatform installed = contribution.getInstalled(); + if (col == DESCRIPTION_COL) { + return contribution.getSelected(); + } + if (col == VERSION_COL) { + return contribution.getSelected().getVersion(); + } + if (col == INSTALLED_COL) { + return installed == null ? "-" : installed.getVersion(); + } + return null; + } + + @Override + public boolean isCellEditable(int row, int col) { + return col == VERSION_COL || col == INSTALLED_COL; + } + + public List getReleasesVersions(int row) { + return contributions.get(row).versions; + } + + public ContributedPlatformReleases getReleases(int row) { + return contributions.get(row); + } + + public ContributedPlatform getSelectedRelease(int row) { + return contributions.get(row).getSelected(); + } + +} diff --git a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java b/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java new file mode 100644 index 000000000..370277a42 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java @@ -0,0 +1,318 @@ +/* + * 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.packages.contributions.ui; + +import static cc.arduino.packages.contributions.ui.ContributionIndexTableModel.DESCRIPTION_COL; +import static cc.arduino.packages.contributions.ui.ContributionIndexTableModel.INSTALLED_COL; +import static cc.arduino.packages.contributions.ui.ContributionIndexTableModel.VERSION_COL; +import static processing.app.I18n._; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.swing.Box; +import javax.swing.BoxLayout; +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.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.ScrollPaneConstants; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +import cc.arduino.packages.contributions.ContributedPlatform; +import cc.arduino.packages.contributions.ContributionsIndex; + +@SuppressWarnings("serial") +public class JContributionManagerDialog extends JDialog { + + private FilterField filterField; + private JScrollPane scrollPane; + private StatusPanel status; + + private JContributionManagerDialogListener listener = null; + + private String category; + private JLabel categoryLabel; + private JComboBox categoryChooser; + private Component categoryStrut1; + private Component categoryStrut2; + private Component categoryStrut3; + + private ContributionIndexTableModel contribModel = new ContributionIndexTableModel(); + private JTable contribTable; + + public JContributionManagerDialog(Frame parent) { + super(parent, "Boards 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.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + notifyCategoryChange(); + } + }); + + setCategories(new ArrayList()); + + filterField = new FilterField(); + + JPanel filterPanel = new JPanel(); + filterPanel.setLayout(new BoxLayout(filterPanel, BoxLayout.X_AXIS)); + pane.add(filterPanel, BorderLayout.NORTH); + filterPanel.add(categoryStrut1); + filterPanel.add(categoryLabel); + filterPanel.add(categoryStrut2); + filterPanel.add(categoryChooser); + filterPanel.add(categoryStrut3); + filterPanel.add(filterField); + filterPanel.setBorder(new EmptyBorder(7, 7, 7, 7)); + + contribTable = new JTable(contribModel); + // contribTable.setTableHeader(null); + // contribTable.setRowSelectionAllowed(false); + contribTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + contribTable.setColumnSelectionAllowed(false); + contribTable.setDragEnabled(false); + contribTable.setIntercellSpacing(new Dimension(0, 1)); + contribTable.setShowVerticalLines(false); + contribTable.getTableHeader().setEnabled(false); + // contribTable.addMouseListener(new MouseAdapter() { + // @Override + // public void mousePressed(MouseEvent e) { + // if (listener == null) + // return; + // Point point = e.getPoint(); + // int row = contribTable.rowAtPoint(point); + // int col = contribTable.columnAtPoint(point); + // } + // }); + TableColumnModel tcm = contribTable.getColumnModel(); + TableColumn descriptionCol = tcm.getColumn(DESCRIPTION_COL); + TableColumn versionCol = tcm.getColumn(VERSION_COL); + TableColumn installedCol = tcm.getColumn(INSTALLED_COL); + + descriptionCol.setCellRenderer(new ContributedPlatformTableCellRenderer()); + descriptionCol.setResizable(true); + + { + versionCol.setCellRenderer(new VersionSelectorTableCellRenderer()); + VersionSelectorTableCellEditor editor = new VersionSelectorTableCellEditor(); + editor.setListener(new VersionSelectorTableCellEditor.Listener() { + @Override + public void onInstallEvent(int row) { + if (listener == null) + return; + ContributedPlatform selected = contribModel.getSelectedRelease(row); + listener.onInstall(selected); + } + }); + versionCol.setCellEditor(editor); + versionCol.setResizable(false); + versionCol.setWidth(140); + } + + { + installedCol.setCellRenderer(new VersionInstalledTableCellRenderer()); + VersionInstalledTableCellEditor editor = new VersionInstalledTableCellEditor(); + editor.setListener(new VersionInstalledTableCellEditor.Listener() { + @Override + public void onRemoveEvent(int row) { + if (listener == null) + return; + ContributedPlatform installed = contribModel.getReleases(row) + .getInstalled(); + listener.onRemove(installed); + } + }); + installedCol.setCellEditor(editor); + installedCol.setResizable(false); + installedCol.setMaxWidth(70); + } + + scrollPane = new JScrollPane(); + scrollPane.setPreferredSize(new Dimension(300, 300)); + scrollPane.setViewportView(contribTable); + scrollPane + .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + scrollPane + .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + pane.add(scrollPane, BorderLayout.CENTER); + + pane.add(Box.createHorizontalStrut(10), BorderLayout.WEST); + pane.add(Box.createHorizontalStrut(10), BorderLayout.EAST); + + status = new StatusPanel(); + status.setBorder(new EmptyBorder(7, 7, 7, 7)); + pane.add(status, BorderLayout.SOUTH); + + setMinimumSize(new Dimension(450, 400)); + } + + public void setListener(JContributionManagerDialogListener listener) { + this.listener = listener; + } + + public void setCategories(Collection categories) { + category = null; + categoryChooser.removeAllItems(); + for (String s : categories) + categoryChooser.addItem(s); + + // Disable if only one possible choice + boolean single = categories.size() == 1; + categoryChooser.setEnabled(!single); + + // Show if there is at lease one possible choice + boolean show = !categories.isEmpty(); + categoryStrut1.setVisible(show); + categoryLabel.setVisible(show); + categoryStrut2.setVisible(show); + categoryChooser.setVisible(show); + categoryStrut3.setVisible(show); + } + + private synchronized void notifyCategoryChange() { + if (listener == null) + return; + String selected = (String) categoryChooser.getSelectedItem(); + if (category == null || !category.equals(selected)) { + category = selected; + listener.onCategoryChange(category); + } + } + + class FilterField extends JTextField { + final static String filterHint = "Filter your search..."; + boolean showingHint; + List filters; + + public FilterField() { + super(filterHint); + + showingHint = true; + filters = new ArrayList(); + updateStyle(); + + addFocusListener(new FocusListener() { + public void focusLost(FocusEvent focusEvent) { + if (filterField.getText().isEmpty()) { + showingHint = true; + } + updateStyle(); + } + + public void focusGained(FocusEvent focusEvent) { + if (showingHint) { + showingHint = false; + filterField.setText(""); + } + updateStyle(); + } + }); + + getDocument().addDocumentListener(new DocumentListener() { + public void removeUpdate(DocumentEvent e) { + applyFilter(); + } + + public void insertUpdate(DocumentEvent e) { + applyFilter(); + } + + public void changedUpdate(DocumentEvent e) { + applyFilter(); + } + }); + } + + public void applyFilter() { + String filter = filterField.getFilterText(); + filter = filter.toLowerCase(); + + // Replace anything but 0-9, a-z, or : with a space + filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " "); + filters = Arrays.asList(filter.split(" ")); + // filterLibraries(category, filters); + } + + public String getFilterText() { + return showingHint ? "" : getText(); + } + + public void updateStyle() { + if (showingHint) { + setText(filterHint); + setForeground(Color.gray); + setFont(getFont().deriveFont(Font.ITALIC)); + } else { + setForeground(UIManager.getColor("TextField.foreground")); + setFont(getFont().deriveFont(Font.PLAIN)); + } + } + } + + public void addContributions(ContributionsIndex index) { + contribModel.updateIndex(index); + } + +} diff --git a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java b/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java new file mode 100644 index 000000000..2a91aa304 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java @@ -0,0 +1,41 @@ +/* + * 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.packages.contributions.ui; + +import cc.arduino.packages.contributions.ContributedPlatform; + +public interface JContributionManagerDialogListener { + + void onCategoryChange(String category); + + void onInstall(ContributedPlatform selected); + + void onRemove(ContributedPlatform selected); + +} \ No newline at end of file diff --git a/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellEditor.java b/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellEditor.java new file mode 100644 index 000000000..6ac6f9cbd --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellEditor.java @@ -0,0 +1,112 @@ +/* + * 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.packages.contributions.ui; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.AbstractCellEditor; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; + +@SuppressWarnings("serial") +public class VersionInstalledTableCellEditor extends AbstractCellEditor + implements TableCellEditor { + + private JPanel panel; + private JLabel versionLabel; + private JButton button; + + private int currRow; + private Object currValue; + private Listener listener = null; + + public VersionInstalledTableCellEditor() { + versionLabel = new JLabel("-"); + versionLabel.setOpaque(false); + + button = new JButton("Remove"); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (listener == null) + return; + listener.onRemoveEvent(currRow); + } + }); + + panel = new JPanel(); + panel.add(versionLabel); + panel.add(button); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, + int col) { + currRow = row; + currValue = value; + + versionLabel.setText((String) value); + + if (value.equals("-")) { + button.setVisible(false); + } else { + button.setVisible(true); + } + + if (table.getRowSelectionAllowed()) { + panel.setBackground(table.getSelectionBackground()); + panel.setForeground(table.getSelectionForeground()); + } else { + panel.setBackground(table.getBackground()); + panel.setForeground(table.getForeground()); + } + + return panel; + } + + @Override + public Object getCellEditorValue() { + return currValue; + } + + public static interface Listener { + public void onRemoveEvent(int row); + } + + public void setListener(Listener newListener) { + listener = newListener; + } + +} diff --git a/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellRenderer.java b/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellRenderer.java new file mode 100644 index 000000000..5a7ba2ef0 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/VersionInstalledTableCellRenderer.java @@ -0,0 +1,92 @@ +/* + * 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.packages.contributions.ui; + +import java.awt.Component; +import java.awt.Dimension; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +public class VersionInstalledTableCellRenderer implements TableCellRenderer { + + private JPanel panel; + private JLabel versionLabel; + private JButton button; + private int minCellWidth; + + public VersionInstalledTableCellRenderer() { + versionLabel = new JLabel("-"); + versionLabel.setOpaque(false); + + button = new JButton("Remove"); + minCellWidth = button.getPreferredSize().width; + + panel = new JPanel(); + panel.add(versionLabel); + panel.add(button); + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int col) { + versionLabel.setText((String) value); + + Dimension labelSize = versionLabel.getPreferredSize(); + if (minCellWidth < labelSize.width) + minCellWidth = labelSize.width; + TableColumn column = table.getColumnModel().getColumn(col); + if (column.getMinWidth() < minCellWidth + 20) { + column.setMinWidth(minCellWidth + 20); + column.setMaxWidth(minCellWidth + 20); + } + + if (value.equals("-")) { + button.setVisible(false); + } else { + button.setVisible(true); + } + + if (isSelected) { + panel.setBackground(table.getSelectionBackground()); + panel.setForeground(table.getSelectionForeground()); + } else { + panel.setBackground(table.getBackground()); + panel.setForeground(table.getForeground()); + } + + return panel; + } + +} diff --git a/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellEditor.java b/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellEditor.java new file mode 100644 index 000000000..f4820c667 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellEditor.java @@ -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.packages.contributions.ui; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.List; + +import javax.swing.AbstractCellEditor; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; + +import cc.arduino.packages.contributions.ui.ContributionIndexTableModel.ContributedPlatformReleases; + +@SuppressWarnings("serial") +public class VersionSelectorTableCellEditor extends AbstractCellEditor + implements TableCellEditor { + + private JPanel panel; + private JComboBox combo; + private JButton button; + + private int currRow, currCol; + private ContributionIndexTableModel currModel = null; + + private ItemListener itemListener = new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (currModel != null) { + currModel.setValueAt(getCellEditorValue(), currRow, currCol); + updateButtons(); + } + } + }; + + private Listener listener = null; + + public VersionSelectorTableCellEditor() { + panel = new JPanel(); + + combo = new JComboBox(); + combo.setOpaque(false); + combo.addItemListener(itemListener); + panel.add(combo); + + button = new JButton("Install"); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (listener == null) + return; + listener.onInstallEvent(currRow); + } + }); + panel.add(button); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, + int col) { + currCol = col; + currRow = row; + currModel = (ContributionIndexTableModel) table.getModel(); + List values = currModel.getReleasesVersions(row); + + ComboBoxModel model = new DefaultComboBoxModel(values.toArray()); + model.setSelectedItem(currModel.getSelectedRelease(row).getVersion()); + combo.setModel(model); + + updateButtons(); + if (table.getRowSelectionAllowed()) { + panel.setBackground(table.getSelectionBackground()); + panel.setForeground(table.getSelectionForeground()); + } else { + panel.setBackground(table.getBackground()); + panel.setForeground(table.getForeground()); + } + return panel; + } + + private void updateButtons() { + ContributedPlatformReleases releases = currModel.getReleases(currRow); + boolean installed = releases.getInstalled() != null; + if (installed) { + if (releases.getInstalled() != releases.getSelected()) { + button.setText("Upgrade"); + button.setVisible(true); + } else { + button.setVisible(false); + } + } else { + button.setText("Install"); + button.setVisible(true); + } + } + + @Override + public Object getCellEditorValue() { + return combo.getSelectedItem(); + } + + public static interface Listener { + public void onInstallEvent(int row); + } + + public void setListener(Listener newListener) { + listener = newListener; + } + +} diff --git a/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellRenderer.java b/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellRenderer.java new file mode 100644 index 000000000..088cb96cb --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/VersionSelectorTableCellRenderer.java @@ -0,0 +1,120 @@ +/* + * 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.packages.contributions.ui; + +import java.awt.Component; + +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +import cc.arduino.packages.contributions.ui.ContributionIndexTableModel.ContributedPlatformReleases; + +public class VersionSelectorTableCellRenderer implements TableCellRenderer { + + private JPanel panel; + private JComboBox versionComboBox; + private JLabel versionLabel; + private JButton button; + private int minCellWidth; + + public VersionSelectorTableCellRenderer() { + panel = new JPanel(); + + versionComboBox = new JComboBox(); + versionComboBox.setOpaque(false); + panel.add(versionComboBox); + versionComboBox.setVisible(false); + + versionLabel = new JLabel(); + versionLabel.setOpaque(false); + panel.add(versionLabel); + + button = new JButton("Install"); + minCellWidth = button.getPreferredSize().width; + button.setText("Upgrade"); + int buttonWidth = button.getPreferredSize().width; + if (minCellWidth < buttonWidth) + minCellWidth = buttonWidth; + + panel.add(button); + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int col) { + ComboBoxModel comboModel = new DefaultComboBoxModel( + new String[] { (String) value }); + versionComboBox.setModel(comboModel); + + versionLabel.setText((String) value); + + ContributionIndexTableModel model = (ContributionIndexTableModel) table + .getModel(); + ContributedPlatformReleases releases = model.getReleases(row); + + boolean installed = releases.getInstalled() != null; + if (installed) { + if (releases.getInstalled() != releases.getSelected()) { + button.setText("Upgrade"); + button.setVisible(true); + } else { + button.setVisible(false); + } + } else { + button.setText("Install"); + button.setVisible(true); + } + + int labelWidth = versionComboBox.getPreferredSize().width; + if (minCellWidth < labelWidth) + minCellWidth = labelWidth; + TableColumn column = table.getColumnModel().getColumn(col); + if (column.getMinWidth() < minCellWidth + 20) { + column.setMinWidth(minCellWidth + 20); + column.setMaxWidth(minCellWidth + 20); + } + + if (isSelected) { + panel.setBackground(table.getSelectionBackground()); + panel.setForeground(table.getSelectionForeground()); + } else { + panel.setBackground(table.getBackground()); + panel.setForeground(table.getForeground()); + } + return panel; + } +} diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b48da543c..433114f72 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -23,6 +23,9 @@ package processing.app; import cc.arduino.packages.DiscoveryManager; +import cc.arduino.packages.contributions.ContributedPlatform; +import cc.arduino.packages.contributions.ui.JContributionManagerDialog; +import cc.arduino.packages.contributions.ui.JContributionManagerDialogListener; import cc.arduino.view.SplashScreenHelper; import processing.app.debug.TargetBoard; import processing.app.debug.TargetPackage; @@ -1107,13 +1110,48 @@ public class Base { editor.onBoardOrPortChange(); } + private void openInstallBoardDialog() { + JContributionManagerDialog dialog = new JContributionManagerDialog( + activeEditor); + dialog.setListener(new JContributionManagerDialogListener() { + @Override + public void onCategoryChange(String category) { + System.out.println("Selected " + category); + } + + @Override + public void onInstall(ContributedPlatform platform) { + BaseNoGui.indexer.install(platform); + } + + @Override + public void onRemove(ContributedPlatform platform) { + BaseNoGui.indexer.remove(platform); + } + }); + dialog.setCategories(Arrays.asList("Arduino", "Arduino Certified", + "Arduino@Heart")); + dialog.addContributions(BaseNoGui.indexer.getIndex()); + dialog.setVisible(true); + } + public void rebuildBoardsMenu(JMenu toolsMenu, Editor editor) throws Exception { + JMenu boardsMenu = getBoardCustomMenu(); + + @SuppressWarnings("serial") + Action runInstaller = new AbstractAction("Install boards...") { + public void actionPerformed(ActionEvent actionevent) { + openInstallBoardDialog(); + } + }; + boardsMenu.add(new JMenuItem(runInstaller)); + // If there are no platforms installed skip menu creation if (BaseNoGui.packages.size() == 0) return; - JMenu boardsMenu = getBoardCustomMenu(); - + boardsMenu.add(new JSeparator()); + boolean first = true; List menuItemsToClickAfterStartup = new LinkedList(); @@ -1308,7 +1346,7 @@ public class Base { } private static JMenuItem selectFirstEnabledMenuItem(JMenu menu) { - for (int i = 0; i < menu.getItemCount(); i++) { + for (int i = 1; i < menu.getItemCount(); i++) { JMenuItem item = menu.getItem(i); if (item != null && item.isEnabled()) { return item; diff --git a/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java b/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java index 1b60f3aea..edcfbc9a9 100644 --- a/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java +++ b/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java @@ -197,4 +197,16 @@ public class ContributionsIndexer { } return res; } + + public ContributionsIndex getIndex() { + return index; + } + + public void install(ContributedPlatform platform) { + // TODO Auto-generated method stub + } + + public void remove(ContributedPlatform platform) { + // TODO Auto-generated method stub + } } diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 98310dd9d..7f870819d 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -69,9 +69,10 @@ public class BaseNoGui { static Platform platform; static File portableFolder = null; - static final String portableSketchbookFolder = "sketchbook"; + static ContributionsIndexer indexer; + // Returns a File object for the given pathname. If the pathname // is not absolute, it is interpreted relative to the current // directory when starting the IDE (which is not the same as the @@ -584,7 +585,7 @@ public class BaseNoGui { } static public void initPackages() throws Exception { - ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); + indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); indexer.parseIndex(); indexer.syncWithFilesystem(); System.out.println(indexer);