diff --git a/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java b/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java
new file mode 100644
index 000000000..050c4b3f6
--- /dev/null
+++ b/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java
@@ -0,0 +1,45 @@
+package cc.arduino;
+
+import processing.app.Base;
+
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import java.net.URL;
+
+public class UpdatableBoardsLibsFakeURLsHandler implements HyperlinkListener {
+
+ private static final String BOARDSMANAGER = "boardsmanager";
+ private static final String LIBRARYMANAGER = "librarymanager";
+
+ private final Base base;
+
+ public UpdatableBoardsLibsFakeURLsHandler(Base base) {
+ this.base = base;
+ }
+
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent event) {
+ if (event.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
+ return;
+ }
+
+ URL url = event.getURL();
+
+ if (BOARDSMANAGER.equals(url.getHost())) {
+ try {
+ base.openBoardsManager("", "DropdownUpdatableCoresItem");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ if (LIBRARYMANAGER.equals(url.getHost())) {
+ base.openLibraryManager("DropdownUpdatableLibrariesItem");
+ return;
+ }
+
+ throw new IllegalArgumentException(url.getHost() + " is invalid");
+ }
+
+}
diff --git a/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java b/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java
index 683c00125..800756c19 100644
--- a/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java
+++ b/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java
@@ -92,10 +92,11 @@ public class BuiltInCoreIsNewerCheck implements Runnable {
assert base.hasActiveEditor();
int chosenOption = JOptionPane.showConfirmDialog(base.getActiveEditor(), I18n.format(tr("The IDE includes an updated {0} package, but you're using an older one.\nDo you want to upgrade {0}?"), installedBuiltIn.getName()), I18n.format(tr("A newer {0} package is available"), installedBuiltIn.getName()), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (chosenOption == JOptionPane.YES_OPTION) {
- Action openBoardsManager = base.getOpenBoardsManager();
- Event event = new Event(base.getActiveEditor(), ActionEvent.ACTION_PERFORMED, installedBuiltIn.getName());
- event.getPayload().put("filterText", installedBuiltIn.getName());
- openBoardsManager.actionPerformed(event);
+ try {
+ base.openBoardsManager(installedBuiltIn.getName(), "");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
});
}
diff --git a/app/src/cc/arduino/contributions/ContributionsSelfCheck.java b/app/src/cc/arduino/contributions/ContributionsSelfCheck.java
new file mode 100644
index 000000000..176049944
--- /dev/null
+++ b/app/src/cc/arduino/contributions/ContributionsSelfCheck.java
@@ -0,0 +1,109 @@
+package cc.arduino.contributions;
+
+import cc.arduino.contributions.libraries.LibrariesIndexer;
+import cc.arduino.contributions.libraries.LibraryInstaller;
+import cc.arduino.contributions.libraries.filters.UpdatableLibraryPredicate;
+import cc.arduino.contributions.packages.ContributionInstaller;
+import cc.arduino.contributions.packages.ContributionsIndexer;
+import cc.arduino.contributions.packages.filters.UpdatablePlatformPredicate;
+import cc.arduino.view.NotificationPopup;
+import processing.app.Base;
+import processing.app.I18n;
+
+import javax.swing.*;
+import javax.swing.event.HyperlinkListener;
+import java.util.TimerTask;
+
+import static processing.app.I18n.tr;
+
+public class ContributionsSelfCheck extends TimerTask {
+
+ private final Base base;
+ private final HyperlinkListener hyperlinkListener;
+ private final ContributionsIndexer contributionsIndexer;
+ private final ContributionInstaller contributionInstaller;
+ private final LibrariesIndexer librariesIndexer;
+ private final LibraryInstaller libraryInstaller;
+ private final ProgressListener progressListener;
+
+ private volatile boolean cancelled;
+ private volatile NotificationPopup notificationPopup;
+
+ public ContributionsSelfCheck(Base base, HyperlinkListener hyperlinkListener, ContributionsIndexer contributionsIndexer, ContributionInstaller contributionInstaller, LibrariesIndexer librariesIndexer, LibraryInstaller libraryInstaller) {
+ this.base = base;
+ this.hyperlinkListener = hyperlinkListener;
+ this.contributionsIndexer = contributionsIndexer;
+ this.contributionInstaller = contributionInstaller;
+ this.librariesIndexer = librariesIndexer;
+ this.libraryInstaller = libraryInstaller;
+ this.progressListener = new NoopProgressListener();
+ this.cancelled = false;
+ }
+
+ @Override
+ public void run() {
+ updateContributionIndex();
+ updateLibrariesIndex();
+
+ long updatablePlatforms = contributionsIndexer.getPackages().stream()
+ .flatMap(pack -> pack.getPlatforms().stream())
+ .filter(new UpdatablePlatformPredicate(contributionsIndexer)).count();
+
+ long updatableLibraries = librariesIndexer.getInstalledLibraries().stream()
+ .filter(new UpdatableLibraryPredicate(librariesIndexer))
+ .count();
+
+ if (updatableLibraries <= 0 && updatablePlatforms <= 0) {
+ return;
+ }
+
+ String text;
+ if (updatableLibraries > 0 && updatablePlatforms <= 0) {
+ text = I18n.format(tr("
Update available for some of your {0}libraries{1}"), "", "");
+ } else if (updatableLibraries <= 0 && updatablePlatforms > 0) {
+ text = I18n.format(tr("
Update available for some of your {0}boards{1}"), "", "");
+ } else {
+ text = I18n.format(tr("
Update available for some of your {0}boards{1} and {2}libraries{3}"), "", "", "", "");
+ }
+
+ if (cancelled) {
+ return;
+ }
+
+ SwingUtilities.invokeLater(() -> {
+ notificationPopup = new NotificationPopup(base.getActiveEditor(), hyperlinkListener, text);
+ notificationPopup.setVisible(true);
+ });
+ }
+
+ @Override
+ public boolean cancel() {
+ cancelled = true;
+ if (notificationPopup != null) {
+ notificationPopup.close();
+ }
+ return super.cancel();
+ }
+
+ private void updateLibrariesIndex() {
+ if (cancelled) {
+ return;
+ }
+ try {
+ libraryInstaller.updateIndex(progressListener);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ private void updateContributionIndex() {
+ if (cancelled) {
+ return;
+ }
+ try {
+ contributionInstaller.updateIndex(progressListener);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+}
diff --git a/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java
index bcfdba5da..9fa9f3145 100644
--- a/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java
+++ b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java
@@ -36,7 +36,6 @@ import cc.arduino.contributions.libraries.LibraryInstaller;
import cc.arduino.contributions.libraries.LibraryTypeComparator;
import cc.arduino.contributions.ui.*;
import cc.arduino.utils.Progress;
-import processing.app.Platform;
import javax.swing.*;
import java.awt.*;
@@ -53,8 +52,8 @@ import static processing.app.I18n.tr;
public class LibraryManagerUI extends InstallerJDialog {
private final JComboBox typeChooser;
- private final Platform platform;
- private LibrariesIndexer indexer;
+ private final LibrariesIndexer indexer;
+ private final LibraryInstaller installer;
private Predicate typeFilter;
@Override
@@ -90,9 +89,10 @@ public class LibraryManagerUI extends InstallerJDialog {
};
}
- public LibraryManagerUI(Frame parent, Platform platform) {
+ public LibraryManagerUI(Frame parent, LibrariesIndexer indexer, LibraryInstaller installer) {
super(parent, "Library Manager", Dialog.ModalityType.APPLICATION_MODAL, tr("Unable to reach Arduino.cc due to possible network issues."));
- this.platform = platform;
+ this.indexer = indexer;
+ this.installer = installer;
filtersContainer.add(new JLabel(tr("Topic")), 1);
filtersContainer.remove(2);
@@ -125,14 +125,12 @@ public class LibraryManagerUI extends InstallerJDialog {
@Override
public void updateIndexFilter(String[] filters, Predicate... additionalFilters) {
if (additionalFilters.length == 1) {
- additionalFilters = new Predicate[] { additionalFilters[0], typeFilter };
+ additionalFilters = new Predicate[]{additionalFilters[0], typeFilter};
}
super.updateIndexFilter(filters, additionalFilters);
}
- public void setIndexer(LibrariesIndexer indexer) {
- this.indexer = indexer;
-
+ public void updateUI() {
DropdownItem previouslySelectedCategory = (DropdownItem) categoryChooser.getSelectedItem();
DropdownItem previouslySelectedType = (DropdownItem) typeChooser.getSelectedItem();
@@ -181,29 +179,16 @@ public class LibraryManagerUI extends InstallerJDialog {
}
filterField.setEnabled(contribModel.getRowCount() > 0);
-
- // Create LibrariesInstaller tied with the provided index
- installer = new LibraryInstaller(indexer, platform) {
- @Override
- public void onProgress(Progress progress) {
- setProgress(progress);
- }
- };
}
- public LibrariesIndexer getIndexer() {
- return indexer;
+ public void selectDropdownItemByClassName(String dropdownItem) {
+ selectDropdownItemByClassName(typeChooser, dropdownItem);
}
public void setProgress(Progress progress) {
progressBar.setValue(progress);
}
- /*
- * Installer methods follows
- */
-
- private LibraryInstaller installer;
private Thread installerThread = null;
@Override
@@ -220,7 +205,7 @@ public class LibraryManagerUI extends InstallerJDialog {
installerThread = new Thread(() -> {
try {
setProgressVisible(true, "");
- installer.updateIndex();
+ installer.updateIndex(this::setProgress);
onIndexesUpdated();
} catch (Exception e) {
throw new RuntimeException(e);
@@ -237,7 +222,7 @@ public class LibraryManagerUI extends InstallerJDialog {
installerThread = new Thread(() -> {
try {
setProgressVisible(true, tr("Installing..."));
- installer.install(lib, replaced);
+ installer.install(lib, replaced, this::setProgress);
onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element
//getContribModel().updateLibrary(lib);
} catch (Exception e) {
@@ -264,7 +249,7 @@ public class LibraryManagerUI extends InstallerJDialog {
installerThread = new Thread(() -> {
try {
setProgressVisible(true, tr("Removing..."));
- installer.remove(lib);
+ installer.remove(lib, this::setProgress);
onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element
//getContribModel().updateLibrary(lib);
} catch (Exception e) {
diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java
index 025cef5f2..49ef97618 100644
--- a/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java
+++ b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java
@@ -30,14 +30,12 @@
package cc.arduino.contributions.packages.ui;
import cc.arduino.contributions.DownloadableContribution;
-import cc.arduino.contributions.GPGDetachedSignatureVerifier;
import cc.arduino.contributions.packages.ContributedPlatform;
import cc.arduino.contributions.packages.ContributionInstaller;
import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.contributions.ui.*;
import cc.arduino.utils.Progress;
import processing.app.I18n;
-import processing.app.Platform;
import javax.swing.*;
import java.awt.*;
@@ -50,7 +48,8 @@ import static processing.app.I18n.tr;
@SuppressWarnings("serial")
public class ContributionManagerUI extends InstallerJDialog {
- private final Platform platform;
+ private final ContributionsIndexer indexer;
+ private final ContributionInstaller installer;
@Override
protected FilteredAbstractTableModel createContribModel() {
@@ -85,12 +84,13 @@ public class ContributionManagerUI extends InstallerJDialog {
};
}
- public ContributionManagerUI(Frame parent, Platform platform) {
+ public ContributionManagerUI(Frame parent, ContributionsIndexer indexer, ContributionInstaller installer) {
super(parent, tr("Boards Manager"), Dialog.ModalityType.APPLICATION_MODAL, tr("Unable to reach Arduino.cc due to possible network issues."));
- this.platform = platform;
+ this.indexer = indexer;
+ this.installer = installer;
}
- public void setIndexer(ContributionsIndexer indexer) {
+ public void updateUI() {
DropdownItem previouslySelectedCategory = (DropdownItem) categoryChooser.getSelectedItem();
categoryChooser.removeActionListener(categoryChooserActionListener);
@@ -116,14 +116,6 @@ public class ContributionManagerUI extends InstallerJDialog {
} else {
categoryChooser.setSelectedIndex(0);
}
-
- // Create ConstributionInstaller tied with the provided index
- installer = new ContributionInstaller(indexer, platform, new GPGDetachedSignatureVerifier()) {
- @Override
- public void onProgress(Progress progress) {
- setProgress(progress);
- }
- };
}
public void setProgress(Progress progress) {
@@ -134,7 +126,6 @@ public class ContributionManagerUI extends InstallerJDialog {
* Installer methods follows
*/
- private ContributionInstaller installer;
private Thread installerThread = null;
@Override
@@ -151,7 +142,7 @@ public class ContributionManagerUI extends InstallerJDialog {
installerThread = new Thread(() -> {
try {
setProgressVisible(true, "");
- List downloadedPackageIndexFiles = installer.updateIndex();
+ List downloadedPackageIndexFiles = installer.updateIndex(this::setProgress);
installer.deleteUnknownFiles(downloadedPackageIndexFiles);
onIndexesUpdated();
} catch (Exception e) {
@@ -170,7 +161,7 @@ public class ContributionManagerUI extends InstallerJDialog {
List errors = new LinkedList<>();
try {
setProgressVisible(true, tr("Installing..."));
- errors.addAll(installer.install(platformToInstall));
+ errors.addAll(installer.install(platformToInstall, this::setProgress));
if (platformToRemove != null && !platformToRemove.isReadOnly()) {
errors.addAll(installer.remove(platformToRemove));
}
diff --git a/app/src/cc/arduino/contributions/ui/InstallerJDialog.java b/app/src/cc/arduino/contributions/ui/InstallerJDialog.java
index bc69af2c4..255d6f407 100644
--- a/app/src/cc/arduino/contributions/ui/InstallerJDialog.java
+++ b/app/src/cc/arduino/contributions/ui/InstallerJDialog.java
@@ -276,6 +276,19 @@ public abstract class InstallerJDialog extends JDialog {
filterField.setText(filterText);
}
+ public void selectDropdownItemByClassName(String dropdownItem) {
+ selectDropdownItemByClassName(categoryChooser, dropdownItem);
+ }
+
+ public void selectDropdownItemByClassName(JComboBox combo, String dropdownItem) {
+ for (int i = 0; i < combo.getItemCount(); i++) {
+ if (dropdownItem.equals(combo.getItemAt(i).getClass().getSimpleName())) {
+ combo.setSelectedIndex(i);
+ return;
+ }
+ }
+ }
+
/**
* Action performed when the Cancel button is pressed.
*/
diff --git a/app/src/cc/arduino/view/NotificationPopup.form b/app/src/cc/arduino/view/NotificationPopup.form
new file mode 100644
index 000000000..5e6f68cc1
--- /dev/null
+++ b/app/src/cc/arduino/view/NotificationPopup.form
@@ -0,0 +1,89 @@
+
+
+
diff --git a/app/src/cc/arduino/view/NotificationPopup.java b/app/src/cc/arduino/view/NotificationPopup.java
new file mode 100644
index 000000000..8938afa38
--- /dev/null
+++ b/app/src/cc/arduino/view/NotificationPopup.java
@@ -0,0 +1,181 @@
+/*
+ * This file is part of Arduino.
+ *
+ * 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.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ */
+
+package cc.arduino.view;
+
+import processing.app.Base;
+import processing.app.BaseNoGui;
+
+import javax.swing.*;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import java.awt.*;
+import java.awt.event.*;
+import java.nio.file.Paths;
+
+public class NotificationPopup extends JDialog {
+
+ private final ComponentAdapter parentMovedListener;
+
+ public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener, String message) {
+ super(parent, false);
+ initComponents();
+
+ updateLocation(parent);
+ parentMovedListener = new ComponentAdapter() {
+ @Override
+ public void componentMoved(ComponentEvent e) {
+ updateLocation(parent);
+ }
+ };
+ parent.addComponentListener(parentMovedListener);
+
+ text.setText("" + message + "");
+
+ text.addHyperlinkListener(hyperlinkListener);
+ text.addHyperlinkListener(e -> {
+ if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
+ return;
+ }
+ close();
+ });
+
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ parent.removeComponentListener(parentMovedListener);
+ }
+ });
+
+ Base.registerWindowCloseKeys(getRootPane(), e -> close());
+
+ MouseAdapter closeOnClick = new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ close();
+ }
+ };
+ addMouseListener(closeOnClick);
+ text.addMouseListener(closeOnClick);
+ icon.addMouseListener(closeOnClick);
+ }
+
+ private void updateLocation(Frame parent) {
+ Point parentLocation = parent.getLocation();
+
+ int parentX = Double.valueOf(parentLocation.getX()).intValue();
+ int parentY = Double.valueOf(parentLocation.getY()).intValue();
+ setLocation(parentX, parentY + parent.getHeight() - getHeight());
+ }
+
+ public void close() {
+ dispatchEvent(new WindowEvent(NotificationPopup.this, WindowEvent.WINDOW_CLOSING));
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ icon = new javax.swing.JLabel();
+ text = new javax.swing.JEditorPane();
+ closeButton = new javax.swing.JButton();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setAlwaysOnTop(true);
+ setFocusable(false);
+ setFocusableWindowState(false);
+ setUndecorated(true);
+ setPreferredSize(new java.awt.Dimension(350, 70));
+ setResizable(false);
+ setSize(new java.awt.Dimension(350, 70));
+ getContentPane().setLayout(null);
+
+ icon.setIcon(new ImageIcon(Paths.get(BaseNoGui.getContentFile("lib").getAbsolutePath(), "arduino_small.png").toFile().getAbsolutePath()));
+ getContentPane().add(icon);
+ icon.setBounds(10, 10, 50, 50);
+
+ text.setEditable(false);
+ text.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 0, true));
+ text.setContentType("text/html"); // NOI18N
+ text.setOpaque(false);
+ getContentPane().add(text);
+ text.setBounds(70, 10, 270, 50);
+
+ closeButton.setIcon(new ImageIcon(Paths.get(BaseNoGui.getContentFile("lib").getAbsolutePath(), "theme", "close.png").toFile().getAbsolutePath()));
+ closeButton.setBorder(null);
+ closeButton.setBorderPainted(false);
+ closeButton.setHideActionText(true);
+ closeButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ closeButtonActionPerformed(evt);
+ }
+ });
+ getContentPane().add(closeButton);
+ closeButton.setBounds(328, 0, 22, 22);
+
+ pack();
+ }// //GEN-END:initComponents
+
+ private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
+ close();
+ }//GEN-LAST:event_closeButtonActionPerformed
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String args[]) {
+
+ /* Create and display the dialog */
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ NotificationPopup dialog = new NotificationPopup(new JFrame(), System.out::println, "test test test test test test test test test\n" +
+ " test test test test test test test test test test test");
+ dialog.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+ dialog.setVisible(true);
+ }
+ });
+ }
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton closeButton;
+ private javax.swing.JLabel icon;
+ private javax.swing.JEditorPane text;
+ // End of variables declaration//GEN-END:variables
+
+}
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 6655c94f3..7cc5c2a89 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -22,10 +22,9 @@
package processing.app;
-import cc.arduino.contributions.BuiltInCoreIsNewerCheck;
-import cc.arduino.contributions.DownloadableContributionVersionComparator;
-import cc.arduino.contributions.GPGDetachedSignatureVerifier;
-import cc.arduino.contributions.VersionHelper;
+import cc.arduino.Constants;
+import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
+import cc.arduino.contributions.*;
import cc.arduino.contributions.libraries.*;
import cc.arduino.contributions.libraries.ui.LibraryManagerUI;
import cc.arduino.contributions.packages.ContributedPlatform;
@@ -34,7 +33,6 @@ import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.contributions.packages.ui.ContributionManagerUI;
import cc.arduino.files.DeleteFilesOnShutdown;
import cc.arduino.packages.DiscoveryManager;
-import cc.arduino.utils.Progress;
import cc.arduino.view.Event;
import cc.arduino.view.JMenuUtils;
import cc.arduino.view.SplashScreenHelper;
@@ -62,6 +60,7 @@ import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
+import java.util.Timer;
import java.util.function.Predicate;
import java.util.logging.Handler;
import java.util.logging.Level;
@@ -93,6 +92,9 @@ public class Base {
public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen());
public static Map FIND_DIALOG_STATE = new HashMap();
+ private final ContributionInstaller contributionInstaller;
+ private final LibraryInstaller libraryInstaller;
+ private ContributionsSelfCheck contributionsSelfCheck;
// set to true after the first time the menu is built.
// so that the errors while building don't show up again.
@@ -117,7 +119,6 @@ public class Base {
// are the same for all windows (since the board and serial port that are
// actually used are determined by the preferences, which are shared)
private List boardsCustomMenus;
- private volatile Action openBoardsManager;
private List programmerMenus;
private final PdeKeywords pdeKeywords;
@@ -303,6 +304,9 @@ public class Base {
this.pdeKeywords = new PdeKeywords();
this.pdeKeywords.reload();
+ contributionInstaller = new ContributionInstaller(BaseNoGui.indexer, BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
+ libraryInstaller = new LibraryInstaller(BaseNoGui.librariesIndexer, BaseNoGui.getPlatform());
+
parser.parseArgumentsPhase2();
for (String path : parser.getFilenames()) {
@@ -341,19 +345,10 @@ public class Base {
if (parser.isInstallBoard()) {
ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
- ContributionInstaller installer = new ContributionInstaller(indexer, BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier()) {
- private String lastStatus = "";
+ ProgressListener progressListener = new ConsoleProgressListener();
- @Override
- protected void onProgress(Progress progress) {
- if (!lastStatus.equals(progress.getStatus())) {
- System.out.println(progress.getStatus());
- }
- lastStatus = progress.getStatus();
- }
- };
- List downloadedPackageIndexFiles = installer.updateIndex();
- installer.deleteUnknownFiles(downloadedPackageIndexFiles);
+ List downloadedPackageIndexFiles = contributionInstaller.updateIndex(progressListener);
+ contributionInstaller.deleteUnknownFiles(downloadedPackageIndexFiles);
indexer.parseIndex();
indexer.syncWithFilesystem(BaseNoGui.getHardwareFolder());
@@ -377,33 +372,23 @@ public class Base {
ContributedPlatform installed = indexer.getInstalled(boardToInstallParts[0], boardToInstallParts[1]);
if (!selected.isReadOnly()) {
- installer.install(selected);
+ contributionInstaller.install(selected, progressListener);
}
if (installed != null && !installed.isReadOnly()) {
- installer.remove(installed);
+ contributionInstaller.remove(installed);
}
System.exit(0);
} else if (parser.isInstallLibrary()) {
LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder(), new ContributionsIndexer(BaseNoGui.getSettingsFolder(), BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier()));
- LibraryInstaller installer = new LibraryInstaller(indexer, BaseNoGui.getPlatform()) {
- private String lastStatus = "";
-
- @Override
- protected void onProgress(Progress progress) {
- if (!lastStatus.equals(progress.getStatus())) {
- System.out.println(progress.getStatus());
- }
- lastStatus = progress.getStatus();
- }
- };
+ ProgressListener progressListener = new ConsoleProgressListener();
indexer.parseIndex();
BaseNoGui.onBoardOrPortChange();
indexer.setSketchbookLibrariesFolder(BaseNoGui.getSketchbookLibrariesFolder());
indexer.setLibrariesFolders(BaseNoGui.getLibrariesPath());
- installer.updateIndex();
+ libraryInstaller.updateIndex(progressListener);
for (String library : parser.getLibraryToInstall().split(",")) {
String[] libraryToInstallParts = library.split(":");
@@ -425,9 +410,9 @@ public class Base {
ContributedLibrary installed = indexer.getIndex().getInstalled(libraryToInstallParts[0]);
if (selected.isReadOnly()) {
- installer.remove(installed);
+ libraryInstaller.remove(installed, progressListener);
} else {
- installer.install(selected, installed);
+ libraryInstaller.install(selected, installed, progressListener);
}
}
@@ -481,6 +466,9 @@ public class Base {
new Thread(new BuiltInCoreIsNewerCheck(this)).start();
+ contributionsSelfCheck = new ContributionsSelfCheck(this, new UpdatableBoardsLibsFakeURLsHandler(this), BaseNoGui.indexer, contributionInstaller, BaseNoGui.librariesIndexer, libraryInstaller);
+ new Timer(false).schedule(contributionsSelfCheck, Constants.BOARDS_LIBS_UPDATABLE_CHECK_START_PERIOD);
+
} else if (parser.isNoOpMode()) {
// Do nothing (intended for only changing preferences)
System.exit(0);
@@ -695,13 +683,6 @@ public class Base {
"jul", "aug", "sep", "oct", "nov", "dec"
};
- /**
- * Handle creating a sketch folder, return its base .pde file
- * or null if the operation was canceled.
- *
- * @param shift whether shift is pressed, which will invert prompt setting
- * @param noPrompt disable prompt, no matter the setting
- */
protected File createNewUntitled() throws IOException {
File newbieDir = null;
String newbieName = null;
@@ -804,20 +785,13 @@ public class Base {
activeEditor.handleOpenInternal(file);
activeEditor.untitled = true;
}
-// return true;
} catch (IOException e) {
activeEditor.statusError(e);
-// return false;
}
}
- /**
- * Open a sketch, replacing the sketch in the current window.
- *
- * @param path Location of the primary pde file for the sketch.
- */
public void handleOpenReplace(File file) {
if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled
@@ -1165,11 +1139,7 @@ public class Base {
importMenu.removeAll();
JMenuItem menu = new JMenuItem(tr("Manage Libraries..."));
- menu.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- openManageLibrariesDialog();
- }
- });
+ menu.addActionListener(e -> openLibraryManager(""));
importMenu.add(menu);
importMenu.addSeparator();
@@ -1257,20 +1227,26 @@ public class Base {
}
}
- private void openManageLibrariesDialog() {
+ public void openLibraryManager(String dropdownItem) {
+ if (contributionsSelfCheck != null) {
+ contributionsSelfCheck.cancel();
+ }
@SuppressWarnings("serial")
- LibraryManagerUI managerUI = new LibraryManagerUI(activeEditor, BaseNoGui.getPlatform()) {
+ LibraryManagerUI managerUI = new LibraryManagerUI(activeEditor, BaseNoGui.librariesIndexer, libraryInstaller) {
@Override
protected void onIndexesUpdated() throws Exception {
BaseNoGui.initPackages();
rebuildBoardsMenu();
rebuildProgrammerMenu();
onBoardOrPortChange();
- setIndexer(BaseNoGui.librariesIndexer);
+ updateUI();
+ if (StringUtils.isNotEmpty(dropdownItem)) {
+ selectDropdownItemByClassName(dropdownItem);
+ }
}
};
managerUI.setLocationRelativeTo(activeEditor);
- managerUI.setIndexer(BaseNoGui.librariesIndexer);
+ managerUI.updateUI();
managerUI.setVisible(true);
// Manager dialog is modal, waits here until closed
@@ -1280,24 +1256,28 @@ public class Base {
rebuildExamplesMenu(Editor.examplesMenu);
}
- private void openInstallBoardDialog(final String filterText) throws Exception {
- // Create dialog for contribution manager
+ public void openBoardsManager(final String filterText, String dropdownItem) throws Exception {
+ if (contributionsSelfCheck != null) {
+ contributionsSelfCheck.cancel();
+ }
@SuppressWarnings("serial")
- ContributionManagerUI managerUI = new ContributionManagerUI(activeEditor, BaseNoGui.getPlatform()) {
+ ContributionManagerUI managerUI = new ContributionManagerUI(activeEditor, BaseNoGui.indexer, contributionInstaller) {
@Override
protected void onIndexesUpdated() throws Exception {
BaseNoGui.initPackages();
rebuildBoardsMenu();
rebuildProgrammerMenu();
- setIndexer(BaseNoGui.indexer);
+ updateUI();
+ if (StringUtils.isNotEmpty(dropdownItem)) {
+ selectDropdownItemByClassName(dropdownItem);
+ }
if (StringUtils.isNotEmpty(filterText)) {
setFilterText(filterText);
}
-
}
};
managerUI.setLocationRelativeTo(activeEditor);
- managerUI.setIndexer(BaseNoGui.indexer);
+ managerUI.updateUI();
managerUI.setVisible(true);
// Installer dialog is modal, waits here until closed
@@ -1316,21 +1296,22 @@ public class Base {
boardMenu.putClientProperty("removeOnWindowDeactivation", true);
MenuScroller.setScrollerFor(boardMenu);
- openBoardsManager = new AbstractAction(tr("Boards Manager...")) {
+ boardMenu.add(new JMenuItem(new AbstractAction(tr("Boards Manager...")) {
public void actionPerformed(ActionEvent actionevent) {
String filterText = "";
- if (actionevent instanceof cc.arduino.view.Event) {
+ String dropdownItem = "";
+ if (actionevent instanceof Event) {
filterText = ((Event) actionevent).getPayload().get("filterText").toString();
+ dropdownItem = ((Event) actionevent).getPayload().get("dropdownItem").toString();
}
try {
- openInstallBoardDialog(filterText);
+ openBoardsManager(filterText, dropdownItem);
} catch (Exception e) {
//TODO show error
e.printStackTrace();
}
}
- };
- boardMenu.add(new JMenuItem(openBoardsManager));
+ }));
boardsCustomMenus.add(boardMenu);
// If there are no platforms installed we are done
@@ -2363,11 +2344,7 @@ public class Base {
}
public List getEditors() {
- return new LinkedList(editors);
- }
-
- public Action getOpenBoardsManager() {
- return openBoardsManager;
+ return new LinkedList<>(editors);
}
public PdeKeywords getPdeKeywords() {
@@ -2377,4 +2354,5 @@ public class Base {
public List getRecentSketchesMenuItems() {
return recentSketchesMenuItems;
}
+
}
diff --git a/app/test/cc/arduino/contributions/GzippedJsonDownloaderTest.java b/app/test/cc/arduino/contributions/GzippedJsonDownloaderTest.java
index a762b6801..e1e231acd 100644
--- a/app/test/cc/arduino/contributions/GzippedJsonDownloaderTest.java
+++ b/app/test/cc/arduino/contributions/GzippedJsonDownloaderTest.java
@@ -38,7 +38,7 @@ public class GzippedJsonDownloaderTest {
@Test
public void testJsonDownload() throws Exception {
- new GZippedJsonDownloader(downloader, new URL("http://downloads.arduino.cc/libraries/library_index.json"), new URL("http://downloads.arduino.cc/libraries/library_index.json.gz")).download(tempFile, new MultiStepProgress(1), "");
+ new GZippedJsonDownloader(downloader, new URL("http://downloads.arduino.cc/libraries/library_index.json"), new URL("http://downloads.arduino.cc/libraries/library_index.json.gz")).download(tempFile, new MultiStepProgress(1), "", new NoopProgressListener());
InputStream indexIn = new FileInputStream(tempFile);
ObjectMapper mapper = new ObjectMapper();
diff --git a/app/test/cc/arduino/contributions/JsonDownloaderTest.java b/app/test/cc/arduino/contributions/JsonDownloaderTest.java
index 98cefef49..ebf3c0913 100644
--- a/app/test/cc/arduino/contributions/JsonDownloaderTest.java
+++ b/app/test/cc/arduino/contributions/JsonDownloaderTest.java
@@ -38,7 +38,7 @@ public class JsonDownloaderTest {
@Test
public void testJsonDownload() throws Exception {
- new JsonDownloader(downloader, new URL("http://downloads.arduino.cc/libraries/library_index.json")).download(tempFile, new MultiStepProgress(1), "");
+ new JsonDownloader(downloader, new URL("http://downloads.arduino.cc/libraries/library_index.json")).download(tempFile, new MultiStepProgress(1), "", new NoopProgressListener());
InputStream indexIn = new FileInputStream(tempFile);
ObjectMapper mapper = new ObjectMapper();
diff --git a/arduino-core/src/cc/arduino/Constants.java b/arduino-core/src/cc/arduino/Constants.java
index 5b0e4436f..098caab97 100644
--- a/arduino-core/src/cc/arduino/Constants.java
+++ b/arduino-core/src/cc/arduino/Constants.java
@@ -44,6 +44,12 @@ public class Constants {
public static final String LIBRARY_DEVELOPMENT_FLAG_FILE = ".development";
+ public static final long BOARDS_LIBS_UPDATABLE_CHECK_START_PERIOD = 60000;
+ public static final int NOTIFICATION_POPUP_AUTOCLOSE_DELAY = 10000;
+
+ public static final String LIBRARY_INDEX_URL;
+ public static final String LIBRARY_INDEX_URL_GZ;
+
static {
String extenalPackageIndexUrl = System.getProperty("PACKAGE_INDEX_URL");
if (extenalPackageIndexUrl != null && !"".equals(extenalPackageIndexUrl)) {
@@ -51,7 +57,14 @@ public class Constants {
} else {
PACKAGE_INDEX_URL = "http://downloads.arduino.cc/packages/package_index.json";
}
+
+ String externalLibraryIndexUrl = System.getProperty("LIBRARY_INDEX_URL");
+ if (externalLibraryIndexUrl != null && !"".equals(externalLibraryIndexUrl)) {
+ LIBRARY_INDEX_URL = externalLibraryIndexUrl;
+ } else {
+ LIBRARY_INDEX_URL = "http://downloads.arduino.cc/libraries/library_index.json";
+ }
+ LIBRARY_INDEX_URL_GZ = "http://downloads.arduino.cc/libraries/library_index.json.gz";
}
-
}
diff --git a/arduino-core/src/cc/arduino/contributions/ConsoleProgressListener.java b/arduino-core/src/cc/arduino/contributions/ConsoleProgressListener.java
new file mode 100644
index 000000000..c45299484
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/ConsoleProgressListener.java
@@ -0,0 +1,15 @@
+package cc.arduino.contributions;
+
+import cc.arduino.utils.Progress;
+
+public class ConsoleProgressListener implements ProgressListener {
+ private String lastStatus = "";
+
+ @Override
+ public void onProgress(Progress progress) {
+ if (!lastStatus.equals(progress.getStatus())) {
+ System.out.println(progress.getStatus());
+ }
+ lastStatus = progress.getStatus();
+ }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/DownloadableContributionsDownloader.java b/arduino-core/src/cc/arduino/contributions/DownloadableContributionsDownloader.java
index 5b6309285..8bbcbc227 100644
--- a/arduino-core/src/cc/arduino/contributions/DownloadableContributionsDownloader.java
+++ b/arduino-core/src/cc/arduino/contributions/DownloadableContributionsDownloader.java
@@ -51,7 +51,7 @@ public class DownloadableContributionsDownloader {
stagingFolder = _stagingFolder;
}
- public File download(DownloadableContribution contribution, Progress progress, final String statusText) throws Exception {
+ public File download(DownloadableContribution contribution, Progress progress, final String statusText, ProgressListener progressListener) throws Exception {
URL url = new URL(contribution.getUrl());
Path outputFile = Paths.get(stagingFolder.getAbsolutePath(), contribution.getArchiveFileName());
@@ -64,12 +64,12 @@ public class DownloadableContributionsDownloader {
// Need to download or resume downloading?
if (!Files.isRegularFile(outputFile, LinkOption.NOFOLLOW_LINKS) || (Files.size(outputFile) < contribution.getSize())) {
- download(url, outputFile.toFile(), progress, statusText);
+ download(url, outputFile.toFile(), progress, statusText, progressListener);
}
// Test checksum
progress.setStatus(tr("Verifying archive integrity..."));
- onProgress(progress);
+ progressListener.onProgress(progress);
String checksum = contribution.getChecksum();
if (hasChecksum(contribution)) {
String algo = checksum.split(":")[0];
@@ -94,7 +94,7 @@ public class DownloadableContributionsDownloader {
return algo != null && !algo.isEmpty();
}
- public void download(URL url, File tmpFile, Progress progress, String statusText) throws Exception {
+ public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
FileDownloader downloader = new FileDownloader(url, tmpFile);
downloader.addObserver((o, arg) -> {
FileDownloader me = (FileDownloader) o;
@@ -106,7 +106,7 @@ public class DownloadableContributionsDownloader {
}
progress.setStatus(statusText + " " + msg);
progress.setProgress(me.getProgress());
- onProgress(progress);
+ progressListener.onProgress(progress);
});
downloader.download();
if (!downloader.isCompleted()) {
@@ -114,8 +114,4 @@ public class DownloadableContributionsDownloader {
}
}
- protected void onProgress(Progress progress) {
- // Empty
- }
-
}
diff --git a/arduino-core/src/cc/arduino/contributions/GZippedJsonDownloader.java b/arduino-core/src/cc/arduino/contributions/GZippedJsonDownloader.java
index b4994d8d7..df7eee420 100644
--- a/arduino-core/src/cc/arduino/contributions/GZippedJsonDownloader.java
+++ b/arduino-core/src/cc/arduino/contributions/GZippedJsonDownloader.java
@@ -49,14 +49,14 @@ public class GZippedJsonDownloader {
this.gzippedUrl = gzippedUrl;
}
- public void download(File tmpFile, Progress progress, String statusText) throws Exception {
+ public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
try {
- new JsonDownloader(downloader, gzippedUrl).download(tmpFile, progress, statusText);
+ new JsonDownloader(downloader, gzippedUrl).download(tmpFile, progress, statusText, progressListener);
File gzipTmpFile = new File(tmpFile.getParentFile(), GzipUtils.getCompressedFilename(tmpFile.getName()));
tmpFile.renameTo(gzipTmpFile);
decompress(gzipTmpFile, tmpFile);
} catch (Exception e) {
- new JsonDownloader(downloader, url).download(tmpFile, progress, statusText);
+ new JsonDownloader(downloader, url).download(tmpFile, progress, statusText, progressListener);
}
}
diff --git a/arduino-core/src/cc/arduino/contributions/JsonDownloader.java b/arduino-core/src/cc/arduino/contributions/JsonDownloader.java
index da01ff95b..88f9e7783 100644
--- a/arduino-core/src/cc/arduino/contributions/JsonDownloader.java
+++ b/arduino-core/src/cc/arduino/contributions/JsonDownloader.java
@@ -44,9 +44,9 @@ public class JsonDownloader {
this.url = url;
}
- public void download(File tmpFile, Progress progress, String statusText) throws Exception {
+ public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
try {
- downloader.download(url, tmpFile, progress, statusText);
+ downloader.download(url, tmpFile, progress, statusText, progressListener);
} catch (InterruptedException e) {
// Download interrupted... just exit
}
diff --git a/arduino-core/src/cc/arduino/contributions/NoopProgressListener.java b/arduino-core/src/cc/arduino/contributions/NoopProgressListener.java
new file mode 100644
index 000000000..68649ecda
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/NoopProgressListener.java
@@ -0,0 +1,12 @@
+package cc.arduino.contributions;
+
+import cc.arduino.utils.Progress;
+
+public class NoopProgressListener implements ProgressListener {
+
+ @Override
+ public void onProgress(Progress progress) {
+
+ }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/ProgressListener.java b/arduino-core/src/cc/arduino/contributions/ProgressListener.java
new file mode 100644
index 000000000..f1b8d32b0
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/ProgressListener.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 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.contributions;
+
+import cc.arduino.utils.Progress;
+
+public interface ProgressListener {
+
+ void onProgress(Progress progress);
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java b/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java
index c2afad7dc..c01b56f20 100644
--- a/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java
+++ b/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java
@@ -29,11 +29,12 @@
package cc.arduino.contributions.libraries;
+import cc.arduino.Constants;
import cc.arduino.contributions.DownloadableContributionsDownloader;
import cc.arduino.contributions.GZippedJsonDownloader;
+import cc.arduino.contributions.ProgressListener;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
-import cc.arduino.utils.Progress;
import processing.app.I18n;
import processing.app.Platform;
import processing.app.helpers.FileUtils;
@@ -46,19 +47,6 @@ import static processing.app.I18n.tr;
public class LibraryInstaller {
- private static final String LIBRARY_INDEX_URL;
- private static final String LIBRARY_INDEX_URL_GZ;
-
- static {
- String externalLibraryIndexUrl = System.getProperty("LIBRARY_INDEX_URL");
- if (externalLibraryIndexUrl != null && !"".equals(externalLibraryIndexUrl)) {
- LIBRARY_INDEX_URL = externalLibraryIndexUrl;
- } else {
- LIBRARY_INDEX_URL = "http://downloads.arduino.cc/libraries/library_index.json";
- }
- LIBRARY_INDEX_URL_GZ = "http://downloads.arduino.cc/libraries/library_index.json.gz";
- }
-
private final LibrariesIndexer indexer;
private final DownloadableContributionsDownloader downloader;
private final Platform platform;
@@ -67,23 +55,18 @@ public class LibraryInstaller {
this.indexer = indexer;
this.platform = platform;
File stagingFolder = indexer.getStagingFolder();
- downloader = new DownloadableContributionsDownloader(stagingFolder) {
- @Override
- protected void onProgress(Progress progress) {
- LibraryInstaller.this.onProgress(progress);
- }
- };
+ downloader = new DownloadableContributionsDownloader(stagingFolder);
}
- public void updateIndex() throws Exception {
+ public synchronized void updateIndex(ProgressListener progressListener) throws Exception {
final MultiStepProgress progress = new MultiStepProgress(2);
// Step 1: Download index
File outputFile = indexer.getIndexFile();
File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp");
try {
- GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, new URL(LIBRARY_INDEX_URL), new URL(LIBRARY_INDEX_URL_GZ));
- gZippedJsonDownloader.download(tmpFile, progress, tr("Downloading libraries index..."));
+ GZippedJsonDownloader gZippedJsonDownloader = new GZippedJsonDownloader(downloader, new URL(Constants.LIBRARY_INDEX_URL), new URL(Constants.LIBRARY_INDEX_URL_GZ));
+ gZippedJsonDownloader.download(tmpFile, progress, tr("Downloading libraries index..."), progressListener);
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
@@ -99,10 +82,10 @@ public class LibraryInstaller {
throw new Exception(tr("An error occurred while updating libraries index!"));
// Step 2: Rescan index
- rescanLibraryIndex(progress);
+ rescanLibraryIndex(progress, progressListener);
}
- public void install(ContributedLibrary lib, ContributedLibrary replacedLib) throws Exception {
+ public synchronized void install(ContributedLibrary lib, ContributedLibrary replacedLib, ProgressListener progressListener) throws Exception {
if (lib.isInstalled()) {
System.out.println(I18n.format(tr("Library is already installed: {0} version {1}"), lib.getName(), lib.getParsedVersion()));
return;
@@ -112,7 +95,7 @@ public class LibraryInstaller {
// Step 1: Download library
try {
- downloader.download(lib, progress, I18n.format(tr("Downloading library: {0}"), lib.getName()));
+ downloader.download(lib, progress, I18n.format(tr("Downloading library: {0}"), lib.getName()), progressListener);
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
@@ -124,7 +107,7 @@ public class LibraryInstaller {
// Step 2: Unpack library on the correct location
progress.setStatus(I18n.format(tr("Installing library: {0}"), lib.getName()));
- onProgress(progress);
+ progressListener.onProgress(progress);
File libsFolder = indexer.getSketchbookLibrariesFolder();
File tmpFolder = FileUtils.createTempFolderIn(libsFolder);
try {
@@ -137,16 +120,16 @@ public class LibraryInstaller {
// Step 3: Remove replaced library and move installed one to the correct location
// TODO: Fix progress bar...
- remove(replacedLib);
+ remove(replacedLib, progressListener);
File destFolder = new File(libsFolder, lib.getName().replaceAll(" ", "_"));
tmpFolder.renameTo(destFolder);
progress.stepDone();
// Step 4: Rescan index
- rescanLibraryIndex(progress);
+ rescanLibraryIndex(progress, progressListener);
}
- public void remove(ContributedLibrary lib) throws IOException {
+ public synchronized void remove(ContributedLibrary lib, ProgressListener progressListener) throws IOException {
if (lib == null || lib.isReadOnly()) {
return;
}
@@ -155,22 +138,18 @@ public class LibraryInstaller {
// Step 1: Remove library
progress.setStatus(I18n.format(tr("Removing library: {0}"), lib.getName()));
- onProgress(progress);
+ progressListener.onProgress(progress);
FileUtils.recursiveDelete(lib.getInstalledFolder());
progress.stepDone();
// Step 2: Rescan index
- rescanLibraryIndex(progress);
+ rescanLibraryIndex(progress, progressListener);
}
- private void rescanLibraryIndex(MultiStepProgress progress) {
+ private void rescanLibraryIndex(MultiStepProgress progress, ProgressListener progressListener) {
progress.setStatus(tr("Updating list of installed libraries"));
- onProgress(progress);
+ progressListener.onProgress(progress);
indexer.rescanLibraries();
progress.stepDone();
}
-
- protected void onProgress(Progress progress) {
- // Empty
- }
}
diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java b/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java
index 52cdf1c64..24712c896 100644
--- a/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java
+++ b/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java
@@ -32,11 +32,11 @@ package cc.arduino.contributions.packages;
import cc.arduino.Constants;
import cc.arduino.contributions.DownloadableContribution;
import cc.arduino.contributions.DownloadableContributionsDownloader;
+import cc.arduino.contributions.ProgressListener;
import cc.arduino.contributions.SignatureVerifier;
import cc.arduino.filters.FileExecutablePredicate;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
-import cc.arduino.utils.Progress;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.Executor;
@@ -70,15 +70,10 @@ public class ContributionInstaller {
this.signatureVerifier = signatureVerifier;
File stagingFolder = contributionsIndexer.getStagingFolder();
indexer = contributionsIndexer;
- downloader = new DownloadableContributionsDownloader(stagingFolder) {
- @Override
- protected void onProgress(Progress progress) {
- ContributionInstaller.this.onProgress(progress);
- }
- };
+ downloader = new DownloadableContributionsDownloader(stagingFolder);
}
- public List install(ContributedPlatform contributedPlatform) throws Exception {
+ public synchronized List install(ContributedPlatform contributedPlatform, ProgressListener progressListener) throws Exception {
List errors = new LinkedList<>();
if (contributedPlatform.isInstalled()) {
throw new Exception("Platform is already installed!");
@@ -104,7 +99,7 @@ public class ContributionInstaller {
// Download all
try {
// Download platform
- downloader.download(contributedPlatform, progress, tr("Downloading boards definitions."));
+ downloader.download(contributedPlatform, progress, tr("Downloading boards definitions."), progressListener);
progress.stepDone();
// Download tools
@@ -112,7 +107,7 @@ public class ContributionInstaller {
for (ContributedTool tool : tools) {
String msg = format(tr("Downloading tools ({0}/{1})."), i, tools.size());
i++;
- downloader.download(tool.getDownloadableContribution(platform), progress, msg);
+ downloader.download(tool.getDownloadableContribution(platform), progress, msg, progressListener);
progress.stepDone();
}
} catch (InterruptedException e) {
@@ -132,7 +127,7 @@ public class ContributionInstaller {
int i = 1;
for (ContributedTool tool : tools) {
progress.setStatus(format(tr("Installing tools ({0}/{1})..."), i, tools.size()));
- onProgress(progress);
+ progressListener.onProgress(progress);
i++;
DownloadableContribution toolContrib = tool.getDownloadableContribution(platform);
File destFolder = new File(toolsFolder, tool.getName() + File.separator + tool.getVersion());
@@ -152,7 +147,7 @@ public class ContributionInstaller {
// Unpack platform on the correct location
progress.setStatus(tr("Installing boards..."));
- onProgress(progress);
+ progressListener.onProgress(progress);
File platformFolder = new File(packageFolder, "hardware" + File.separator + contributedPlatform.getArchitecture());
File destFolder = new File(platformFolder, contributedPlatform.getParsedVersion());
Files.createDirectories(destFolder.toPath());
@@ -168,7 +163,7 @@ public class ContributionInstaller {
progress.stepDone();
progress.setStatus(tr("Installation completed!"));
- onProgress(progress);
+ progressListener.onProgress(progress);
return errors;
}
@@ -234,7 +229,7 @@ public class ContributionInstaller {
}
}
- public List remove(ContributedPlatform contributedPlatform) {
+ public synchronized List remove(ContributedPlatform contributedPlatform) {
if (contributedPlatform == null || contributedPlatform.isReadOnly()) {
return new LinkedList<>();
}
@@ -274,11 +269,11 @@ public class ContributionInstaller {
return errors;
}
- public List updateIndex() throws Exception {
+ public synchronized List updateIndex(ProgressListener progressListener) throws Exception {
MultiStepProgress progress = new MultiStepProgress(1);
List downloadedPackageIndexFilesAccumulator = new LinkedList<>();
- downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, Constants.PACKAGE_INDEX_URL);
+ downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, Constants.PACKAGE_INDEX_URL, progressListener);
Set packageIndexURLs = new HashSet<>();
String additionalURLs = PreferencesData.get(Constants.PREF_BOARDS_MANAGER_ADDITIONAL_URLS, "");
@@ -287,7 +282,7 @@ public class ContributionInstaller {
}
for (String packageIndexURL : packageIndexURLs) {
- downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, packageIndexURL);
+ downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, packageIndexURL, progressListener);
}
progress.stepDone();
@@ -295,11 +290,11 @@ public class ContributionInstaller {
return downloadedPackageIndexFilesAccumulator;
}
- private void downloadIndexAndSignature(MultiStepProgress progress, List downloadedPackagedIndexFilesAccumulator, String packageIndexUrl) throws Exception {
- File packageIndex = download(progress, packageIndexUrl);
+ private void downloadIndexAndSignature(MultiStepProgress progress, List downloadedPackagedIndexFilesAccumulator, String packageIndexUrl, ProgressListener progressListener) throws Exception {
+ File packageIndex = download(progress, packageIndexUrl, progressListener);
downloadedPackagedIndexFilesAccumulator.add(packageIndex.getName());
try {
- File packageIndexSignature = download(progress, packageIndexUrl + ".sig");
+ File packageIndexSignature = download(progress, packageIndexUrl + ".sig", progressListener);
boolean signatureVerified = signatureVerifier.isSigned(packageIndex);
if (signatureVerified) {
downloadedPackagedIndexFilesAccumulator.add(packageIndexSignature.getName());
@@ -314,32 +309,21 @@ public class ContributionInstaller {
}
}
- private File download(MultiStepProgress progress, String packageIndexUrl) throws Exception {
+ private File download(MultiStepProgress progress, String packageIndexUrl, ProgressListener progressListener) throws Exception {
String statusText = tr("Downloading platforms index...");
URL url = new URL(packageIndexUrl);
String[] urlPathParts = url.getFile().split("/");
File outputFile = indexer.getIndexFile(urlPathParts[urlPathParts.length - 1]);
File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp");
- downloader.download(url, tmpFile, progress, statusText);
+ downloader.download(url, tmpFile, progress, statusText, progressListener);
- // Replace old index with the updated one
- if (outputFile.exists()) {
- if (!outputFile.delete()) {
- throw new Exception("An error occurred while updating platforms index! I can't delete file " + outputFile);
- }
- }
- if (!tmpFile.renameTo(outputFile)) {
- throw new Exception("An error occurred while updating platforms index! I can't rename file " + tmpFile);
- }
+ Files.deleteIfExists(outputFile.toPath());
+ Files.move(tmpFile.toPath(), outputFile.toPath());
return outputFile;
}
- protected void onProgress(Progress progress) {
- // Empty
- }
-
- public void deleteUnknownFiles(List downloadedPackageIndexFiles) throws IOException {
+ public synchronized void deleteUnknownFiles(List downloadedPackageIndexFiles) throws IOException {
File preferencesFolder = indexer.getIndexFile(".").getParentFile();
File[] additionalPackageIndexFiles = preferencesFolder.listFiles(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME));
if (additionalPackageIndexFiles == null) {
diff --git a/build/build.xml b/build/build.xml
index b3bc4fd1c..c8ecf2942 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -136,6 +136,8 @@
+
+
diff --git a/build/shared/lib/theme/close.png b/build/shared/lib/theme/close.png
new file mode 100644
index 000000000..8041c8bde
Binary files /dev/null and b/build/shared/lib/theme/close.png differ