From 56ae061d7e2679dfad0585db0ac27e4b9fe13641 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 16 May 2014 01:06:32 +0200 Subject: [PATCH] Improved platforms installer GUI. Platforms are now downloaded from network. --- .../ui/ContributionInstallerUI.java | 155 +++++++++++++++++ ...Dialog.java => ContributionManagerUI.java} | 164 ++++++++++++------ ...ava => ContributionManagerUIListener.java} | 6 +- app/src/processing/app/Base.java | 84 +++++++-- .../contributions/ContributionInstaller.java | 143 ++++++++++++--- .../contributions/ContributionsIndexer.java | 39 ++--- 6 files changed, 480 insertions(+), 111 deletions(-) create mode 100644 app/src/cc/arduino/packages/contributions/ui/ContributionInstallerUI.java rename app/src/cc/arduino/packages/contributions/ui/{JContributionManagerDialog.java => ContributionManagerUI.java} (68%) rename app/src/cc/arduino/packages/contributions/ui/{JContributionManagerDialogListener.java => ContributionManagerUIListener.java} (93%) diff --git a/app/src/cc/arduino/packages/contributions/ui/ContributionInstallerUI.java b/app/src/cc/arduino/packages/contributions/ui/ContributionInstallerUI.java new file mode 100644 index 000000000..d8e1ac7f7 --- /dev/null +++ b/app/src/cc/arduino/packages/contributions/ui/ContributionInstallerUI.java @@ -0,0 +1,155 @@ +/* + * 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.BorderLayout; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.border.EmptyBorder; + +import cc.arduino.packages.contributions.ContributionInstaller; +import cc.arduino.packages.contributions.ContributionInstaller.Listener; + +@SuppressWarnings("serial") +public class ContributionInstallerUI extends JDialog { + + private final JPanel contentPanel = new JPanel(); + private JButton cancelButton; + private JProgressBar progressBar; + private JLabel operationLabel; + + public ContributionInstallerUI(Window parent) { + super(parent, "Installer progress", Dialog.ModalityType.APPLICATION_MODAL); + + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); + { + Box verticalBox = Box.createVerticalBox(); + contentPanel.add(verticalBox); + { + Component verticalGlue = Box.createVerticalGlue(); + verticalBox.add(verticalGlue); + } + { + Box horizontalBox = Box.createHorizontalBox(); + verticalBox.add(horizontalBox); + { + Component horizontalGlue = Box.createHorizontalGlue(); + horizontalBox.add(horizontalGlue); + } + { + JLabel lblNewLabel = new JLabel("Description"); + horizontalBox.add(lblNewLabel); + } + { + Component horizontalGlue = Box.createHorizontalGlue(); + horizontalBox.add(horizontalGlue); + } + } + { + Component verticalGlue = Box.createVerticalGlue(); + verticalBox.add(verticalGlue); + } + { + Box horizontalBox = Box.createHorizontalBox(); + verticalBox.add(horizontalBox); + { + operationLabel = new JLabel("Current running operation"); + horizontalBox.add(operationLabel); + } + { + Component horizontalGlue = Box.createHorizontalGlue(); + horizontalBox.add(horizontalGlue); + } + } + { + Component verticalStrut = Box.createVerticalStrut(20); + verticalStrut.setPreferredSize(new Dimension(0, 5)); + verticalStrut.setMinimumSize(new Dimension(0, 5)); + verticalBox.add(verticalStrut); + } + { + progressBar = new JProgressBar(); + progressBar.setStringPainted(true); + progressBar.setValue(10); + progressBar.setSize(new Dimension(0, 30)); + progressBar.setMinimumSize(new Dimension(10, 30)); + progressBar.setMaximumSize(new Dimension(32767, 30)); + verticalBox.add(progressBar); + } + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); + } + } + } + + public void onCancel(ActionListener listener) { + cancelButton.addActionListener(listener); + } + + public void setOperationText(String message) { + operationLabel.setText(message); + } + + public void setProgress(int progress) { + progressBar.setValue(progress); + } + + public void attach(ContributionInstaller installer) { + installer.setListener(new Listener() { + @Override + public void onProgress(double progress, String message) { + setOperationText(message); + setProgress((int) progress); + } + }); + } +} diff --git a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java b/app/src/cc/arduino/packages/contributions/ui/ContributionManagerUI.java similarity index 68% rename from app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java rename to app/src/cc/arduino/packages/contributions/ui/ContributionManagerUI.java index 370277a42..9d0029643 100644 --- a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialog.java +++ b/app/src/cc/arduino/packages/contributions/ui/ContributionManagerUI.java @@ -52,10 +52,12 @@ import java.util.List; 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.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; @@ -72,13 +74,11 @@ import cc.arduino.packages.contributions.ContributedPlatform; import cc.arduino.packages.contributions.ContributionsIndex; @SuppressWarnings("serial") -public class JContributionManagerDialog extends JDialog { +public class ContributionManagerUI extends JDialog { private FilterField filterField; - private JScrollPane scrollPane; - private StatusPanel status; - private JContributionManagerDialogListener listener = null; + private ContributionManagerUIListener listener = null; private String category; private JLabel categoryLabel; @@ -89,53 +89,59 @@ public class JContributionManagerDialog extends JDialog { private ContributionIndexTableModel contribModel = new ContributionIndexTableModel(); private JTable contribTable; + private JProgressBar progressBar; - public JContributionManagerDialog(Frame parent) { + private Box progressBox; + private Box updateBox; + + public ContributionManagerUI(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); + { + categoryStrut1 = Box.createHorizontalStrut(5); + categoryStrut2 = Box.createHorizontalStrut(5); + categoryStrut3 = Box.createHorizontalStrut(5); - categoryLabel = new JLabel(_("Category:")); + categoryLabel = new JLabel(_("Category:")); - categoryChooser = new JComboBox(); - categoryChooser.setMaximumRowCount(20); - categoryChooser.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - notifyCategoryChange(); - } - }); + categoryChooser = new JComboBox(); + categoryChooser.setMaximumRowCount(20); + categoryChooser.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + notifyCategoryChange(); + } + }); - setCategories(new ArrayList()); + setCategories(new ArrayList()); - filterField = new FilterField(); + 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)); + 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.setTableHeader(null); + // contribTable.getTableHeader().setEnabled(false); // 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) { @@ -147,14 +153,15 @@ public class JContributionManagerDialog extends JDialog { // } // }); 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); + { + TableColumn descriptionCol = tcm.getColumn(DESCRIPTION_COL); + descriptionCol + .setCellRenderer(new ContributedPlatformTableCellRenderer()); + descriptionCol.setResizable(true); + } { + TableColumn versionCol = tcm.getColumn(VERSION_COL); versionCol.setCellRenderer(new VersionSelectorTableCellRenderer()); VersionSelectorTableCellEditor editor = new VersionSelectorTableCellEditor(); editor.setListener(new VersionSelectorTableCellEditor.Listener() { @@ -172,6 +179,7 @@ public class JContributionManagerDialog extends JDialog { } { + TableColumn installedCol = tcm.getColumn(INSTALLED_COL); installedCol.setCellRenderer(new VersionInstalledTableCellRenderer()); VersionInstalledTableCellEditor editor = new VersionInstalledTableCellEditor(); editor.setListener(new VersionInstalledTableCellEditor.Listener() { @@ -189,26 +197,67 @@ public class JContributionManagerDialog extends JDialog { 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); + { + JScrollPane s = new JScrollPane(); + s.setPreferredSize(new Dimension(300, 300)); + 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); - status = new StatusPanel(); - status.setBorder(new EmptyBorder(7, 7, 7, 7)); - pane.add(status, BorderLayout.SOUTH); + { + progressBar = new JProgressBar(); + progressBar.setStringPainted(true); + progressBar.setString(" "); + progressBar.setVisible(true); - setMinimumSize(new Dimension(450, 400)); + JButton cancelButton = new JButton(_("Cancel")); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (listener != null) + listener.onCancelPressed(); + } + }); + + JButton updateButton = new JButton(_("Update list")); + updateButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (listener != null) + listener.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(500, 400)); } - public void setListener(JContributionManagerDialogListener listener) { + public void setListener(ContributionManagerUIListener listener) { this.listener = listener; } @@ -315,4 +364,19 @@ public class JContributionManagerDialog extends JDialog { contribModel.updateIndex(index); } + public void setProgressVisible(boolean visible) { + progressBox.setVisible(visible); + + filterField.setEnabled(!visible); + categoryChooser.setEnabled(!visible); + contribTable.setEnabled(!visible); + updateBox.setVisible(!visible); + updateBox.setEnabled(!visible); + } + + public void setProgress(int progress, String text) { + progressBar.setValue(progress); + if (text != null) + progressBar.setString(text); + } } diff --git a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java b/app/src/cc/arduino/packages/contributions/ui/ContributionManagerUIListener.java similarity index 93% rename from app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java rename to app/src/cc/arduino/packages/contributions/ui/ContributionManagerUIListener.java index 2a91aa304..dfc334a92 100644 --- a/app/src/cc/arduino/packages/contributions/ui/JContributionManagerDialogListener.java +++ b/app/src/cc/arduino/packages/contributions/ui/ContributionManagerUIListener.java @@ -30,12 +30,16 @@ package cc.arduino.packages.contributions.ui; import cc.arduino.packages.contributions.ContributedPlatform; -public interface JContributionManagerDialogListener { +public interface ContributionManagerUIListener { void onCategoryChange(String category); void onInstall(ContributedPlatform selected); void onRemove(ContributedPlatform selected); + + void onCancelPressed(); + + void onUpdatePressed(); } \ No newline at end of file diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index f08073acb..566f5727c 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -24,8 +24,10 @@ 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.packages.contributions.ContributionInstaller; +import cc.arduino.packages.contributions.ContributionInstaller.Listener; +import cc.arduino.packages.contributions.ui.ContributionManagerUI; +import cc.arduino.packages.contributions.ui.ContributionManagerUIListener; import cc.arduino.view.SplashScreenHelper; import processing.app.debug.TargetBoard; import processing.app.debug.TargetPackage; @@ -1111,32 +1113,82 @@ public class Base { } private void openInstallBoardDialog() { - JContributionManagerDialog dialog = new JContributionManagerDialog( - activeEditor); - dialog.setListener(new JContributionManagerDialogListener() { + // Create dialog for contribution manager + final ContributionManagerUI managerUI = new ContributionManagerUI(activeEditor); + final Listener installerListener = new ContributionInstaller.Listener() { + @Override + public void onProgress(double progress, String message) { + managerUI.setProgress((int) progress, message); + } + }; + managerUI.setListener(new ContributionManagerUIListener() { @Override public void onCategoryChange(String category) { + // TODO Auto-generated method stub System.out.println("Selected " + category); } @Override - public void onInstall(ContributedPlatform platform) { - try { - BaseNoGui.indexer.install(platform); - } catch (Exception e) { - e.printStackTrace(); - } + public void onUpdatePressed() { + // TODO Auto-generated method stub + System.out.println("Update pressed"); } + Thread task = null; + @Override - public void onRemove(ContributedPlatform platform) { - BaseNoGui.indexer.remove(platform); + public void onCancelPressed() { + if (task != null) + task.interrupt(); + } + + @Override + public void onInstall(final ContributedPlatform platform) { + final ContributionInstaller installer = new ContributionInstaller(BaseNoGui.indexer); + installer.setListener(installerListener); + task = new Thread(new Runnable() { + @Override + public void run() { + try { + managerUI.setProgressVisible(true); + installer.install(platform); + } catch (Exception e) { + // TODO Show ERROR + e.printStackTrace(); + } finally { + managerUI.setProgressVisible(false); + } + } + }); + task.start(); + } + + @Override + public void onRemove(final ContributedPlatform platform) { + // Create installer with his dialog + final ContributionInstaller installer = new ContributionInstaller(BaseNoGui.indexer); + installer.setListener(installerListener); + task = new Thread(new Runnable() { + @Override + public void run() { + try { + managerUI.setProgressVisible(true); + installer.remove(platform); + } catch (Exception e) { + // TODO Show ERROR + e.printStackTrace(); + } finally { + managerUI.setProgressVisible(false); + } + } + }); + task.start(); } }); - dialog.setCategories(Arrays.asList("Arduino", "Arduino Certified", + managerUI.setCategories(Arrays.asList("Arduino", "Arduino Certified", "Arduino@Heart")); - dialog.addContributions(BaseNoGui.indexer.getIndex()); - dialog.setVisible(true); + managerUI.addContributions(BaseNoGui.indexer.getIndex()); + managerUI.setVisible(true); } public void rebuildBoardsMenu(JMenu toolsMenu, Editor editor) throws Exception { diff --git a/arduino-core/src/cc/arduino/packages/contributions/ContributionInstaller.java b/arduino-core/src/cc/arduino/packages/contributions/ContributionInstaller.java index de5224c16..8d26d1c38 100644 --- a/arduino-core/src/cc/arduino/packages/contributions/ContributionInstaller.java +++ b/arduino-core/src/cc/arduino/packages/contributions/ContributionInstaller.java @@ -28,40 +28,114 @@ */ package cc.arduino.packages.contributions; +import static processing.app.I18n._; +import static processing.app.I18n.format; + import java.io.File; import java.net.URL; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Observable; +import java.util.Observer; import processing.app.helpers.FileUtils; - import cc.arduino.utils.ArchiveExtractor; import cc.arduino.utils.FileHash; +import cc.arduino.utils.network.FileDownloader; public class ContributionInstaller { - private File preferencesFolder; + /** + * Listener for installation progress. + */ + public static interface Listener { + /** + * Receive the latest progress update. + * + * @param progress + * Actual progress in the range 0...100 + * @param message + * A verbose description message of the actual operation + */ + void onProgress(double progress, String message); + } + + private Listener listener = null; + private File stagingFolder; private ContributionsIndexer indexer; - public ContributionInstaller(File _preferencesFolder, - ContributionsIndexer contributionsIndexer) { - preferencesFolder = _preferencesFolder; - stagingFolder = new File(preferencesFolder, "staging"); + private double progress; + private double progressStepsDelta; + + public void setListener(Listener listener) { + this.listener = listener; + } + + private void updateProgress(double progress, String message) { + if (listener != null) + listener.onProgress(progress, message); + } + + public ContributionInstaller(ContributionsIndexer contributionsIndexer) { + stagingFolder = contributionsIndexer.getStagingFolder(); indexer = contributionsIndexer; } public void install(ContributedPlatform platform) throws Exception { - // Download all files and dependencies - download(platform); - for (ContributedTool tool : platform.getResolvedTools()) { - download(tool.getDownloadableContribution()); + if (platform.isInstalled()) + throw new Exception("Platform is already installed!"); + + // Do not download already installed tools + List tools = new LinkedList(platform.getResolvedTools()); + Iterator toolsIterator = tools.iterator(); + while (toolsIterator.hasNext()) { + ContributedTool tool = toolsIterator.next(); + DownloadableContribution downloadable = tool.getDownloadableContribution(); + if (downloadable == null) { + throw new Exception(format(_("Tool {0} is not available for your operating system."), tool.getName())); + } + if (downloadable.isInstalled()) { + toolsIterator.remove(); + } + } + + // Calculate progress increases + progress = 0.0; + progressStepsDelta = 100.0 / (tools.size() + 1) / 2.0; + + // Download all + try { + // Download platform + download(platform, _("Downloading boards definitions.")); + + // Download tools + int i = 1; + for (ContributedTool tool : tools) { + String msg = format(_("Downloading tools ({0}/{1})."), i, tools.size()); + download(tool.getDownloadableContribution(), msg); + i++; + } + } catch (InterruptedException e) { + // Download interrupted... just exit + return; } ContributedPackage pack = platform.getParentPackage(); File packageFolder = new File(indexer.getPackagesFolder(), pack.getName()); + // 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. + // Unzip tools on the correct location File toolsFolder = new File(packageFolder, "tools"); + int i = 1; for (ContributedTool tool : platform.getResolvedTools()) { + String msg = format(_("Installing tools ({0}/{1})..."), i, tools.size()); + updateProgress(progress, msg); + i++; DownloadableContribution toolContrib = tool.getDownloadableContribution(); File destFolder = new File(toolsFolder, tool.getName() + File.separator + tool.getVersion()); @@ -70,9 +144,11 @@ public class ContributionInstaller { ArchiveExtractor.extract(toolContrib.getDownloadedFile(), destFolder, 1); toolContrib.setInstalled(true); toolContrib.setInstalledFolder(destFolder); + progress += progressStepsDelta; } - // Unzip platform on the correct location + // Unpack platform on the correct location + updateProgress(progress, _("Installing boards...")); File platformFolder = new File(packageFolder, "hardware" + File.separator + platform.getArchitecture()); File destFolder = new File(platformFolder, platform.getVersion()); @@ -80,29 +156,48 @@ public class ContributionInstaller { ArchiveExtractor.extract(platform.getDownloadedFile(), destFolder, 1); platform.setInstalled(true); platform.setInstalledFolder(destFolder); + progress += progressStepsDelta; - // TODO: Update index + updateProgress(100.0, _("Installation completed!")); } - public File download(DownloadableContribution contribution) throws Exception { - contribution.setDownloaded(false); - - System.out.println("Downloading " + contribution.getUrl()); - + public File download(DownloadableContribution contribution, + final String statusText) throws Exception { URL url = new URL(contribution.getUrl()); String path = url.getPath(); String fileName = path.substring(path.lastIndexOf('/') + 1); - File outputFile = new File(stagingFolder, fileName); + final File outputFile = new File(stagingFolder, fileName); - if (outputFile.isFile()) { - if (outputFile.length() != contribution.getSize()) { - // TODO: RESUME DOWNLOAD - } - } else { - // TODO: DOWNLOAD + // Ensure the existence of staging folder + stagingFolder.mkdirs(); + + // Need to download or resume downloading? + if (!outputFile.isFile() || (outputFile.length() < contribution.getSize())) { + + // Use FileDownloader to retrieve the file + FileDownloader downloader = new FileDownloader(url, outputFile); + downloader.addObserver(new Observer() { + @Override + public void update(Observable o, Object arg) { + FileDownloader me = (FileDownloader) o; + String msg = ""; + if (me.getDownloadSize() != null) { + long downloaded = me.getInitialSize() + me.getDownloaded() / 1000; + long total = me.getInitialSize() + me.getDownloadSize() / 1000; + msg = format(_("Downloaded {0}kb of {1}kb."), downloaded, total); + } + updateProgress((int) progress + progressStepsDelta * + me.getProgress() / 100.0, statusText + " " + msg); + } + }); + downloader.download(); + if (!downloader.isCompleted()) + throw new Exception("Error dowloading " + url, downloader.getError()); } + progress += progressStepsDelta; // Test checksum + updateProgress(progress, _("Verifying archive integrity...")); String checksum = contribution.getChecksum(); String algo = checksum.split(":")[0]; if (!FileHash.hash(outputFile, algo).equals(checksum)) diff --git a/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java b/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java index 621aa63ff..c61570414 100644 --- a/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java +++ b/arduino-core/src/cc/arduino/packages/contributions/ContributionsIndexer.java @@ -50,11 +50,13 @@ public class ContributionsIndexer { private File preferencesFolder; private File packagesFolder; + private File stagingFolder; private ContributionsIndex index; public ContributionsIndexer(File _preferencesFolder) { preferencesFolder = _preferencesFolder; packagesFolder = new File(preferencesFolder, "packages"); + stagingFolder = new File(preferencesFolder, "staging"); } // public static void main(String args[]) throws Exception { @@ -198,26 +200,6 @@ public class ContributionsIndexer { return res; } - public ContributionsIndex getIndex() { - return index; - } - - public void install(ContributedPlatform platform) throws Exception { - ContributionInstaller installer = new ContributionInstaller( - preferencesFolder, this); - installer.install(platform); - } - - public void remove(ContributedPlatform platform) { - ContributionInstaller installer = new ContributionInstaller( - preferencesFolder, this); - installer.remove(platform); - } - - public File getPackagesFolder() { - return packagesFolder; - } - /** * Check if a ContributedTool is currently in use by an installed platform * @@ -237,4 +219,21 @@ public class ContributionsIndexer { } return false; } + + public ContributionsIndex getIndex() { + return index; + } + + public File getPreferencesFolder() { + return preferencesFolder; + } + + public File getPackagesFolder() { + return packagesFolder; + } + + public File getStagingFolder() { + return stagingFolder; + } + }