Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Use menu and item identifiers to add items to the main menu plugin #16205

Merged
merged 6 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions spyder/api/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,10 @@ def create_menu(self, menu_id, title='', icon=None):
'Menu name "{}" already in use!'.format(menu_id)
)

menu = MainWidgetMenu(parent=self, title=title)
menu.ID = menu_id
menu = MainWidgetMenu(parent=self, title=title, menu_id=menu_id)

MENU_REGISTRY.register_reference(
menu, menu.ID, self.PLUGIN_NAME, self.CONTEXT_NAME)
menu, menu_id, self.PLUGIN_NAME, self.CONTEXT_NAME)

if icon is not None:
menu.menuAction().setIconVisibleInMenu(True)
Expand Down
49 changes: 39 additions & 10 deletions spyder/api/widgets/menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@

# Standard library imports
import sys
from typing import Optional, Union, TypeVar

# Third party imports
from qtpy.QtWidgets import QAction, QMenu

# Local imports
from spyder.utils.qthelpers import add_actions
from spyder.utils.qthelpers import add_actions, SpyderAction


# --- Constants
# ----------------------------------------------------------------------------
MENU_SEPARATOR = None


# Generic type annotations
T = TypeVar('T', bound='SpyderMenu')


class OptionsMenuSections:
Top = 'top_section'
Bottom = 'bottom_section'
Expand All @@ -41,14 +46,17 @@ class SpyderMenu(QMenu):
"""
MENUS = []

def __init__(self, parent=None, title=None, dynamic=True):
def __init__(self, parent=None, title=None, dynamic=True,
menu_id=None):
self._parent = parent
self._title = title
self._sections = []
self._actions = []
self._actions_map = {}
self.unintroduced_actions = {}
self.unintroduced_sections = []
self._dirty = False
self.menu_id = menu_id

if title is None:
super().__init__(parent)
Expand All @@ -74,11 +82,16 @@ def clear_actions(self):
self.clear()
self._sections = []
self._actions = []
self._actions_map = {}
self.unintroduced_actions = {}
self.unintroduced_sections = []

def add_action(self, action, section=None, before=None,
before_section=None, check_before=True):
def add_action(self: T, action: Union[SpyderAction, T],
section: Optional[str] = None,
before: Optional[str] = None,
before_section: Optional[str] = None,
check_before: bool = True,
omit_id: bool = False):
"""
Add action to a given menu section.

