cmd_actions.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from PySide6.QtGui import QAction
  2. from PySide6.QtWidgets import QMenu
  3. from .active_api import (
  4. api_group_order,
  5. )
  6. def add_cmd_actions_to_menu(parent, receiver, api, menu=None, cmdkwargs=None):
  7. """Slot to populate (connected) QMenu with dataset actions
  8. Actions' `triggered` signal will be connected to a `receiver` slot.
  9. Typical usage is to connect a QMenu's aboutToShow signal to this
  10. slot, in order to lazily populate the menu with items, before they
  11. are needed.
  12. If `menu` is `None`, the sender is expected to be a QMenu.
  13. """
  14. if menu is None:
  15. menu = parent.sender()
  16. group_separator = menu.addSeparator()
  17. # generate a submenu for each unique group specification
  18. # across all commands in the dataset API
  19. submenus = {
  20. group: QMenu(group, parent=menu)
  21. for group in set(
  22. cmdspec['group'] for cmdspec in api.values()
  23. if 'group' in cmdspec
  24. )
  25. }
  26. for cmdname, cmdspec in api.items():
  27. # we create a dedicated action for each command
  28. action = QAction(cmdspec.get('name', cmdname), parent=parent)
  29. # the name of the command is injected into the action
  30. # as user data. We wrap it in a dict to enable future
  31. # additional payload
  32. adata = dict(__cmd_name__=cmdname)
  33. # put on record, if we are generating actions for a specific
  34. # dataset
  35. if cmdkwargs is not None:
  36. adata.update(cmdkwargs)
  37. action.setData(adata)
  38. # all actions connect to the command configuration
  39. # UI handler, such that clicking on the menu item
  40. # brings up the config UI
  41. action.triggered.connect(receiver)
  42. # add to menu
  43. # sort and group actions by some semantics
  44. # e.g. all commands from one extension together
  45. # to avoid a monster menu.
  46. # if the menu lookup knows a better place to put a command
  47. # based on the command interface class, it will be used
  48. # instead of the main menu
  49. target_menu = submenus.get(cmdspec.get('group'), menu)
  50. target_menu.addAction(action)
  51. for group, submenu in sorted(
  52. submenus.items(),
  53. # sort items with no sorting indicator last
  54. key=lambda x: api_group_order.get(x[0], ('zzzz'))):
  55. # skip menus without actions
  56. if not submenu.actions():
  57. continue
  58. menu.insertMenu(group_separator, submenu)