/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander 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 3 of the License, or * (at your option) any later version. * * muCommander 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, see <http://www.gnu.org/licenses/>. */ package com.mucommander.ui.main.menu; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Hashtable; import java.util.Iterator; import java.util.WeakHashMap; import javax.swing.AbstractAction; import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JSeparator; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import com.mucommander.bonjour.BonjourMenu; import com.mucommander.bonjour.BonjourService; import com.mucommander.bookmark.Bookmark; import com.mucommander.bookmark.BookmarkManager; import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.protocol.local.LocalFile; import com.mucommander.commons.runtime.OsFamily; import com.mucommander.conf.MuConfigurations; import com.mucommander.conf.MuPreference; import com.mucommander.conf.MuPreferences; import com.mucommander.desktop.DesktopManager; import com.mucommander.text.Translator; import com.mucommander.ui.action.ActionManager; import com.mucommander.ui.action.ActionParameters; import com.mucommander.ui.action.MuAction; import com.mucommander.ui.action.impl.AddBookmarkAction; import com.mucommander.ui.action.impl.NewTabAction; import com.mucommander.ui.action.impl.BatchRenameAction; import com.mucommander.ui.action.impl.BringAllToFrontAction; import com.mucommander.ui.action.impl.CalculateChecksumAction; import com.mucommander.ui.action.impl.ChangeDateAction; import com.mucommander.ui.action.impl.ChangeLocationAction; import com.mucommander.ui.action.impl.ChangePermissionsAction; import com.mucommander.ui.action.impl.CheckForUpdatesAction; import com.mucommander.ui.action.impl.CloseWindowAction; import com.mucommander.ui.action.impl.CombineFilesAction; import com.mucommander.ui.action.impl.CompareFoldersAction; import com.mucommander.ui.action.impl.ConnectToServerAction; import com.mucommander.ui.action.impl.CopyFileBaseNamesAction; import com.mucommander.ui.action.impl.CopyFileNamesAction; import com.mucommander.ui.action.impl.CopyFilePathsAction; import com.mucommander.ui.action.impl.CopyFilesToClipboardAction; import com.mucommander.ui.action.impl.CustomizeCommandBarAction; import com.mucommander.ui.action.impl.DonateAction; import com.mucommander.ui.action.impl.EditBookmarksAction; import com.mucommander.ui.action.impl.EditCredentialsAction; import com.mucommander.ui.action.impl.EmailAction; import com.mucommander.ui.action.impl.ExploreBookmarksAction; import com.mucommander.ui.action.impl.GoBackAction; import com.mucommander.ui.action.impl.GoForwardAction; import com.mucommander.ui.action.impl.GoToDocumentationAction; import com.mucommander.ui.action.impl.GoToForumsAction; import com.mucommander.ui.action.impl.GoToParentAction; import com.mucommander.ui.action.impl.GoToParentInBothPanelsAction; import com.mucommander.ui.action.impl.GoToParentInOtherPanelAction; import com.mucommander.ui.action.impl.GoToRootAction; import com.mucommander.ui.action.impl.GoToWebsiteAction; import com.mucommander.ui.action.impl.InvertSelectionAction; import com.mucommander.ui.action.impl.MarkAllAction; import com.mucommander.ui.action.impl.MarkExtensionAction; import com.mucommander.ui.action.impl.MarkGroupAction; import com.mucommander.ui.action.impl.MarkSelectedFileAction; import com.mucommander.ui.action.impl.MaximizeWindowAction; import com.mucommander.ui.action.impl.MinimizeWindowAction; import com.mucommander.ui.action.impl.NewWindowAction; import com.mucommander.ui.action.impl.OpenAction; import com.mucommander.ui.action.impl.OpenInBothPanelsAction; import com.mucommander.ui.action.impl.OpenInNewTabAction; import com.mucommander.ui.action.impl.OpenInOtherPanelAction; import com.mucommander.ui.action.impl.OpenLocationAction; import com.mucommander.ui.action.impl.OpenNativelyAction; import com.mucommander.ui.action.impl.PackAction; import com.mucommander.ui.action.impl.PasteClipboardFilesAction; import com.mucommander.ui.action.impl.QuitAction; import com.mucommander.ui.action.impl.RecallNextWindowAction; import com.mucommander.ui.action.impl.RecallPreviousWindowAction; import com.mucommander.ui.action.impl.RecallWindowAction; import com.mucommander.ui.action.impl.ReportBugAction; import com.mucommander.ui.action.impl.RevealInDesktopAction; import com.mucommander.ui.action.impl.ReverseSortOrderAction; import com.mucommander.ui.action.impl.RunCommandAction; import com.mucommander.ui.action.impl.SetSameFolderAction; import com.mucommander.ui.action.impl.ShowAboutAction; import com.mucommander.ui.action.impl.ShowBookmarksQLAction; import com.mucommander.ui.action.impl.ShowDebugConsoleAction; import com.mucommander.ui.action.impl.ShowFilePropertiesAction; import com.mucommander.ui.action.impl.ShowKeyboardShortcutsAction; import com.mucommander.ui.action.impl.ShowParentFoldersQLAction; import com.mucommander.ui.action.impl.ShowPreferencesAction; import com.mucommander.ui.action.impl.ShowRecentExecutedFilesQLAction; import com.mucommander.ui.action.impl.ShowRecentLocationsQLAction; import com.mucommander.ui.action.impl.ShowRootFoldersQLAction; import com.mucommander.ui.action.impl.ShowServerConnectionsAction; import com.mucommander.ui.action.impl.ShowTabsQLAction; import com.mucommander.ui.action.impl.SplitEquallyAction; import com.mucommander.ui.action.impl.SplitFileAction; import com.mucommander.ui.action.impl.SplitHorizontallyAction; import com.mucommander.ui.action.impl.SplitVerticallyAction; import com.mucommander.ui.action.impl.SwapFoldersAction; import com.mucommander.ui.action.impl.ToggleAutoSizeAction; import com.mucommander.ui.action.impl.ToggleCommandBarAction; import com.mucommander.ui.action.impl.ToggleHiddenFilesAction; import com.mucommander.ui.action.impl.ToggleShowFoldersFirstAction; import com.mucommander.ui.action.impl.ToggleSinglePanelAction; import com.mucommander.ui.action.impl.ToggleStatusBarAction; import com.mucommander.ui.action.impl.ToggleToolBarAction; import com.mucommander.ui.action.impl.ToggleTreeAction; import com.mucommander.ui.action.impl.UnmarkAllAction; import com.mucommander.ui.action.impl.UnmarkGroupAction; import com.mucommander.ui.action.impl.UnpackAction; import com.mucommander.ui.dialog.InformationDialog; import com.mucommander.ui.dialog.pref.theme.ThemeEditorDialog; import com.mucommander.ui.helper.MenuToolkit; import com.mucommander.ui.helper.MnemonicHelper; import com.mucommander.ui.main.MainFrame; import com.mucommander.ui.main.WindowManager; import com.mucommander.ui.main.table.Column; import com.mucommander.ui.main.table.FileTable; import com.mucommander.ui.theme.Theme; import com.mucommander.ui.theme.ThemeManager; import com.mucommander.ui.viewer.FileFrame; /** * This class is the main menu bar. It takes care of displaying menu and menu items and triggering * the proper actions. * * <p><b>Implementation note</b>: for performance reasons, some menu items are created/enabled/disabled when corresponding menus * are selected, instead of monitoring the MainFrame's state and unnecessarily creating/enabling/disabling menu items * when they are not visible. However, this prevents keyboard shortcuts from being managed by the menu bar for those * dynamic items. * * @author Maxence Bernard */ public class MainMenuBar extends JMenuBar implements ActionListener, MenuListener { private MainFrame mainFrame; // View menu private JMenu viewMenu; private JMenu themesMenu; private JCheckBoxMenuItem[] sortByItems = new JCheckBoxMenuItem[Column.values().length]; private JMenu columnsMenu; private JCheckBoxMenuItem[] toggleColumnItems = new JCheckBoxMenuItem[Column.values().length]; private JCheckBoxMenuItem toggleToggleAutoSizeItem; private JCheckBoxMenuItem toggleShowFoldersFirstItem; private JCheckBoxMenuItem toggleShowHiddenFilesItem; private JCheckBoxMenuItem toggleTreeItem; private JCheckBoxMenuItem toggleSinglePanel; /* TODO branch private JCheckBoxMenuItem toggleBranchView; */ // Go menu private JMenu goMenu; private int volumeOffset; // Bookmark menu private JMenu bookmarksMenu; private int bookmarksOffset; // Index of the first bookmark menu item // Window menu private JMenu windowMenu; private int windowOffset; // Index of the first window menu item private JCheckBoxMenuItem splitHorizontallyItem; private JCheckBoxMenuItem splitVerticallyItem; /** Maps window menu items onto weakly-referenced frames */ private WeakHashMap<JMenuItem, Frame> windowMenuFrames; private final static String RECALL_WINDOW_ACTION_IDS[] = { com.mucommander.ui.action.impl.RecallWindow1Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow2Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow3Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow4Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow5Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow6Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow7Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow8Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow9Action.Descriptor.ACTION_ID, com.mucommander.ui.action.impl.RecallWindow10Action.Descriptor.ACTION_ID }; /** * Creates a new MenuBar for the given MainFrame. */ public MainMenuBar(MainFrame mainFrame) { this.mainFrame = mainFrame; // Disable menu bar (NOT menu item) mnemonics under Mac OS X because of a bug: when screen menu bar is enabled // and a menu is triggered by a mnemonic, the menu pops up where it would appear with a regular menu bar // (i.e. with screen menu bar disabled). MnemonicHelper menuMnemonicHelper = OsFamily.MAC_OS_X.isCurrent()?null:new MnemonicHelper(); MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); MnemonicHelper menuItemMnemonicHelper2 = new MnemonicHelper(); // File menu JMenu fileMenu = MenuToolkit.addMenu(Translator.get("file_menu"), menuMnemonicHelper, this); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(NewWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(NewTabAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); fileMenu.add(new JSeparator()); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(OpenAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(OpenNativelyAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); fileMenu.add(new OpenWithMenu(mainFrame)); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(OpenInNewTabAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(OpenInOtherPanelAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(OpenInBothPanelsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(RevealInDesktopAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); fileMenu.add(new JSeparator()); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(RunCommandAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(PackAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(UnpackAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(EmailAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(BatchRenameAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(SplitFileAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(CombineFilesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); fileMenu.add(new JSeparator()); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(ShowFilePropertiesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(CalculateChecksumAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(ChangePermissionsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(ChangeDateAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // Under Mac OS X, 'Preferences' already appears in the application (muCommander) menu, do not display it again if(!OsFamily.MAC_OS_X.isCurrent()) { fileMenu.add(new JSeparator()); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(ShowPreferencesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); } fileMenu.add(new JSeparator()); MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(CloseWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // Under Mac OS X, 'Quit' already appears in the application (muCommander) menu, do not display it again if(!OsFamily.MAC_OS_X.isCurrent()) MenuToolkit.addMenuItem(fileMenu, ActionManager.getActionInstance(QuitAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); add(fileMenu); // Mark menu menuItemMnemonicHelper.clear(); JMenu markMenu = MenuToolkit.addMenu(Translator.get("mark_menu"), menuMnemonicHelper, this); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(MarkSelectedFileAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(MarkGroupAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(UnmarkGroupAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(MarkAllAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(UnmarkAllAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(MarkExtensionAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(InvertSelectionAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); markMenu.add(new JSeparator()); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(CopyFilesToClipboardAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(CopyFileNamesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(CopyFileBaseNamesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(CopyFilePathsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(PasteClipboardFilesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); markMenu.add(new JSeparator()); MenuToolkit.addMenuItem(markMenu, ActionManager.getActionInstance(CompareFoldersAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); add(markMenu); // View menu menuItemMnemonicHelper.clear(); viewMenu = MenuToolkit.addMenu(Translator.get("view_menu"), menuMnemonicHelper, this); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(SwapFoldersAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(SetSameFolderAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); viewMenu.add(new JSeparator()); toggleShowFoldersFirstItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleShowFoldersFirstAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); toggleShowHiddenFilesItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleHiddenFilesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); toggleTreeItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleTreeAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); toggleSinglePanel = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleSinglePanelAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); /* TODO branch toggleBranchView = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleBranchViewAction.class, mainFrame), menuItemMnemonicHelper); */ viewMenu.add(new JSeparator()); ButtonGroup buttonGroup = new ButtonGroup(); for(Column c : Column.values()) buttonGroup.add(sortByItems[c.ordinal()] = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(c.getSortByColumnActionId(), mainFrame), menuItemMnemonicHelper)); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(ReverseSortOrderAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); viewMenu.add(new JSeparator()); // Toggle columns submenu columnsMenu = MenuToolkit.addMenu(Translator.get("view_menu.show_hide_columns"), null, this); menuItemMnemonicHelper2.clear(); for(Column c : Column.values()) { if(c==Column.NAME) continue; toggleColumnItems[c.ordinal()] = MenuToolkit.addCheckBoxMenuItem(columnsMenu, ActionManager.getActionInstance(c.getToggleColumnActionId(), mainFrame), menuItemMnemonicHelper2); } viewMenu.add(columnsMenu); toggleToggleAutoSizeItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, ActionManager.getActionInstance(ToggleAutoSizeAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); viewMenu.add(new JSeparator()); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(ToggleToolBarAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(ToggleStatusBarAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(ToggleCommandBarAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(viewMenu, ActionManager.getActionInstance(CustomizeCommandBarAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); add(viewMenu); // Go menu menuItemMnemonicHelper.clear(); goMenu = MenuToolkit.addMenu(Translator.get("go_menu"), menuMnemonicHelper, this); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoBackAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoForwardAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); goMenu.add(new JSeparator()); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoToParentAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoToParentInOtherPanelAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoToParentInBothPanelsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(GoToRootAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); goMenu.add(new JSeparator()); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(ChangeLocationAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(ConnectToServerAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(goMenu, ActionManager.getActionInstance(ShowServerConnectionsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // Quick lists goMenu.add(new JSeparator()); JMenu quickListMenu = MenuToolkit.addMenu(Translator.get("quick_lists_menu"), menuMnemonicHelper, this); menuItemMnemonicHelper2.clear(); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowParentFoldersQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowRecentLocationsQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowRecentExecutedFilesQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowBookmarksQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowRootFoldersQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); MenuToolkit.addMenuItem(quickListMenu, ActionManager.getActionInstance(ShowTabsQLAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper2); goMenu.add(quickListMenu); // Add Bonjour services menu goMenu.add(new JSeparator()); BonjourMenu bonjourMenu = new BonjourMenu() { @Override public MuAction getMenuItemAction(BonjourService bs) { return new OpenLocationAction(MainMenuBar.this.mainFrame, new Hashtable<String, Object>(), bs); } }; char mnemonic = menuItemMnemonicHelper.getMnemonic(bonjourMenu.getName()); if(mnemonic!=0) bonjourMenu.setMnemonic(mnemonic); bonjourMenu.setIcon(null); goMenu.add(bonjourMenu); // Volumes will be added when the menu is selected goMenu.add(new JSeparator()); volumeOffset = goMenu.getItemCount(); add(goMenu); // Bookmark menu, menu items will be added when the menu gets selected menuItemMnemonicHelper.clear(); bookmarksMenu = MenuToolkit.addMenu(Translator.get("bookmarks_menu"), menuMnemonicHelper, this); MenuToolkit.addMenuItem(bookmarksMenu, ActionManager.getActionInstance(AddBookmarkAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(bookmarksMenu, ActionManager.getActionInstance(EditBookmarksAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(bookmarksMenu, ActionManager.getActionInstance(ExploreBookmarksAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); bookmarksMenu.add(new JSeparator()); MenuToolkit.addMenuItem(bookmarksMenu, ActionManager.getActionInstance(EditCredentialsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); bookmarksMenu.add(new JSeparator()); // Save the first bookmark menu item's offset for later (bookmarks will be added when menu becomes visible) this.bookmarksOffset = bookmarksMenu.getItemCount(); add(bookmarksMenu); // Window menu menuItemMnemonicHelper.clear(); windowMenu = MenuToolkit.addMenu(Translator.get("window_menu"), menuMnemonicHelper, this); // If running Mac OS X, add 'Minimize' and 'Zoom' items if(OsFamily.MAC_OS_X.isCurrent()) { MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(MinimizeWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(MaximizeWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); windowMenu.add(new JSeparator()); } MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(SplitEquallyAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); buttonGroup = new ButtonGroup(); buttonGroup.add(splitVerticallyItem = MenuToolkit.addCheckBoxMenuItem(windowMenu, ActionManager.getActionInstance(SplitVerticallyAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper)); buttonGroup.add(splitHorizontallyItem = MenuToolkit.addCheckBoxMenuItem(windowMenu, ActionManager.getActionInstance(SplitHorizontallyAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper)); windowMenu.add(new JSeparator()); themesMenu = MenuToolkit.addMenu(Translator.get("prefs_dialog.themes"), null, this); // Theme menu items will be added when the themes menu is selected windowMenu.add(themesMenu); windowMenu.add(new JSeparator()); MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(RecallPreviousWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(RecallNextWindowAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(windowMenu, ActionManager.getActionInstance(BringAllToFrontAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // All other window menu items will be added when the menu gets selected windowMenu.add(new JSeparator()); // Save the first window menu item's offset for later this.windowOffset = windowMenu.getItemCount(); add(windowMenu); // Help menu menuItemMnemonicHelper.clear(); JMenu helpMenu = MenuToolkit.addMenu(Translator.get("help_menu"), menuMnemonicHelper, null); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(GoToDocumentationAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(ShowKeyboardShortcutsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(ShowDebugConsoleAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // Links to website, only shows for OS/Window manager that can launch the default browser to open URLs if(DesktopManager.canBrowse()) { helpMenu.add(new JSeparator()); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(GoToWebsiteAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); // MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(GoToForumsAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(ReportBugAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(DonateAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); helpMenu.add(new JSeparator()); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(CheckForUpdatesAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); } // Under Mac OS X, 'About' already appears in the application (muCommander) menu, do not display it again if(!OsFamily.MAC_OS_X.isCurrent()) { helpMenu.add(new JSeparator()); MenuToolkit.addMenuItem(helpMenu, ActionManager.getActionInstance(ShowAboutAction.Descriptor.ACTION_ID, mainFrame), menuItemMnemonicHelper); } add(helpMenu); } /////////////////////////// // ActionListener method // /////////////////////////// public void actionPerformed(ActionEvent e) { // Discard action events while in 'no events mode' if(mainFrame.getNoEventsMode()) return; // Bring the frame corresponding to the clicked menu item to the front windowMenuFrames.get(e.getSource()).toFront(); } ////////////////////////// // MenuListener methods // ////////////////////////// public void menuSelected(MenuEvent e) { Object source = e.getSource(); if(source==viewMenu) { FileTable activeTable = mainFrame.getActiveTable(); // Select the 'sort by' criterion currently in use in the active table sortByItems[activeTable.getSortInfo().getCriterion().ordinal()].setSelected(true); toggleShowFoldersFirstItem.setSelected(activeTable.getSortInfo().getFoldersFirst()); toggleShowHiddenFilesItem.setSelected(MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_HIDDEN_FILES, MuPreferences.DEFAULT_SHOW_HIDDEN_FILES)); toggleTreeItem.setSelected(activeTable.getFolderPanel().isTreeVisible()); toggleToggleAutoSizeItem.setSelected(mainFrame.isAutoSizeColumnsEnabled()); toggleSinglePanel.setSelected(mainFrame.isSinglePanel()); /* TODO branch toggleBranchView.setSelected(activeTable.getFolderPanel().isBranchView()); */ } else if(source==columnsMenu) { // Update the selected and enabled state of each column menu item. FileTable activeTable = mainFrame.getActiveTable(); for(Column c : Column.values()) { if(c==Column.NAME) // Name column doesn't have a menu item as it cannot be disabled continue; JCheckBoxMenuItem item = toggleColumnItems[c.ordinal()]; item.setSelected(activeTable.isColumnEnabled(c)); item.setEnabled(activeTable.isColumnDisplayable(c)); // Override the action's label to a shorter one item.setText(c.getLabel()); } } else if(source==goMenu) { // Remove any previous volumes from the Go menu // as they might have changed since menu was last selected for(int i=goMenu.getItemCount(); i> volumeOffset; i--) goMenu.remove(volumeOffset); AbstractFile volumes[] = LocalFile.getVolumes(); int nbFolders = volumes.length; for(int i=0; i<nbFolders; i++) goMenu.add(new OpenLocationAction(mainFrame, new Hashtable<String, Object>(), volumes[i])); } else if(source==bookmarksMenu) { // Remove any previous bookmarks menu items from menu // as bookmarks might have changed since menu was last selected for(int i=bookmarksMenu.getItemCount(); i>bookmarksOffset; i--) bookmarksMenu.remove(bookmarksOffset); // Add bookmarks menu items java.util.List<Bookmark> bookmarks = BookmarkManager.getBookmarks(); int nbBookmarks = bookmarks.size(); if(nbBookmarks>0) { for(int i=0; i<nbBookmarks; i++) MenuToolkit.addMenuItem(bookmarksMenu, new OpenLocationAction(mainFrame, new Hashtable<String, Object>(), bookmarks.get(i)), null); } else { // Show 'No bookmark' as a disabled menu item instead showing nothing JMenuItem noBookmarkItem = MenuToolkit.addMenuItem(bookmarksMenu, Translator.get("bookmarks_menu.no_bookmark"), null, null, null); noBookmarkItem.setEnabled(false); } } else if(source==windowMenu) { // Select the split orientation currently in use if(mainFrame.getSplitPaneOrientation()) splitVerticallyItem.setSelected(true); else splitHorizontallyItem.setSelected(true); // Removing any window menu item previously added // Note: menu item cannot be removed by menuDeselected() as actionPerformed() will be called after // menu has been deselected. for(int i=windowMenu.getItemCount(); i>windowOffset; i--) windowMenu.remove(windowOffset); // This WeakHashMap maps menu items to frame instances. It has to be a weakly referenced hash map // and not a regular hash map, since it will not (and cannot) be emptied when the menu has been deselected // and we really do not want this hash map to prevent the frames to be GCed windowMenuFrames = new WeakHashMap<JMenuItem, Frame>(); // Create a menu item for each of the MainFrame instances, that displays the MainFrame's path // and a keyboard accelerator to recall the frame (for the first 10 frames only). java.util.List<MainFrame> mainFrames = WindowManager.getMainFrames(); MainFrame mainFrame; JCheckBoxMenuItem checkBoxMenuItem; int nbFrames = mainFrames.size(); for(int i=0; i<nbFrames; i++) { mainFrame = mainFrames.get(i); checkBoxMenuItem = new JCheckBoxMenuItem(); // If frame number is less than 10, use the corresponding action class (accelerator will be displayed in the menu item) MuAction recallWindowAction; if(i<10) { recallWindowAction = ActionManager.getActionInstance(RECALL_WINDOW_ACTION_IDS[i], this.mainFrame); } // Else use the generic RecallWindowAction else { Hashtable<String, Object> actionProps = new Hashtable<String, Object>(); // Specify the window number using the dedicated property actionProps.put(RecallWindowAction.WINDOW_NUMBER_PROPERTY_KEY, ""+(i+1)); recallWindowAction = ActionManager.getActionInstance(new ActionParameters(RecallWindowAction.Descriptor.ACTION_ID, actionProps), this.mainFrame); } checkBoxMenuItem.setAction(recallWindowAction); // Replace the action's label and use the MainFrame's current folder path instead checkBoxMenuItem.setText((i+1)+" "+mainFrame.getActiveTable().getFolderPanel().getCurrentFolder().getAbsolutePath()); // Use the action's label as a tooltip checkBoxMenuItem.setToolTipText(recallWindowAction.getLabel()); // Check current MainFrame (the one this menu bar belongs to) checkBoxMenuItem.setSelected(mainFrame==this.mainFrame); windowMenu.add(checkBoxMenuItem); } // Add 'other' (non-MainFrame) windows : viewer and editor frames, no associated accelerator Frame frames[] = Frame.getFrames(); nbFrames = frames.length; Frame frame; JMenuItem menuItem; boolean firstFrame = true; for(int i=0; i<nbFrames; i++) { frame = frames[i]; // Test if Frame is not hidden (disposed), Frame.getFrames() returns both active and disposed frames if(frame.isShowing() && (frame instanceof FileFrame)) { // Add a separator before the first non-MainFrame frame to mark a separation between MainFrames // and other frames if(firstFrame) { windowMenu.add(new JSeparator()); firstFrame = false; } // Use frame's window title menuItem = new JMenuItem(frame.getTitle()); menuItem.addActionListener(this); windowMenu.add(menuItem); windowMenuFrames.put(menuItem, frame); } } } else if(source==themesMenu) { // Remove all previous theme items, create new ones for each available theme and select the current theme themesMenu.removeAll(); ButtonGroup buttonGroup = new ButtonGroup(); Iterator<Theme> themes = ThemeManager.availableThemes(); Theme theme; JCheckBoxMenuItem item; themesMenu.add(new JMenuItem(new EditCurrentThemeAction())); themesMenu.add(new JSeparator()); while(themes.hasNext()) { theme = themes.next(); item = new JCheckBoxMenuItem(new ChangeCurrentThemeAction(theme)); buttonGroup.add(item); if(ThemeManager.isCurrentTheme(theme)) item.setSelected(true); themesMenu.add(item); } } } public void menuDeselected(MenuEvent e) { } public void menuCanceled(MenuEvent e) { } /** * Action that changes the current theme to the specified in the constructor. */ private class ChangeCurrentThemeAction extends AbstractAction { private Theme theme; public ChangeCurrentThemeAction(Theme theme) { super(theme.getName()); this.theme = theme; } public void actionPerformed(ActionEvent actionEvent) { try { ThemeManager.setCurrentTheme(theme); } catch(IllegalArgumentException e) { InformationDialog.showErrorDialog(mainFrame, Translator.get("theme_could_not_be_loaded")); } } } /** * Actions that edits the current theme. */ private class EditCurrentThemeAction extends AbstractAction { public EditCurrentThemeAction() { super(Translator.get("prefs_dialog.edit_current_theme")); } public void actionPerformed(ActionEvent actionEvent) { new ThemeEditorDialog(mainFrame, ThemeManager.getCurrentTheme()).editTheme(); } } }