From 4e977273554be45b50d0554a5bc2aaea5acb9d78 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 19 Sep 2019 19:31:58 +0200 Subject: [PATCH 1/6] Handle nested submenus of the Tools menu There is some code that, for each submenu under Tools, shows the selected item in the label of the submenu itself (e.g. before opening the submenu). This was done whenever the Tools menu is opened and iterated over all the items in the submenu to identify the s Previously, this code only looked at direct children of the submenu. Now, this code also looks through submenus recursively, to keep the code working even when items are divided over sub-submenus. This makes a small behaviour change: previously, the first selected item with a non-zero label was used. Now, the first selected item is used, which makes the code a bit cleaner. I cannot quickly see any case where the first selected item would have an empty text (and even more that there is *another* selected item), so this check seems unnecessary. If this case would occur nonetheless, it would only mean the selected item is not displayed in the tools menu, nothing would otherwise break. --- app/src/processing/app/Editor.java | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index f0c7c19248c..2ec29c498cb 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -761,6 +761,20 @@ private JMenu buildToolsMenu() { toolsMenu.add(item); toolsMenu.addMenuListener(new StubMenuListener() { + public JMenuItem getSelectedItemRecursive(JMenu menu) { + int count = menu.getItemCount(); + for (int i=0; i < count; i++) { + JMenuItem item = menu.getItem(i); + + if ((item instanceof JMenu)) + item = getSelectedItemRecursive((JMenu)item); + + if (item != null && item.isSelected()) + return item; + } + return null; + } + public void menuSelected(MenuEvent e) { //System.out.println("Tools menu selected."); populatePortMenu(); @@ -772,15 +786,9 @@ public void menuSelected(MenuEvent e) { String basename = name; int index = name.indexOf(':'); if (index > 0) basename = name.substring(0, index); - String sel = null; - int count = menu.getItemCount(); - for (int i=0; i < count; i++) { - JMenuItem item = menu.getItem(i); - if (item != null && item.isSelected()) { - sel = item.getText(); - if (sel != null) break; - } - } + + JMenuItem item = getSelectedItemRecursive(menu); + String sel = item != null ? item.getText() : null; if (sel == null) { if (!name.equals(basename)) menu.setText(basename); } else { From 89cf60074363ba40db4c5ce441950b1ee24153b9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Sun, 26 Jan 2020 15:59:43 +0100 Subject: [PATCH 2/6] Separate the boards menu per platform Previously, the Tools->Boards menu was one long list, divided into different platforms by (unselectable) headers. When more than one or two platforms were installed, this quickly results in a very long list of boards that is hard to navigate. This commit changes the board menu to have a submenu for each platform, where each submenu contains just the boards for that platform. Note that this first keeps a list of board items and then adds those to the boards menu later. This could have been done directly, but the intermediate list makes it easier to special-case single platform installations, as well as sort the list in subsequent commits. This fixes part of #8858. --- app/src/processing/app/Base.java | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index e9ddc9e4222..3d27f358623 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1481,24 +1481,21 @@ public void actionPerformed(ActionEvent actionevent) { ButtonGroup boardsButtonGroup = new ButtonGroup(); Map buttonGroupsMap = new HashMap<>(); + List platformMenus = new ArrayList(); + // Cycle through all packages - boolean first = true; for (TargetPackage targetPackage : BaseNoGui.packages.values()) { // For every package cycle through all platform for (TargetPlatform targetPlatform : targetPackage.platforms()) { - // Add a separator from the previous platform - if (!first) - boardMenu.add(new JSeparator()); - first = false; - // Add a title for each platform String platformLabel = targetPlatform.getPreferences().get("name"); - if (platformLabel != null && !targetPlatform.getBoards().isEmpty()) { - JMenuItem menuLabel = new JMenuItem(tr(platformLabel)); - menuLabel.setEnabled(false); - boardMenu.add(menuLabel); - } + if (platformLabel == null) + platformLabel = targetPackage.getId() + "-" + targetPlatform.getId(); + + JMenu platformBoardsMenu = new JMenu(tr(platformLabel)); + MenuScroller.setScrollerFor(platformBoardsMenu); + platformMenus.add(platformBoardsMenu); // Cycle through all boards of this platform for (TargetBoard board : targetPlatform.getBoards().values()) { @@ -1507,14 +1504,27 @@ public void actionPerformed(ActionEvent actionevent) { JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup, buttonGroupsMap, board, targetPlatform, targetPackage); - boardMenu.add(item); + platformBoardsMenu.add(item); boardsButtonGroup.add(item); } } } + JMenuItem firstBoardItem = null; + for (JMenu platformMenu : platformMenus) { + if (firstBoardItem == null && platformMenu.getItemCount() > 0) + firstBoardItem = platformMenu.getItem(0); + boardMenu.add(platformMenu); + } + + if (firstBoardItem == null) { + throw new IllegalStateException("No available boards"); + } + + // If there is no current board yet (first startup, or selected + // board no longer defined), select first available board. if (menuItemsToClickAfterStartup.isEmpty()) { - menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu)); + menuItemsToClickAfterStartup.add(firstBoardItem); } for (JMenuItem menuItemToClick : menuItemsToClickAfterStartup) { @@ -1669,16 +1679,6 @@ private static JMenuItem selectVisibleSelectedOrFirstMenuItem(JMenu menu) { throw new IllegalStateException("Menu has no enabled items"); } - private static JMenuItem selectFirstEnabledMenuItem(JMenu menu) { - for (int i = 1; i < menu.getItemCount(); i++) { - JMenuItem item = menu.getItem(i); - if (item != null && item.isEnabled()) { - return item; - } - } - throw new IllegalStateException("Menu has no enabled items"); - } - public void rebuildProgrammerMenu() { programmerMenus = new LinkedList<>(); ButtonGroup group = new ButtonGroup(); From 1964b81c3290d80de11736e19640ca52e6cb6345 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 19 Sep 2019 17:03:34 +0200 Subject: [PATCH 3/6] Do not use a boards submenu with just one platform When just one platform is installed, it does not make much sense to use a submenu, so just add the boards directly under the boards menu as before. --- app/src/processing/app/Base.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 3d27f358623..130dc8895a8 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1511,10 +1511,21 @@ public void actionPerformed(ActionEvent actionevent) { } JMenuItem firstBoardItem = null; - for (JMenu platformMenu : platformMenus) { - if (firstBoardItem == null && platformMenu.getItemCount() > 0) - firstBoardItem = platformMenu.getItem(0); - boardMenu.add(platformMenu); + if (platformMenus.size() == 1) { + // When just one platform exists, add the board items directly, + // rather than using a submenu + for (Component boardItem : platformMenus.get(0).getMenuComponents()) { + boardMenu.add(boardItem); + if (firstBoardItem == null) + firstBoardItem = (JMenuItem)boardItem; + } + } else { + // For multiple platforms, use submenus + for (JMenu platformMenu : platformMenus) { + if (firstBoardItem == null && platformMenu.getItemCount() > 0) + firstBoardItem = platformMenu.getItem(0); + boardMenu.add(platformMenu); + } } if (firstBoardItem == null) { From 55fa3f542fc19e73351efad093a4c1ba9165103f Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 3 Feb 2020 17:10:55 +0100 Subject: [PATCH 4/6] Sort board submenus alphabetically This sorts the board submenus themselves, based on the displayed name. This does not change the ordering of board items within these submenus (which uses the order from boards.txt). --- app/src/processing/app/Base.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 130dc8895a8..0ada91f15e1 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1510,6 +1510,8 @@ public void actionPerformed(ActionEvent actionevent) { } } + platformMenus.sort((x,y) -> x.getText().compareToIgnoreCase(y.getText())); + JMenuItem firstBoardItem = null; if (platformMenus.size() == 1) { // When just one platform exists, add the board items directly, From e00304935b3a22a2d28ff0ecc49813ad6eadd7b9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 25 Mar 2020 12:51:39 +0100 Subject: [PATCH 5/6] Do not translate labels of boards submenus Otherwise it may happen some weird sorting when untraslated and translated labels are sorted together: Arduino megaAVR Boards Arduino nRF52 Board ESP32 Arduino ESP8266 Modules Schede Arduino AVR <-- the localized string falls to the bottom Also there is no way for 3rd party boards developers to actually provide a translation, so let's just remove them. --- app/src/processing/app/Base.java | 2 +- arduino-core/src/processing/app/I18n.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 0ada91f15e1..1af97af5261 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1493,7 +1493,7 @@ public void actionPerformed(ActionEvent actionevent) { if (platformLabel == null) platformLabel = targetPackage.getId() + "-" + targetPlatform.getId(); - JMenu platformBoardsMenu = new JMenu(tr(platformLabel)); + JMenu platformBoardsMenu = new JMenu(platformLabel); MenuScroller.setScrollerFor(platformBoardsMenu); platformMenus.add(platformBoardsMenu); diff --git a/arduino-core/src/processing/app/I18n.java b/arduino-core/src/processing/app/I18n.java index 0ab961aa9ed..1f1a9f93703 100644 --- a/arduino-core/src/processing/app/I18n.java +++ b/arduino-core/src/processing/app/I18n.java @@ -106,10 +106,6 @@ public static String format(String fmt, Object... args) { * This method is an hack to extract words with gettext tool. */ protected static void unusedStrings() { - // These phrases are defined in the "platform.txt". - tr("Arduino AVR Boards"); - tr("Arduino ARM (32-bits) Boards"); - // This word is defined in the "boards.txt". tr("Processor"); } From b821f7561b3cb354caa8415cdd29bdb0c70196d5 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 25 Mar 2020 12:59:36 +0100 Subject: [PATCH 6/6] Removed some trivial warnings --- app/src/processing/app/Base.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 1af97af5261..7af728fdd49 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -999,9 +999,9 @@ public boolean handleQuit() { // kill uploader (if still alive) UploaderUtils uploaderInstance = new UploaderUtils(); Uploader uploader = uploaderInstance.getUploaderByPreferences(false); - if (uploader != null && uploader.programmerPid != null && uploader.programmerPid.isAlive()) { + if (uploader != null && Uploader.programmerPid != null && Uploader.programmerPid.isAlive()) { // kill the stuck programmer - uploader.programmerPid.destroyForcibly(); + Uploader.programmerPid.destroyForcibly(); } if (handleQuitEach()) { @@ -1444,8 +1444,9 @@ public void actionPerformed(ActionEvent actionevent) { String filterText = ""; String dropdownItem = ""; if (actionevent instanceof Event) { - filterText = ((Event) actionevent).getPayload().get("filterText").toString(); - dropdownItem = ((Event) actionevent).getPayload().get("dropdownItem").toString(); + Event e = ((Event) actionevent); + filterText = e.getPayload().get("filterText").toString(); + dropdownItem = e.getPayload().get("dropdownItem").toString(); } try { openBoardsManager(filterText, dropdownItem); @@ -1481,7 +1482,7 @@ public void actionPerformed(ActionEvent actionevent) { ButtonGroup boardsButtonGroup = new ButtonGroup(); Map buttonGroupsMap = new HashMap<>(); - List platformMenus = new ArrayList(); + List platformMenus = new ArrayList<>(); // Cycle through all packages for (TargetPackage targetPackage : BaseNoGui.packages.values()) { @@ -1602,7 +1603,7 @@ public void actionPerformed(ActionEvent e) { }; List boards = (List) subAction.getValue("board"); if (boards == null) { - boards = new ArrayList(); + boards = new ArrayList<>(); } boards.add(board); subAction.putValue("board", boards); @@ -2003,6 +2004,7 @@ public void keyPressed(KeyEvent e) { Base.this.handleFontSizeChange(-1); } break; + default: } } }