Expand All @@ -88,23 +101,38 @@ def add_action(self, action, section=None, before=None,
The action to add.
section: str or None
The section id in which to insert the `action`.
before: SpyderAction or None
Make the action appear before another given action.
before_section: Section or None
before: str
Make the action appear before the given action identifier.
before_section: str or None
Make the item section (if provided) appear before another
given section.
check_before: bool
Check if the `before` action is part of the menu. This is
necessary to avoid an infinite recursion when adding
unintroduced actions with this method again.
omit_id: bool
If True, then the menu will check if the item to add declares an
id, False otherwise. This flag exists only for items added on
Spyder 4 plugins. Default: False
"""
item_id = None
if isinstance(action, SpyderAction) or hasattr(action, 'action_id'):
item_id = action.action_id
elif isinstance(action, SpyderMenu) or hasattr(action, 'menu_id'):
item_id = action.menu_id

if not omit_id and item_id is None and action is not None:
raise AttributeError(f'Item {action} must declare an id.')

if before is None:
self._actions.append((section, action))
else:
new_actions = []
added = False
before_item = self._actions_map.get(before, None)

for sec, act in self._actions:
if act == before:
if before_item is not None and act == before_item:
added = True
new_actions.append((section, action))

Expand Down Expand Up @@ -136,6 +164,7 @@ def add_action(self, action, section=None, before=None,

# Track state of menu to avoid re-rendering if menu has not changed
self._dirty = True
self._actions_map[item_id] = action

def get_title(self):
"""
Expand Down Expand Up @@ -191,8 +220,8 @@ def _render(self):
# a `before` action they required was not part of the menu yet.
for before, actions in self.unintroduced_actions.items():
for section, action in actions:
self.add_action(action, section=section, before=before,
check_before=False)
self.add_action(action, section=section,
before=before, check_before=False)

actions = self.get_actions()
add_actions(self, actions)
Expand Down
2 changes: 1 addition & 1 deletion spyder/api/widgets/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def create_menu(self, name, text=None, icon=None):
"""
from spyder.api.widgets.menus import SpyderMenu

menu = SpyderMenu(parent=self, title=text)
menu = SpyderMenu(parent=self, title=text, menu_id=name)
if icon is not None:
menu.menuAction().setIconVisibleInMenu(True)
menu.setIcon(icon)
Expand Down
16 changes: 10 additions & 6 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#==============================================================================
from spyder import __version__
from spyder import dependencies
from spyder.api.widgets.menus import SpyderMenu
from spyder.app.utils import (
create_application, create_splash_screen, create_window,
delete_lsp_log_files, qt_message_handler, set_links_color, setup_logging,
Expand Down Expand Up @@ -975,15 +976,17 @@ def setup(self):
icon=ima.icon('filelist'),
tip=_('Fast switch between files'),
triggered=self.open_switcher,
context=Qt.ApplicationShortcut)
context=Qt.ApplicationShortcut,
id_='file_switcher')
self.register_shortcut(self.file_switcher_action, context="_",
name="File switcher")
self.symbol_finder_action = create_action(
self, _('Symbol finder...'),
icon=ima.icon('symbol_find'),
tip=_('Fast symbol search in file'),
triggered=self.open_symbolfinder,
context=Qt.ApplicationShortcut)
context=Qt.ApplicationShortcut,
id_='symbol_finder')
self.register_shortcut(self.symbol_finder_action, context="_",
name="symbol finder", add_shortcut_to_tip=True)

Expand Down Expand Up @@ -1046,21 +1049,22 @@ def create_edit_action(text, tr_text, icon):
_("PYTHONPATH manager"),
None, icon=ima.icon('pythonpath'),
triggered=self.show_path_manager,
tip=_("PYTHONPATH manager"))
tip=_("PYTHONPATH manager"),
id_='spyder_path_action')
from spyder.plugins.application.plugin import (
ApplicationActions, WinUserEnvDialog)
winenv_action = None
if WinUserEnvDialog:
winenv_action = self.application.get_action(
ApplicationActions.SpyderWindowsEnvVariables)
winenv_action = ApplicationActions.SpyderWindowsEnvVariables
mainmenu.add_item_to_application_menu(
spyder_path_action,
menu_id=ApplicationMenus.Tools,
section=ToolsMenuSections.Tools,
before=winenv_action
)
if get_debug_level() >= 3:
self.menu_lsp_logs = QMenu(_("LSP logs"))
self.menu_lsp_logs = SpyderMenu(
title=_("LSP logs"), menu_id='lsp_logs_menu')
self.menu_lsp_logs.aboutToShow.connect(self.update_lsp_logs)
mainmenu.add_item_to_application_menu(
self.menu_lsp_logs,
Expand Down
3 changes: 1 addition & 2 deletions spyder/plugins/application/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ def _populate_help_menu_documentation_section(self):

if shortcuts:
from spyder.plugins.shortcuts.plugin import ShortcutActions
shortcuts_summary_action = shortcuts.get_action(
ShortcutActions.ShortcutSummaryAction)
shortcuts_summary_action = ShortcutActions.ShortcutSummaryAction
for documentation_action in [
self.documentation_action, self.video_action]:
mainmenu.add_item_to_application_menu(
Expand Down
4 changes: 2 additions & 2 deletions spyder/plugins/breakpoints/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ def on_editor_available(self):
def on_main_menu_available(self):
mainmenu = self.get_plugin(Plugins.MainMenu)
list_action = self.get_action(BreakpointsActions.ListBreakpoints)
debug_menu = mainmenu.get_application_menu(ApplicationMenus.Debug)
mainmenu.add_item_to_application_menu(list_action, debug_menu)
mainmenu.add_item_to_application_menu(
list_action, menu_id=ApplicationMenus.Debug)

# --- Private API
# ------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions spyder/plugins/completion/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ def add_item_to_menu(self, action_or_menu, menu, section=None,
self.main.add_item_to_menu(
action_or_menu, menu, section=section, before=before)

def add_item_to_application_menu(self, item, menu=None, menu_id=None,
def add_item_to_application_menu(self, item, menu_id=None,
section=None, before=None,
before_section=None):
"""
Expand All @@ -1348,7 +1348,7 @@ def add_item_to_application_menu(self, item, menu=None, menu_id=None,
The application menu unique string identifier.
section: str or None
The section id in which to insert the `item` on the `menu`.
before: SpyderAction/SpyderMenu or None
before: str or None
Make the item appear before another given item.
before_section: Section or None
Make the item section (if provided) appear before another
Expand All @@ -1359,5 +1359,5 @@ def add_item_to_application_menu(self, item, menu=None, menu_id=None,
Must provide a `menu` or a `menu_id`.
"""
self.main.add_item_to_application_menu(
item, menu=menu, menu_id=menu_id, section=section,
item, menu_id=menu_id, section=section,
before=before, before_section=before_section)
18 changes: 12 additions & 6 deletions spyder/plugins/editor/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,8 @@ def get_plugin_actions(self):
self.new_action,
menu_id=ApplicationMenus.File,
section=FileMenuSections.New,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)
# Open section
open_actions = [
self.open_action,
Expand All @@ -997,7 +998,8 @@ def get_plugin_actions(self):
open_action,
menu_id=ApplicationMenus.File,
section=FileMenuSections.Open,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)
# Save section
save_actions = [
self.save_action,
Expand All @@ -1011,7 +1013,8 @@ def get_plugin_actions(self):
save_action,
menu_id=ApplicationMenus.File,
section=FileMenuSections.Save,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)
# Print
print_actions = [
print_preview_action,
Expand All @@ -1022,7 +1025,8 @@ def get_plugin_actions(self):
print_action,
menu_id=ApplicationMenus.File,
section=FileMenuSections.Print,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)
# Close
close_actions = [
self.close_action,
Expand All @@ -1033,14 +1037,16 @@ def get_plugin_actions(self):
close_action,
menu_id=ApplicationMenus.File,
section=FileMenuSections.Close,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)
# Navigation
if sys.platform == 'darwin':
self.main.mainmenu.add_item_to_application_menu(
self.tab_navigation_actions,
menu_id=ApplicationMenus.File,
section=FileMenuSections.Navigation,
before_section=FileMenuSections.Restart)
before_section=FileMenuSections.Restart,
omit_id=True)

file_toolbar_actions = ([self.new_action, self.open_action,
self.save_action, self.save_all_action] +
Expand Down
3 changes: 1 addition & 2 deletions spyder/plugins/findinfiles/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,9 @@ def on_main_menu_available(self):
mainmenu = self.get_plugin(Plugins.MainMenu)
findinfiles_action = self.get_action(FindInFilesActions.FindInFiles)

menu = mainmenu.get_application_menu(ApplicationMenus.Search)
mainmenu.add_item_to_application_menu(
findinfiles_action,
menu=menu,
menu_id=ApplicationMenus.Search,
)

def on_close(self, cancelable=False):
Expand Down
3 changes: 1 addition & 2 deletions spyder/plugins/help/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ def _setup_menus(self):
shortcuts_summary_action = None
if shortcuts:
from spyder.plugins.shortcuts.plugin import ShortcutActions
shortcuts_summary_action = shortcuts.get_action(
ShortcutActions.ShortcutSummaryAction)
shortcuts_summary_action = ShortcutActions.ShortcutSummaryAction
if mainmenu:
from spyder.plugins.mainmenu.api import (
ApplicationMenus, HelpMenuSections)
Expand Down
9 changes: 6 additions & 3 deletions spyder/plugins/ipythonconsole/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,14 @@ def get_plugin_actions(self):
self.main.mainmenu.add_item_to_application_menu(
console_new_action,
menu_id=ApplicationMenus.Consoles,
section=ConsolesMenuSections.New)
section=ConsolesMenuSections.New,
omit_id=True)
for console_restart_connect_action in restart_connect_consoles_actions:
self.main.mainmenu.add_item_to_application_menu(
console_restart_connect_action,
menu_id=ApplicationMenus.Consoles,
section=ConsolesMenuSections.Restart)
section=ConsolesMenuSections.Restart,
omit_id=True)

# IPython documentation
self.ipython_menu = SpyderMenu(
Expand All @@ -703,7 +705,8 @@ def get_plugin_actions(self):
self.ipython_menu,
menu_id=ApplicationMenus.Help,
section=HelpMenuSections.ExternalDocumentation,
before_section=HelpMenuSections.About)
before_section=HelpMenuSections.About,
omit_id=True)

# Plugin actions
self.menu_actions = [create_client_action, special_console_menu,
Expand Down
1 change: 1 addition & 0 deletions spyder/plugins/layout/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ def create_plugins_menu(self):
except AttributeError:
# Old API
action = plugin._toggle_view_action
action.action_id = f'switch to {plugin.CONF_SECTION}'

if action:
action.setChecked(plugin.dockwidget.isVisible())
Expand Down
Loading