Skip to content

Commit

Permalink
Merge pull request arduino#9158 from joew46167/master
Browse files Browse the repository at this point in the history
Make update boards and libraries startup dialog accessible -
  • Loading branch information
facchinm authored Aug 21, 2019
2 parents 5bb9f87 + 710667d commit 140f8e3
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 20 deletions.
74 changes: 64 additions & 10 deletions app/src/cc/arduino/contributions/ContributionsSelfCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,34 @@

package cc.arduino.contributions;

import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
import cc.arduino.contributions.libraries.LibraryInstaller;
import cc.arduino.contributions.libraries.filters.UpdatableLibraryPredicate;
import cc.arduino.contributions.packages.ContributionInstaller;
import cc.arduino.contributions.packages.filters.UpdatablePlatformPredicate;
import cc.arduino.view.NotificationPopup;
import processing.app.Base;
import processing.app.BaseNoGui;
import processing.app.Editor;
import processing.app.I18n;
import org.apache.logging.log4j.LogManager;
import processing.app.*;

import javax.swing.*;
import javax.swing.event.HyperlinkListener;

import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.net.URL;
import java.util.TimerTask;

import static processing.app.I18n.tr;

public class ContributionsSelfCheck extends TimerTask {
public class ContributionsSelfCheck extends TimerTask implements NotificationPopup.OptionalButtonCallbacks {

private final Base base;
private final HyperlinkListener hyperlinkListener;
private final ContributionInstaller contributionInstaller;
private final LibraryInstaller libraryInstaller;
private final ProgressListener progressListener;
private final String boardsManagerURL = "http://boardsmanager/DropdownUpdatableCoresItem";
private final String libraryManagerURL = "http://librarymanager/DropdownUpdatableLibrariesItem";

private volatile boolean cancelled;
private volatile NotificationPopup notificationPopup;
Expand All @@ -81,13 +83,41 @@ public void run() {
return;
}

String text;
boolean setAccessible = PreferencesData.getBoolean("ide.accessible");
final String text;
final String button1Name;
final String button2Name;
String openAnchorBoards = "<a href=\"" + boardsManagerURL + "\">";
String closeAnchorBoards = "</a>";
String openAnchorLibraries = "<a href=\"" + libraryManagerURL + "\">";
String closeAnchorLibraries = "</a>";

// if accessibility mode and board updates are available set the button name and clear the anchors
if(setAccessible && updatablePlatforms) {
button1Name = tr("Boards");
openAnchorBoards = "";
closeAnchorBoards = "";
}
else { // when not accessibility mode or no boards to update no button is needed
button1Name = null;
}

// if accessibility mode and libraries updates are available set the button name and clear the anchors
if (setAccessible && updatableLibraries) {
button2Name = tr("Libraries");
openAnchorLibraries = "";
closeAnchorLibraries = "";
}
else { // when not accessibility mode or no libraries to update no button is needed
button2Name = null;
}

if (updatableLibraries && !updatablePlatforms) {
text = I18n.format(tr("Updates available for some of your {0}libraries{1}"), "<a href=\"http://librarymanager/DropdownUpdatableLibrariesItem\">", "</a>");
text = I18n.format(tr("Updates available for some of your {0}libraries{1}"), openAnchorLibraries, closeAnchorLibraries);
} else if (!updatableLibraries && updatablePlatforms) {
text = I18n.format(tr("Updates available for some of your {0}boards{1}"), "<a href=\"http://boardsmanager/DropdownUpdatableCoresItem\">", "</a>");
text = I18n.format(tr("Updates available for some of your {0}boards{1}"), openAnchorBoards, closeAnchorBoards);
} else {
text = I18n.format(tr("Updates available for some of your {0}boards{1} and {2}libraries{3}"), "<a href=\"http://boardsmanager/DropdownUpdatableCoresItem\">", "</a>", "<a href=\"http://librarymanager/DropdownUpdatableLibrariesItem\">", "</a>");
text = I18n.format(tr("Updates available for some of your {0}libraries{1} and {2}libraries{3}"), openAnchorBoards, closeAnchorBoards, openAnchorLibraries, closeAnchorLibraries);
}

if (cancelled) {
Expand All @@ -96,7 +126,13 @@ public void run() {

SwingUtilities.invokeLater(() -> {
Editor ed = base.getActiveEditor();
notificationPopup = new NotificationPopup(ed, hyperlinkListener, text);
boolean accessibleIde = PreferencesData.getBoolean("ide.accessible");
if (accessibleIde) {
notificationPopup = new NotificationPopup(ed, hyperlinkListener, text, false, this, button1Name, button2Name);
}
else { // if not accessible view leave it the same
notificationPopup = new NotificationPopup(ed, hyperlinkListener, text);
}
if (ed.isFocused()) {
notificationPopup.begin();
return;
Expand All @@ -122,6 +158,24 @@ public void windowGainedFocus(WindowEvent evt) {
});
}

private void goToManager(String link) {
try {
((UpdatableBoardsLibsFakeURLsHandler) hyperlinkListener).openBoardLibManager(new URL(link));
}
catch (Exception e){
LogManager.getLogger(ContributionsSelfCheck.class).warn("Exception while attempting to go to board manager", e);
}
}
// callback for boards button
public void onOptionalButton1Callback() {
goToManager(boardsManagerURL);
}

// callback for libraries button
public void onOptionalButton2Callback() {
goToManager(libraryManagerURL);
}

static boolean checkForUpdatablePlatforms() {
return BaseNoGui.indexer.getPackages().stream()
.flatMap(pack -> pack.getPlatforms().stream())
Expand Down
129 changes: 120 additions & 9 deletions app/src/cc/arduino/view/NotificationPopup.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,7 @@
import java.awt.Frame;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;

Expand All @@ -55,22 +50,46 @@
import javax.swing.event.HyperlinkListener;

import cc.arduino.Constants;
import processing.app.PreferencesData;
import processing.app.Theme;

public class NotificationPopup extends JDialog {
import java.awt.event.KeyEvent;

import static processing.app.I18n.tr;

public class NotificationPopup extends JDialog {
private Timer autoCloseTimer = new Timer(false);
private boolean autoClose = true;
private OptionalButtonCallbacks optionalButtonCallbacks;

public interface OptionalButtonCallbacks {
void onOptionalButton1Callback();
void onOptionalButton2Callback();
}

public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener,
String message) {
this(parent, hyperlinkListener, message, true);
this(parent, hyperlinkListener, message, true, null, null, null);
}

public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener,
String message, boolean _autoClose) {
this(parent, hyperlinkListener, message, _autoClose, null, null, null);
}

public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener,
String message, boolean _autoClose, OptionalButtonCallbacks listener, String button1Name, String button2Name) {
super(parent, false);
autoClose = _autoClose;

if (!PreferencesData.getBoolean("ide.accessible")) {
// often auto-close is too fast for users of screen readers, so don't allow it.
autoClose = _autoClose;
}
else {
autoClose = false;
}
optionalButtonCallbacks = listener;

setLayout(new FlowLayout());
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setUndecorated(true);
Expand All @@ -90,13 +109,101 @@ public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener,
text.addHyperlinkListener(hyperlinkListener);
add(text);

if (button1Name != null) {
JButton optionalButton1 = new JButton(tr(button1Name));
MouseAdapter button1Action = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (optionalButtonCallbacks != null) {
optionalButtonCallbacks.onOptionalButton1Callback();
}
}
};
optionalButton1.addMouseListener(button1Action);

KeyListener button1Key = new KeyListener() {
// Ignore when the key is typed - only act once the key is released
public void keyTyped(KeyEvent e) {
// do nothing here, wait until the key is released
}

// Ignore when the key is pressed - only act once the key is released
public void keyPressed(KeyEvent e) {
// do nothing here, wait until the key is released
}

public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_ENTER) || (key == KeyEvent.VK_SPACE)) {
optionalButtonCallbacks.onOptionalButton1Callback();
}
}
};
optionalButton1.addKeyListener(button1Key);
add(optionalButton1);
}

if (button2Name != null) {
JButton optionalButton2 = new JButton(tr(button2Name));
MouseAdapter button2Action = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (optionalButtonCallbacks != null) {
optionalButtonCallbacks.onOptionalButton2Callback();
}
}
};
optionalButton2.addMouseListener(button2Action);

