diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 62ebfc2acaf..897df1dd01a 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -117,6 +117,13 @@ public class Base { List editors = Collections.synchronizedList(new ArrayList()); Editor activeEditor; + private static JMenu boardMenu; + private static ButtonGroup boardsButtonGroup; + private static ButtonGroup recentBoardsButtonGroup; + private static Map buttonGroupsMap; + private static List menuItemsToClickAfterStartup; + private static MenuScroller boardMenuScroller; + // these menus are shared so that the board and serial port selections // are the same for all windows (since the board and serial port that are // actually used are determined by the preferences, which are shared) @@ -552,6 +559,36 @@ protected boolean restoreSketches() throws Exception { return (opened > 0); } + protected boolean restoreRecentlyUsedBoards() throws Exception { + // Iterate through all sketches that were open last time p5 was running. + // If !windowPositionValid, then ignore the coordinates found for each. + + // Save the sketch path and window placement for each open sketch + int count = PreferencesData.getInteger("last.recent_boards.count"); + int opened = 0; + for (int i = count - 1; i >= 0; i--) { + String fqbn = PreferencesData.get("last.recent_board" + i + ".fqbn"); + if (fqbn == null) { + continue; + } + //selectTargetBoard(new TargetBoard()); + } + return count != 0; + } + + /** + * Store list of sketches that are currently open. + * Called when the application is quitting and documents are still open. + */ + protected void storeRecentlyUsedBoards() { + int i = 0; + for (TargetBoard board : BaseNoGui.getRecentlyUsedBoards()) { + PreferencesData.set("last.recent_board" + i + ".fqbn", board.getFQBN()); + i++; + } + PreferencesData.setInteger("last.recent_boards.count", BaseNoGui.getRecentlyUsedBoards().size()); + } + /** * Store screen dimensions on last close */ @@ -1313,6 +1350,63 @@ public void rebuildExamplesMenu(JMenu menu) { private static String priorPlatformFolder; private static boolean newLibraryImported; + public void selectTargetBoard(TargetBoard targetBoard) { + for (int i = 0; i < boardMenu.getItemCount(); i++) { + JMenuItem menuItem = boardMenu.getItem(i); + if (!(menuItem instanceof JRadioButtonMenuItem)) { + continue; + } + + JRadioButtonMenuItem radioButtonMenuItem = ((JRadioButtonMenuItem) menuItem); + if (targetBoard.getName().equals(radioButtonMenuItem.getText())) { + radioButtonMenuItem.setSelected(true); + break; + } + } + + BaseNoGui.selectBoard(targetBoard); + filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, targetBoard, 1); + + onBoardOrPortChange(); + rebuildImportMenu(Editor.importMenu); + rebuildExamplesMenu(Editor.examplesMenu); + try { + rebuildRecentBoardsMenu(); + } catch (Exception e) { + // fail silently + } + } + + public void rebuildRecentBoardsMenu() throws Exception { + + Enumeration btns = recentBoardsButtonGroup.getElements(); + while (btns.hasMoreElements()) { + AbstractButton x = btns.nextElement(); + if (x.isSelected()) { + return; + } + } + btns = recentBoardsButtonGroup.getElements(); + while (btns.hasMoreElements()) { + AbstractButton x = btns.nextElement(); + boardMenu.remove(x); + } + int index = 0; + for (TargetBoard board : BaseNoGui.getRecentlyUsedBoards()) { + JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup, + buttonGroupsMap, + board, board.getContainerPlatform(), board.getContainerPlatform().getContainerPackage()); + boardMenu.insert(item, 3); + item.setAccelerator(KeyStroke.getKeyStroke('1' + index, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | + ActionEvent.SHIFT_MASK)); + recentBoardsButtonGroup.add(item); + boardsButtonGroup.add(item); + index ++; + } + boardMenuScroller.setTopFixedCount(3 + index); + } + public void onBoardOrPortChange() { BaseNoGui.onBoardOrPortChange(); @@ -1406,9 +1500,10 @@ public void rebuildBoardsMenu() throws Exception { boardsCustomMenus = new LinkedList<>(); // The first custom menu is the "Board" selection submenu - JMenu boardMenu = new JMenu(tr("Board")); + boardMenu = new JMenu(tr("Board")); boardMenu.putClientProperty("removeOnWindowDeactivation", true); - MenuScroller.setScrollerFor(boardMenu).setTopFixedCount(1); + boardMenuScroller = MenuScroller.setScrollerFor(boardMenu); + boardMenuScroller.setTopFixedCount(1); boardMenu.add(new JMenuItem(new AbstractAction(tr("Boards Manager...")) { public void actionPerformed(ActionEvent actionevent) { @@ -1448,21 +1543,26 @@ public void actionPerformed(ActionEvent actionevent) { boardsCustomMenus.add(customMenu); } - List menuItemsToClickAfterStartup = new LinkedList<>(); + List _menuItemsToClickAfterStartup = new LinkedList<>(); + boardsButtonGroup = new ButtonGroup(); + recentBoardsButtonGroup = new ButtonGroup(); + buttonGroupsMap = new HashMap<>(); + + boolean hasRecentBoardsMenu = (PreferencesData.getInteger("editor.recent_boards.size", 4) != 0); - ButtonGroup boardsButtonGroup = new ButtonGroup(); - Map buttonGroupsMap = new HashMap<>(); + if (hasRecentBoardsMenu) { + JMenuItem recentLabel = new JMenuItem(tr("Recently used boards")); + recentLabel.setEnabled(false); + boardMenu.add(recentLabel); + } // 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; + boardMenu.add(new JSeparator()); // Add a title for each platform String platformLabel = targetPlatform.getPreferences().get("name"); @@ -1476,7 +1576,7 @@ public void actionPerformed(ActionEvent actionevent) { for (TargetBoard board : targetPlatform.getBoards().values()) { if (board.getPreferences().get("hide") != null) continue; - JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup, + JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, _menuItemsToClickAfterStartup, buttonGroupsMap, board, targetPlatform, targetPackage); boardMenu.add(item); @@ -1485,14 +1585,16 @@ public void actionPerformed(ActionEvent actionevent) { } } - if (menuItemsToClickAfterStartup.isEmpty()) { - menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu)); + if (_menuItemsToClickAfterStartup.isEmpty()) { + _menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu)); } - for (JMenuItem menuItemToClick : menuItemsToClickAfterStartup) { + for (JMenuItem menuItemToClick : _menuItemsToClickAfterStartup) { menuItemToClick.setSelected(true); menuItemToClick.getAction().actionPerformed(new ActionEvent(this, -1, "")); } + + menuItemsToClickAfterStartup = _menuItemsToClickAfterStartup; } private JRadioButtonMenuItem createBoardMenusAndCustomMenus( @@ -1512,12 +1614,7 @@ private JRadioButtonMenuItem createBoardMenusAndCustomMenus( @SuppressWarnings("serial") Action action = new AbstractAction(board.getName()) { public void actionPerformed(ActionEvent actionevent) { - BaseNoGui.selectBoard((TargetBoard) getValue("b")); - filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, (TargetBoard) getValue("b"), 1); - - onBoardOrPortChange(); - rebuildImportMenu(Editor.importMenu); - rebuildExamplesMenu(Editor.examplesMenu); + selectTargetBoard((TargetBoard) getValue("b")); } }; action.putValue("b", board); @@ -1533,6 +1630,9 @@ public void actionPerformed(ActionEvent actionevent) { for (final String menuId : customMenus.keySet()) { String title = customMenus.get(menuId); JMenu menu = getBoardCustomMenu(tr(title)); + if (menu == null) { + continue; + } if (board.hasMenu(menuId)) { PreferencesMap boardCustomMenu = board.getMenuLabels(menuId); @@ -1595,13 +1695,13 @@ private static boolean ifThereAreVisibleItemsOn(JMenu menu) { return false; } - private JMenu getBoardCustomMenu(String label) throws Exception { + private JMenu getBoardCustomMenu(String label) { for (JMenu menu : boardsCustomMenus) { if (label.equals(menu.getText())) { return menu; } } - throw new Exception("Custom menu not found!"); + return null; } public List getProgrammerMenus() { diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 0a58769712a..e0fa5f1d5e9 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -915,6 +915,12 @@ static public void saveFile(String str, File file) throws IOException { } } + static private LinkedList recentlyUsedBoards = new LinkedList(); + + static public LinkedList getRecentlyUsedBoards() { + return recentlyUsedBoards; + } + static public void selectBoard(TargetBoard targetBoard) { TargetPlatform targetPlatform = targetBoard.getContainerPlatform(); TargetPackage targetPackage = targetPlatform.getContainerPackage(); @@ -926,6 +932,13 @@ static public void selectBoard(TargetBoard targetBoard) { File platformFolder = targetPlatform.getFolder(); PreferencesData.set("runtime.platform.path", platformFolder.getAbsolutePath()); PreferencesData.set("runtime.hardware.path", platformFolder.getParentFile().getAbsolutePath()); + + if (!recentlyUsedBoards.contains(targetBoard)) { + recentlyUsedBoards.add(targetBoard); + } + if (recentlyUsedBoards.size() > PreferencesData.getInteger("editor.recent_boards.size", 4)) { + recentlyUsedBoards.remove(); + } } public static void selectSerialPort(String port) {