dataladcmd_ui.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. from types import MappingProxyType
  2. from typing import (
  3. Dict,
  4. )
  5. from PySide6.QtCore import (
  6. QObject,
  7. Signal,
  8. Slot,
  9. )
  10. from PySide6.QtGui import QAction
  11. from PySide6.QtWidgets import (
  12. QDialogButtonBox,
  13. QFormLayout,
  14. QLabel,
  15. QScrollArea,
  16. QWidget,
  17. )
  18. from .param_form_utils import populate_form_w_params
  19. from .api_utils import get_cmd_displayname
  20. from .active_api import api
  21. class GooeyDataladCmdUI(QObject):
  22. configured_dataladcmd = Signal(str, MappingProxyType)
  23. def __init__(self, app, ui_parent: QWidget):
  24. super().__init__()
  25. self._app = app
  26. self._ui_parent = ui_parent
  27. # start out disabled, there will be no populated form
  28. self._ui_parent.setDisabled(True)
  29. self._pform = None
  30. self._cmd_title = None
  31. @property
  32. def pwidget(self):
  33. return self._ui_parent
  34. @property
  35. def pform(self):
  36. if self._pform is None:
  37. pw = self.pwidget
  38. # make sure all expected UI blocks are present
  39. self._cmd_title = pw.findChild(QLabel, 'cmdTabTitle')
  40. scrollarea_content = pw.findChild(QScrollArea).widget()
  41. buttonbox = pw.findChild(QDialogButtonBox, 'cmdTabButtonBox')
  42. for w in (self._cmd_title, scrollarea_content, buttonbox):
  43. assert w
  44. # create main form layout for the parameters to appear in
  45. form_layout = QFormLayout(scrollarea_content)
  46. form_layout.setObjectName('cmdTabFormLayout')
  47. self._pform = form_layout
  48. # connect the dialog interaction with slots in this instance
  49. # we run the retrieval helper on ok/run
  50. buttonbox.accepted.connect(self._retrieve_input)
  51. # we disable the UI (however that might look like) on cancel
  52. buttonbox.rejected.connect(self.disable)
  53. return self._pform
  54. @Slot(str, dict)
  55. def configure(
  56. self,
  57. cmdname: str = None,
  58. cmdkwargs: Dict or None = None):
  59. if cmdkwargs is None:
  60. cmdkwargs = dict()
  61. # figure out the object that emitted the signal triggering
  62. # this slot execution. Will be None for a regular method call.
  63. # we can use this to update the method parameter values
  64. # with information from menu-items, or tree nodes clicked
  65. sender = self.sender()
  66. if sender is not None:
  67. if cmdname is None and isinstance(sender, QAction):
  68. cmdname = sender.data().get('__cmd_name__')
  69. # pull in any signal-provided kwargs for the command
  70. # unless they have been also specified directly to the method
  71. cmdkwargs = {
  72. k: v for k, v in sender.data().items()
  73. if k != '__cmd_name__' and k not in cmdkwargs
  74. }
  75. assert cmdname is not None, \
  76. "GooeyDataladCmdUI.configure() called without command name"
  77. self._app.get_widget('contextTabs').setCurrentWidget(self.pwidget)
  78. self.reset_form()
  79. populate_form_w_params(
  80. self._app.rootpath,
  81. self.pform,
  82. cmdname,
  83. cmdkwargs,
  84. )
  85. # set title afterwards, form might just have been created first, lazily
  86. self._cmd_title.setText(
  87. # remove potential shortcut marker
  88. get_cmd_displayname(api, cmdname).replace('&', '')
  89. )
  90. self._cmd_title.setToolTip(f'API command: `{cmdname}`')
  91. # deposit the command name in the widget, to be retrieved later by
  92. # retrieve_parameters()
  93. self.pform.datalad_cmd_name = cmdname
  94. # make sure the UI is visible
  95. self.pwidget.setEnabled(True)
  96. @Slot()
  97. def _retrieve_input(self):
  98. from .param_widgets import _NoValue
  99. params = dict()
  100. for i in range(self.pform.rowCount()):
  101. # the things is wrapped into a QWidgetItem layout class, hence .wid
  102. field_widget = self.pform.itemAt(i, QFormLayout.FieldRole).wid
  103. # _get_datalad_param_spec() is our custom private adhoc method
  104. # expected to return a dict with a parameter setting, or an
  105. # empty dict, when the default shall be used.
  106. params.update({
  107. k: v for k, v in field_widget.get_gooey_param_spec().items()
  108. if v is not _NoValue
  109. })
  110. # take a peek, TODO remove
  111. from pprint import pprint
  112. pprint(params)
  113. self.disable()
  114. self.configured_dataladcmd.emit(
  115. self.pform.datalad_cmd_name,
  116. MappingProxyType(params),
  117. )
  118. @Slot()
  119. def disable(self):
  120. """Disable UI when no longer needed for configuration"""
  121. # only disaable, not hide, to keep the info what ran (was configured)
  122. # accessible. Widget empties itself on reconfigure
  123. self.pwidget.setDisabled(True)
  124. def reset_form(self):
  125. if self._cmd_title:
  126. self._cmd_title.setText('')
  127. for i in range(self.pform.rowCount() - 1, -1, -1):
  128. # empty the form layout (deletes all widgets)
  129. self.pform.removeRow(i)
  130. self.disable()