KeyListener button2Key = new KeyListener() {
// Ignore when the key is typed - only act once the key is released
public void keyTyped(KeyEvent e) {
// do nothing here, wait until the key is released
}

// Ignore when the key is pressed - only act once the key is released
public void keyPressed(KeyEvent e) {
// do nothing here, wait until the key is released
}

public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_ENTER) || (key == KeyEvent.VK_SPACE)) {
optionalButtonCallbacks.onOptionalButton2Callback();
}
}
};
optionalButton2.addKeyListener(button2Key);
add(optionalButton2);
}

Image close = Theme.getThemeImage("close", this, scale(22), scale(22));
JButton closeButton = new JButton(new ImageIcon(close));
closeButton.setBorder(null);
closeButton.setBorderPainted(false);
closeButton.setHideActionText(true);
closeButton.setOpaque(false);
closeButton.setBackground(new Color(0, 0, 0, 0));
closeButton.getAccessibleContext().setAccessibleDescription(tr("Close"));
KeyListener closeKey = new KeyListener() {
// Ignore when the key is typed - only act once the key is released
public void keyTyped(KeyEvent e) {
// do nothing here, wait until the key is released
}

// Ignore when the key is pressed - only act once the key is released
public void keyPressed(KeyEvent e) {
// do nothing here, wait until the key is released
}

public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_ENTER) || (key == KeyEvent.VK_SPACE)) {
close();
}
}
};
closeButton.addKeyListener(closeKey);
add(closeButton);

