from __future__ import annotations
from typing import cast, Any, List, 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.shortcuts import Shortcuts
from ooodev.utils.helper.dot_dict import DotDict
from ooodev.utils.kind.module_names_kind import ModuleNamesKind
from ooodev.gui.menu.ma.ma_item import MAItem
if TYPE_CHECKING:
from ooodev.gui.menu.common.command_dict import CommandDict
[docs]class MAProcessor(EventsPartial):
"""Class for processing App menus. Does not process submenus"""
[docs] def __init__(self, container: List[MAItem]) -> None:
"""
Constructor
Args:
container (List[MAItem]): Menu item data.
"""
EventsPartial.__init__(self)
self._init_events()
self._container = container
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_command(self, pop: MAItem) -> None:
"""Process command"""
if not pop.command:
return
if pop.is_separator():
return
if isinstance(pop.command, str):
cmd = pop.command
else:
cmd = pop.command.to_dict()
pop.command = Shortcuts.get_url_script(cmd)
def _get_action_from_module(self, menu: dict, index: int) -> MAItem | None:
"""
Gets the Action Trigger 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:
MAItem | None: Action Item if found, otherwise None
Note:
If the menu text is not found then the event ``ma_item_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
module_kind = ModuleNamesKind(menu["module"])
cmd = cast(str, menu["CommandURL"])
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 "Label" in menu:
cmd_text = menu["Label"]
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("ma_item_module_no_text_found", cargs)
if cargs.cancel:
return None
if "Label" in cargs.event_data.menu:
cmd_text = cargs.event_data.menu["Label"]
if not cmd_text:
raise ValueError(f"No text for command: {module_kind} {cmd}")
menu_data = {
"CommandURL": cmd,
}
menu_data.update(menu)
# set the text back to the found command text
menu_data["Label"] = cmd_text
return self._get_action_item(menu_data, index)
def _get_action_item(self, menu: dict, index: int) -> MAItem:
"""Get popup item data"""
eargs = EventArgs(self)
eargs.event_data = DotDict(**menu)
eargs.event_data.index = index
self.trigger_event("before_get_action_item", eargs)
menu_data = cast(DotDict, eargs.event_data)
text = menu_data.Label
command = cast(Union[str, "CommandDict"], menu_data.get("CommandURL", ""))
return MAItem(
label=text,
command=Shortcuts.get_url_script(command),
style=menu_data.get("Style", 0),
shortcut=menu_data.get("ShortCut", ""),
submenu=menu_data.get("Submenu"),
)
[docs] def get_action_item(self, menu: dict, index: int) -> MAItem | None:
"""Get Action item"""
if "module" in menu:
item = self._get_action_from_module(menu, index)
elif "Label" in menu:
text = menu["Label"]
if text == "-":
item = MAItem(label="-")
else:
item = self._get_action_item(menu, index)
else:
item = self._get_action_item(menu, index)
return item
[docs] def process(self, menu: dict, index: int) -> MAItem | None:
"""Process menu item"""
item = self.get_action_item(menu, index)
if item is None:
return None
cargs = CancelEventArgs(source=self)
cargs.event_data = DotDict(container=self._container, action_item=item)
self.trigger_event("before_process", cargs)
if cargs.cancel:
return item
self._container.insert(index, item)
if item.is_separator():
return item
self._process_command(item)
eargs = EventArgs.from_args(cargs)
self.trigger_event("after_process", eargs)
return item