Source code for ooodev.gui.menu.popup.popup_processor
from __future__ import annotations
from typing import cast, Any, Union, TYPE_CHECKING
from ooodev.events.args.cancel_event_args import CancelEventArgs
from ooodev.events.args.event_args import EventArgs
from ooodev.events.partial.events_partial import EventsPartial
from ooodev.gui.commands.cmd_data import CmdData
from ooodev.gui.commands.cmd_info import CmdInfo
from ooodev.gui.menu.popup_menu import PopupMenu
from ooodev.gui.menu.popup.popup_item import PopupItem
from ooodev.gui.menu.shortcuts import Shortcuts
from ooodev.utils.helper.dot_dict import DotDict
from ooodev.utils.kind.module_names_kind import ModuleNamesKind
from ooodev.utils.string.str_list import StrList
if TYPE_CHECKING:
from ooodev.gui.menu.common.command_dict import CommandDict
[docs]class PopupProcessor(EventsPartial):
"""
Class for processing menus. Does not process submenus.
See Also:
- :ref:`help_popup_from_dict_or_json`
- :ref:`help_popup_via_builder_item`
"""
[docs] def __init__(self, popup: PopupMenu) -> None:
"""
Constructor
Args:
item (PopupItem): Menu item data.
"""
EventsPartial.__init__(self)
self._init_events()
self._popup = popup
self._cmd_info = CmdInfo()
self._cmd_info.subscribe_on_command_found(self._fn_on_command_found)
def _init_events(self) -> None:
self._fn_on_command_found = self._on_command_found
def _on_command_found(self, source: Any, event: CancelEventArgs) -> None:
"""Command found event"""
pass
# cmd_data = cast(CmdData, event.event_data["cmd_data"])
# if not cmd_data.global_hotkey:
# event.cancel = True
def _process_shortcut(self, pop: PopupItem) -> None:
"""Process shortcut"""
keys = pop.shortcut.strip()
if not keys:
return
sl_keys = StrList.from_str(keys)
for key in sl_keys:
if not key:
continue
kv = Shortcuts.to_key_event(key)
if kv is not None:
self._popup.set_accelerator_key_event(pop.menu_id, kv)
def _process_command(self, pop: PopupItem) -> None:
"""Process command"""
if not pop.command:
return
cmd = Shortcuts.get_url_script(pop.command)
self._popup.set_command(pop.menu_id, cmd)
def _get_popup_from_module(self, menu: dict, index: int) -> PopupItem | None:
"""
Gets the popup item and looks up the command data from the command info.
Args:
menu (dict): Menu Data
index (int): Current Index
Raises:
ValueError: If no text is found for the command
Returns:
PopupItem | None: Popup Item if found, otherwise None
Note:
If the menu text is not found then the event ``popup_module_no_text_found`` is raised.
The event data is a dictionary with keys:
- ``module_kind``: ModuleNamesKind
- ``cmd``: Command as a string.
- ``index``: Index as an integer.
- ``menu``: Menu Data as a dictionary.
The caller can set ``menu["text"]`` to provide a valid menu text.
If the caller cancels the event then the menu item is not created and None is returned.
"""
def _get_command_data(kind: ModuleNamesKind, cmd: str) -> CmdData | None:
if kind == ModuleNamesKind.NONE:
# get from global
data = self._cmd_info.find_command(cmd)
if cmd not in data:
return None
c_infos = data[cmd]
if not c_infos:
return None
return c_infos[0]
return self._cmd_info.get_cmd_data(kind, cmd)
def get_cmd_text(data: CmdData) -> str:
return data.label or data.name
def get_shortcut(data: CmdData) -> str:
if data.module_hotkey:
return data.module_hotkey
if data.global_hotkey:
# str_keys = StrList.from_str(data.global_hotkey)
return data.global_hotkey
return ""
module_kind = ModuleNamesKind(menu["module"])
cmd = cast(str, menu["command"])
command_data = _get_command_data(module_kind, cmd)
if command_data is None:
cmd_text = ""
else:
cmd_text = get_cmd_text(command_data)
if not cmd_text:
# check if a label has bee provided:
if "text" in menu:
cmd_text = menu["text"]
else:
# no valid menu text found
# raise an event to allow the caller to provide a valid menu text
cargs = CancelEventArgs(self)
event_data = DotDict(module_kind=module_kind, cmd=cmd, index=index, menu=menu)
cargs.event_data = event_data
self.trigger_event("popup_module_no_text_found", cargs)
if cargs.cancel:
return None
if "text" in cargs.event_data.menu:
cmd_text = cargs.event_data.menu["text"]
if not cmd_text:
raise ValueError(f"No text for command: {module_kind} {cmd}")
menu_data = {
"command": cmd,
}
if command_data is not None and command_data.tooltip_label:
menu_data["tip_help_text"] = command_data.tooltip_label
menu_data.update(menu)
# set the text back to the found command text
menu_data["text"] = cmd_text
if command_data is not None:
if "shortcut" not in menu_data:
shortcut = get_shortcut(command_data)
if shortcut:
menu_data["shortcut"] = shortcut
return self._get_popup_item(menu_data, index)
def _get_popup_item(self, menu: dict, index: int) -> PopupItem:
"""Get popup item data"""
eargs = EventArgs(self)
eargs.event_data = DotDict(**menu)
eargs.event_data.index = index
self.trigger_event("before_get_popup_item", eargs)
menu_data = cast(DotDict, eargs.event_data)
text = menu_data.text
command = cast(Union[str, "CommandDict"], menu_data.get("command", ""))
style = int(menu_data.get("style", 0))
checked = bool(menu_data.get("checked", False))
enabled = bool(menu_data.get("enabled", True))
default = bool(menu_data.get("default", False))
help_command = menu_data.get("help_command", "")
help_text = menu_data.get("help_text", "")
tip_help_text = menu_data.get("tip_help_text", "")
shortcut = cast(str, menu_data.get("shortcut", ""))
data = menu_data.get("data")
menu_id = int(menu_data.get("menu_id", index))
return PopupItem(
text=text,
menu_id=menu_id,
command=Shortcuts.get_url_script(command),
style=style,
checked=checked,
enabled=enabled,
default=default,
help_command=help_command,
help_text=help_text,
tip_help_text=tip_help_text,
shortcut=shortcut,
index=index,
data=data,
)
[docs] def get_popup_item(self, menu: dict, index: int) -> PopupItem | None:
"""Get popup item"""
if "module" in menu:
pop = self._get_popup_from_module(menu, index)
else:
pop = self._get_popup_item(menu, index)
return pop
[docs] def process(self, menu: dict, index: int) -> PopupItem | None:
"""Process menu item"""
pop = self.get_popup_item(menu, index)
if pop is None:
return None
cargs = CancelEventArgs(source=self)
cargs.event_data = DotDict(popup_menu=self._popup, popup_item=pop)
self.trigger_event("before_process", cargs)
if cargs.cancel:
return pop
if pop.is_separator():
self._popup.insert_separator(pop.index)
return pop
self._popup.insert_item(pop.menu_id, pop.text, pop.style, pop.index)
self._process_command(pop)
self._popup.enable_item(pop.menu_id, pop.enabled)
if pop.checked:
self._popup.check_item(pop.menu_id)
if pop.default:
self._popup.set_default_item(pop.menu_id)
if pop.help_command:
self._popup.set_help_command(pop.menu_id, pop.help_command)
if pop.help_text:
self._popup.set_help_text(pop.menu_id, pop.help_text)
if pop.tip_help_text:
self._popup.set_tip_help_text(pop.menu_id, pop.tip_help_text)
if pop.shortcut:
self._process_shortcut(pop)
eargs = EventArgs.from_args(cargs)
self.trigger_event("after_process", eargs)
return pop