MouseAdapter closeOnClick = new MouseAdapter() {
Expand Down Expand Up @@ -158,5 +265,9 @@ public void run() {
}, Constants.NOTIFICATION_POPUP_AUTOCLOSE_DELAY);
}
setVisible(true);
if (PreferencesData.getBoolean("ide.accessible")) {
requestFocus();
setModal(true);
}
}
}
9 changes: 8 additions & 1 deletion app/src/cc/arduino/view/preferences/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ private void initComponents() {
externalEditorBox = new javax.swing.JCheckBox();
checkUpdatesBox = new javax.swing.JCheckBox();
saveVerifyUploadBox = new javax.swing.JCheckBox();
accessibleIDEBox = new javax.swing.JCheckBox();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
scaleSpinner = new javax.swing.JSpinner();
Expand Down Expand Up @@ -281,6 +282,9 @@ public void mouseEntered(java.awt.event.MouseEvent evt) {
saveVerifyUploadBox.setText(tr("Save when verifying or uploading"));
checkboxesContainer.add(saveVerifyUploadBox);

accessibleIDEBox.setText(tr("Use accessibility features"));
checkboxesContainer.add(accessibleIDEBox);

jLabel1.setText(tr("Interface scale:"));

jLabel2.setText(tr(" (requires restart of Arduino)"));
Expand Down Expand Up @@ -713,6 +717,7 @@ private void autoScaleCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//
private javax.swing.JCheckBox autoScaleCheckBox;
private javax.swing.JButton browseButton;
private javax.swing.JCheckBox checkUpdatesBox;
private javax.swing.JCheckBox accessibleIDEBox;
private javax.swing.JPanel checkboxesContainer;
private javax.swing.JComboBox comboLanguage;
private javax.swing.JLabel comboLanguageLabel;
Expand Down Expand Up @@ -826,7 +831,7 @@ private void savePreferencesData() {

PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected());

PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
PreferencesData.setBoolean("ide.accessible", accessibleIDEBox.isSelected());

PreferencesData.set("boardsmanager.additional.urls", additionalBoardsManagerField.getText().replace("\r\n", "\n").replace("\r", "\n").replace("\n", ","));

Expand Down Expand Up @@ -902,6 +907,8 @@ private void showPreferencesData() {
PreferencesData.setBoolean("editor.update_extension", true);
}

accessibleIDEBox.setSelected(PreferencesData.getBoolean("ide.accessible"));

saveVerifyUploadBox.setSelected(PreferencesData.getBoolean("editor.save_on_verify"));

additionalBoardsManagerField.setText(PreferencesData.get("boardsmanager.additional.urls"));
Expand Down

0 comments on commit 140f8e3

Please sign in to comment.