diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a8b40a..a051cf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,13 @@ # Version 1.0.0 -- Edits 'contributing.md' and 'README.md (#131, #133). -- Adds unit test for `addWidget` and `addSpanningWidget`; - Adds `getIndexFromVerticalLayout` -to `FormDialog` (#123). -- Initialises `widget_states` in init (#132). -- Adds methods to insert widgets in the forms & tests/example - Removes `_addWidget` - Adds `getWidgetRow`and updates states dictionary and related methods - Adds `getNameAndRole*`. - Changes `num_widgets` to be a property (#109) +- Adds the class `AdvancedDialogForm` & tests/example; +deprecates `getWidgetStates` to be `getSavedWidgetStates` (#124) +- Edits 'contributing.md' and 'README.md (#131, #133) +- Adds unit test for `addWidget` and `addSpanningWidget`; adds `getIndexFromVerticalLayout` +to `FormDialog` (#123) +- Initialises `widget_states` in init (#132) +- Adds methods to insert widgets in the forms & tests/example; removes `_addWidget`; +adds `getWidgetRow`and updates states dictionary and related methods; adds +`getNameAndRole*`; changes `num_widgets` to be a property (#109) - Reinstates changelog (#99) - Adds `title` to `FormDockWidget` & update tests/examples (#102) - Stops `pre-commit` committing corrections to user PRs (#112) diff --git a/eqt/ui/FormDialog.py b/eqt/ui/FormDialog.py index 8ae8627..52b69e9 100644 --- a/eqt/ui/FormDialog.py +++ b/eqt/ui/FormDialog.py @@ -203,7 +203,6 @@ def getNumWidgets(self): def getWidget(self, name, role='field'): ''' Returns the widget by the name with which it has been added. - By default it returns the widget that is the field in the form. The user can get the label by specifying the role to be label. Raises ValueError if the role is not field or label. @@ -242,9 +241,13 @@ def saveAllWidgetStates(self): self.formWidget.saveAllWidgetStates() def getWidgetStates(self): - '''Returns the saved widget states.''' + '''Deprecated. Use `getSavedWidgetStates`.''' return self.formWidget.getWidgetStates() + def getSavedWidgetStates(self): + '''Returns the saved widget states.''' + return self.formWidget.getSavedWidgetStates() + def getDefaultWidgetStates(self): '''Returns the saved default widget states.''' return self.formWidget.getDefaultWidgetStates() @@ -325,3 +328,117 @@ def applyWidgetStates(self, states): 'widget2': {'value': 2, 'enabled': False, 'visible': False, 'widget_row': 1}}. ''' return self.formWidget.applyWidgetStates(states) + + +class AdvancedFormDialog(FormDialog): + def __init__(self, parent=None, title=None, parent_button_name=None): + """ + Constructs an advanced form dialog that adds widgets on its parent. + + To add widgets to the parent, call `displayWidgetValueOnParent` after creating an instance + of the class. The advanced form dialog has a default button in its vertical layout, which + is located between the form layout and the buttons 'ok' and 'cancel'. This button sets the + widgets to their default values. + + Parameters + ---------- + parent : UIFormWidget or None, optional + The parent widget of the advanced form dialog. + If None, the dialog is created without a parent. + title : str or None, optional + The title of the advanced form dialog. + parent_button_name : str or None, optional + The name of the button opening the advanced form dialog in the parent. + If passed, the extra widgets will be added under this button in the parent, + otherwise they are added at the end. + """ + self.dialog_parent = parent + self.display_on_parent = [] + if parent_button_name is None: + self.parent_button_row = -1 + elif parent is None: + raise ValueError( + 'The parent is None. Set the parent if you want to set the parent button name.') + else: + self.parent_button_row = self.dialog_parent.getWidgetRow(parent_button_name) + + FormDialog.__init__(self, parent, title) + + # add default button to vertical layout + self.default_button = QtWidgets.QPushButton("Set default values") + self.insertWidgetToVerticalLayout(1, self.default_button) + self.default_button.clicked.connect(lambda: self._setDefaultValues()) + + def _onOk(self): + """ + Called when the "Ok" button is clicked in the advanced dialog. + + Calls the super-class method `_onOk`, sets the default widgets + to visible, and adds/updates/removes widgets from the + parent depending on the the widgets in the advanced dialog. + """ + super()._onOk() + self.formWidget.setDefaultWidgetStatesVisibleTrue() + if self.display_on_parent: + if self.getSavedWidgetStates() == self.getDefaultWidgetStates(): + self._removeWidgetsFromParent() + else: + self._addOrUpdateWidgetsInParent() + + def _addOrUpdateWidgetsInParent(self): + """ + Adds or updates widgets in the parent form. + + This method iterates over the display_on_parent and adds the widgets to the parent + form. If a widget already exists in the parent form, it is updated with the most current + value set in the advanced dialog. + """ + for index, name in enumerate(self.display_on_parent, start=1): + widget_row = self.parent_button_row + index if self.parent_button_row != -1 else -1 + value = self.getSavedWidgetStates()[f'{name}_field']['value'] + qwidget = self.getWidget(name, 'field') + if isinstance(qwidget, QtWidgets.QComboBox): + value = qwidget.itemText(value) + if f'{name}_field' not in self.dialog_parent.getWidgets(): + label = str(self.getSavedWidgetStates()[f'{name}_label']['value']) + self.dialog_parent.insertWidget(widget_row, name, QtWidgets.QLabel(str(value)), + label) + else: + self.dialog_parent.getWidget(name, 'field').setText(str(value)) + + def _removeWidgetsFromParent(self): + """ + Removes widgets from the parent form. + + This method iterates over the display_on_parent and removes + the widgets from the parent. + """ + for name in self.display_on_parent: + if f'{name}_field' in self.dialog_parent.getWidgets(): + self.dialog_parent.removeWidget(name) + + def _setDefaultValues(self): + """ + Sets the widgets in the advanced dialog to their default states. + + Makes the default widget states visible, as often the default states are saved while the + widgets are not visible. Applies the widget states to the widgets in the form. + """ + self.formWidget.setDefaultWidgetStatesVisibleTrue() + self.applyWidgetStates(self.formWidget.default_widget_states) + + def displayWidgetValueOnParent(self, name): + """ + Adds `name` in a list. The order in which names are added to this + list reflects the order in which the widgets are added to the parent. + Raises an error if the parent of the advanced dialog is `None`. + + Parameters + ---------- + name : str + The name of the widget in the advanced dialog to be displayed in the parent. + """ + if self.dialog_parent is None: + raise KeyError('''The advanced-dialog parent is None. + Set the parent if you want to add widgets to it.''') + self.display_on_parent.append(name) diff --git a/eqt/ui/UIFormWidget.py b/eqt/ui/UIFormWidget.py index cb45953..2f163d5 100644 --- a/eqt/ui/UIFormWidget.py +++ b/eqt/ui/UIFormWidget.py @@ -1,3 +1,5 @@ +from warnings import warn + from PySide2 import QtWidgets from .UISliderWidget import UISliderWidget @@ -465,6 +467,12 @@ def saveAllWidgetStates(self): self.widget_states = self.getAllWidgetStates() def getWidgetStates(self): + '''Deprecated. Use `getSavedWidgetStates`.''' + warn('The method `getWidgetStates` is deprecated, use `getSavedWidgetStates`.', + DeprecationWarning, stacklevel=2) + return self.getSavedWidgetStates() + + def getSavedWidgetStates(self): '''Returns the saved widget states.''' return self.widget_states @@ -623,9 +631,13 @@ def saveAllWidgetStates(self): self.widget().saveAllWidgetStates() def getWidgetStates(self): - '''Returns the saved widget states.''' + '''Deprecated. Use `getSavedWidgetStates`.''' return self.widget().getWidgetStates() + def getSavedWidgetStates(self): + '''Returns the saved widget states.''' + return self.widget().getSavedWidgetStates() + def getDefaultWidgetStates(self): '''Returns the saved default widget states.''' return self.widget().getDefaultWidgetStates() diff --git a/examples/advanced_dialog_example.py b/examples/advanced_dialog_example.py new file mode 100644 index 0000000..ea59e6a --- /dev/null +++ b/examples/advanced_dialog_example.py @@ -0,0 +1,35 @@ +import sys + +import utilitiesForExamples +from PySide2 import QtWidgets + +from eqt.ui.FormDialog import AdvancedFormDialog +from eqt.ui.UIFormWidget import FormWidget + + +def run_example(): + parent = FormWidget(parent=None) + # open advanced dialog button + pb = QtWidgets.QPushButton(parent) + pb.setText("Open Advanced Dialog") + pb.clicked.connect(lambda: advanced_dialog.exec()) + parent.addSpanningWidget(pb, 'button_advanced') + # extra button + extra_button = QtWidgets.QPushButton(parent) + extra_button.setText("Extra button") + parent.addSpanningWidget(extra_button, 'extra_button') + # create dialog + advanced_dialog = AdvancedFormDialog(parent=parent, title='Example', + parent_button_name='button_advanced') + # all widgets + utilitiesForExamples.addWidgetsToExample(advanced_dialog) + for name in utilitiesForExamples.list_all_widgets(): + advanced_dialog.displayWidgetValueOnParent(name) + # show + parent.show() + + +if __name__ == "__main__": + app = QtWidgets.QApplication(sys.argv) + run_example() + sys.exit(app.exec_()) diff --git a/examples/utilitiesForExamples.py b/examples/utilitiesForExamples.py index 19eda57..4f409f5 100644 --- a/examples/utilitiesForExamples.py +++ b/examples/utilitiesForExamples.py @@ -3,6 +3,20 @@ from eqt.ui.UISliderWidget import UISliderWidget +def list_all_widgets(): + list_all_widgets = { + 'label': QtWidgets.QLabel('test label'), 'checkBox': QtWidgets.QCheckBox('test checkbox'), + 'comboBox': QtWidgets.QComboBox(), 'doubleSpinBox': QtWidgets.QDoubleSpinBox(), + 'spinBox': QtWidgets.QSpinBox(), 'slider': QtWidgets.QSlider(), + 'uiSliderWidget': UISliderWidget(QtWidgets.QLabel()), + 'radioButton': QtWidgets.QRadioButton('test radio button'), + 'textEdit': QtWidgets.QTextEdit('test text edit'), + 'plainTextEdit': QtWidgets.QPlainTextEdit('test plain text edit'), + 'lineEdit': QtWidgets.QLineEdit('test line edit'), + 'button': QtWidgets.QPushButton('test push button')} + return list_all_widgets + + def addWidgetsToExample(form): ''' Adds a spanning widget and every type of widget to a form @@ -12,9 +26,10 @@ def addWidgetsToExample(form): # add all widgets form.addWidget(QtWidgets.QLabel('Label'), 'Label: ', 'label') form.addWidget(QtWidgets.QCheckBox('check me'), 'CheckBox: ', 'checkBox') + qwidget = QtWidgets.QComboBox() combobox_list = ['choice 1', 'choice 2'] - form.addWidget(QtWidgets.QComboBox(), 'ComboBox: ', 'comboBox') - form.getWidget('comboBox').addItems(combobox_list) + qwidget.addItems(combobox_list) + form.addWidget(qwidget, 'ComboBox: ', 'comboBox') form.addWidget(QtWidgets.QDoubleSpinBox(), 'DoubleSpinBox: ', 'doubleSpinBox') form.addWidget(QtWidgets.QSpinBox(), 'SpinBox: ', 'spinBox') form.addWidget(QtWidgets.QSlider(), 'Slider: ', 'slider') diff --git a/test/__init__.py b/test/__init__.py index 8cc5203..bb1eb5b 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -5,7 +5,9 @@ from eqt.ui import FormDialog -if any(os.getenv(var, '0').lower() in ('1', 'true') for var in ('CONDA_BUILD', 'CI')): +is_ci = any(os.getenv(var, '0').lower() in ('1', 'true') for var in ('CONDA_BUILD', 'CI')) + +if is_ci: def skip_ci(_): def inner(*_, **__): diff --git a/test/test__formUI_status_test.py b/test/test__formUI_status_test.py index efe15ec..f5600e7 100644 --- a/test/test__formUI_status_test.py +++ b/test/test__formUI_status_test.py @@ -6,40 +6,51 @@ from PySide2.QtCore import Qt from PySide2.QtTest import QTest -from eqt.ui.FormDialog import FormDialog +from eqt.ui.FormDialog import AdvancedFormDialog, FormDialog from eqt.ui.UIFormWidget import FormDockWidget, FormWidget from eqt.ui.UISliderWidget import UISliderWidget -from . import skip_ci +from . import is_ci, skip + +if is_ci: + skip("Running in CI (no GUI)", allow_module_level=True) class FormsCommonTests(metaclass=abc.ABCMeta): """Common tests for all Form types""" @abc.abstractmethod def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + """ + self.form = None # stop mypy [attr-defined] error raise NotImplementedError @property def exampleState(self): # define two states for every widget state = [{ - 'label_value': 'Test label state 0', 'checkbox_value': False, 'combobox_value': 0, + 'label_value': 'Test label state 0', 'checkBox_value': False, 'comboBox_value': 0, 'doubleSpinBox_value': 10.0, 'spinBox_value': 10, 'slider_value': 10, - 'uislider_value': 10, 'radio_value': False, 'textEdit_value': 'test edit 0', - 'plainTextEdit_value': 'test plain 0', 'lineEdit_value': 'test line 0', - 'pushButton_value': False}, { - 'label_value': 'Test label state 1', 'checkbox_value': True, 'combobox_value': 1, + 'uiSliderWidget_value': 10, 'radioButton_value': False, + 'textEdit_value': 'test edit 0', 'plainTextEdit_value': 'test plain 0', + 'lineEdit_value': 'test line 0', 'button_value': False}, { + 'label_value': 'Test label state 1', 'checkBox_value': True, 'comboBox_value': 1, 'doubleSpinBox_value': 1.0, 'spinBox_value': 1, 'slider_value': 1, - 'uislider_value': 1, 'radio_value': True, 'textEdit_value': 'test edit 1', - 'plainTextEdit_value': 'test plain 1', 'lineEdit_value': 'test line 1', - 'pushButton_value': True}] + 'uiSliderWidget_value': 1, 'radioButton_value': True, + 'textEdit_value': 'test edit 1', 'plainTextEdit_value': 'test plain 1', + 'lineEdit_value': 'test line 1', 'button_value': True}] return state @property def list_all_widgets(self): + combobox_widget = QtWidgets.QComboBox() + combobox_list = ['choice 1', 'choice 2'] + combobox_widget.addItems(combobox_list) list_all_widgets = { 'label': QtWidgets.QLabel('test label'), - 'checkBox': QtWidgets.QCheckBox('test checkbox'), 'comboBox': QtWidgets.QComboBox(), + 'checkBox': QtWidgets.QCheckBox('test checkbox'), 'comboBox': combobox_widget, 'doubleSpinBox': QtWidgets.QDoubleSpinBox(), 'spinBox': QtWidgets.QSpinBox(), 'slider': QtWidgets.QSlider(), 'uiSliderWidget': UISliderWidget(QtWidgets.QLabel()), 'radioButton': QtWidgets.QRadioButton('test radio button'), @@ -67,36 +78,26 @@ def add_every_widget(self): for key in self.list_all_widgets: form.addWidget(self.list_all_widgets[key], key, key) - def add_every_spanning_widget(self): - """Generate every spanning widget and add it to the form.""" - form = self.form - for key in self.list_all_widgets: - form.addSpanningWidget(self.list_all_widgets[key], f'{key}_spanning') - def add_two_widgets(self): """Generate two widgets and add them to `self.simple_form`""" form = self.simple_form form.addWidget(QtWidgets.QLabel('test label'), 'Label: ', 'label') form.addWidget(QtWidgets.QCheckBox('test checkbox'), 'CheckBox: ', 'checkBox') - def set_state(self, i): + def set_state(self, i: int): """ Applies the values saved in `self.exampleState` at position `i` to the widgets in the form. - - Parameters - ---------------- - i: int """ state = self.exampleState # set the states # QLabel self.form.getWidget('label').setText(state[i]['label_value']) # QCheckBox - self.form.getWidget('checkBox').setChecked(state[i]['checkbox_value']) + self.form.getWidget('checkBox').setChecked(state[i]['checkBox_value']) # QComboBox combobox_list = ['test', 'test2'] self.form.getWidget('comboBox').addItems(combobox_list) - self.form.getWidget('comboBox').setCurrentIndex(state[i]['combobox_value']) + self.form.getWidget('comboBox').setCurrentIndex(state[i]['comboBox_value']) # QDoubleSpinBox self.form.getWidget('doubleSpinBox').setValue(state[i]['doubleSpinBox_value']) # QSpinBox @@ -104,9 +105,9 @@ def set_state(self, i): # QSlider self.form.getWidget('slider').setValue(state[i]['slider_value']) # UISlider - self.form.getWidget('uiSliderWidget').setValue(state[i]['uislider_value']) + self.form.getWidget('uiSliderWidget').setValue(state[i]['uiSliderWidget_value']) # QRadioButton - self.form.getWidget('radioButton').setChecked(state[i]['radio_value']) + self.form.getWidget('radioButton').setChecked(state[i]['radioButton_value']) # QTextEdit self.form.getWidget('textEdit').setText(state[i]['textEdit_value']) # QPlainTextEdit @@ -115,7 +116,42 @@ def set_state(self, i): self.form.getWidget('lineEdit').setText(state[i]['lineEdit_value']) # QPushButton self.form.getWidget('button').setCheckable(True) - self.form.getWidget('button').setChecked(state[i]['pushButton_value']) + self.form.getWidget('button').setChecked(state[i]['button_value']) + + def set_spanning_state(self, i: int): + """ + Applies the values saved in `self.exampleState` at position `i` + to the spanning widgets in the form. + """ + state = self.exampleState + # set the states + # QLabel + self.form.getWidget('label_spanning').setText(state[i]['label_value']) + # QCheckBox + self.form.getWidget('checkBox_spanning').setChecked(state[i]['checkBox_value']) + # QComboBox + combobox_list = ['test', 'test2'] + self.form.getWidget('comboBox_spanning').addItems(combobox_list) + self.form.getWidget('comboBox_spanning').setCurrentIndex(state[i]['comboBox_value']) + # QDoubleSpinBox + self.form.getWidget('doubleSpinBox_spanning').setValue(state[i]['doubleSpinBox_value']) + # QSpinBox + self.form.getWidget('spinBox_spanning').setValue(state[i]['spinBox_value']) + # QSlider + self.form.getWidget('slider_spanning').setValue(state[i]['slider_value']) + # UISlider + self.form.getWidget('uiSliderWidget_spanning').setValue(state[i]['uiSliderWidget_value']) + # QRadioButton + self.form.getWidget('radioButton_spanning').setChecked(state[i]['radioButton_value']) + # QTextEdit + self.form.getWidget('textEdit_spanning').setText(state[i]['textEdit_value']) + # QPlainTextEdit + self.form.getWidget('plainTextEdit_spanning').setPlainText(state[i]['plainTextEdit_value']) + # QLineEdit + self.form.getWidget('lineEdit_spanning').setText(state[i]['lineEdit_value']) + # QPushButton + self.form.getWidget('button_spanning').setCheckable(True) + self.form.getWidget('button_spanning').setChecked(state[i]['button_value']) def _test_add_one_widget(self, name, qwidget, qlabel): """ @@ -437,21 +473,193 @@ def test_getAllWidgetStates(self): self.assertEqual(self.simple_form.getAllWidgetStates(), self.state_simple_form) -@skip_ci +class FormWidgetStateTest(FormsCommonTests, unittest.TestCase): + def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + """ + self.form = FormWidget() + self.add_every_widget() + self.simple_form = FormWidget() + self.add_two_widgets() + self.layout = self.form.uiElements['groupBoxFormLayout'] + + def test_get_name_and_role_from_key_or_widget(self): + """ + Checks that the method `_getNameAndRoleFromKey` returns the correct name and role in + all widgets. + """ + for name in self.list_all_widgets: + for role in {'field', 'label'}: + name_role = name + '_' + role + name_c, role_c = self.form._getNameAndRoleFromKey(name_role) + self.assertEqual(name_c, name) + self.assertEqual(role_c, role) + name_c, role_c = self.form._getNameAndRoleFromWidget( + self.form.getWidget(name, role)) + self.assertEqual(name_c, name) + self.assertEqual(role_c, role) + + def test_getWidgetState_returns_QLabel_value(self): + """Check that the value of the QLabel is saved to the state""" + initial_label_value = 'test label' + self.assertEqual(self.form.getWidgetState('label_field')['value'], initial_label_value) + + final_label_value = 'final test label' + self.form.getWidget('label').setText(final_label_value) + self.assertEqual(self.form.getWidgetState('label_field')['value'], final_label_value) + + def test_saveAllWidgetStates(self): + """Check that the state of all widgets is saved to the state variable""" + self.simple_form.saveAllWidgetStates() + self.assertEqual(self.simple_form.widget_states, self.state_simple_form) + + def test_restoreAllSavedWidgetStates(self): + """Check that the state of all widgets is restored from the state variable""" + state_to_restore = self.state_simple_form + self.simple_form.widget_states = self.state_simple_form + self.simple_form.restoreAllSavedWidgetStates() + + self.assertEqual( + self.simple_form.getWidget('checkBox').isChecked(), + state_to_restore['checkBox_field']['value']) + self.assertEqual( + self.simple_form.getWidget('checkBox').isEnabled(), + state_to_restore['checkBox_field']['enabled']) + self.assertEqual( + self.simple_form.getWidget('checkBox').isVisible(), + state_to_restore['checkBox_field']['visible']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').text(), + state_to_restore['checkBox_label']['value']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').isEnabled(), + state_to_restore['checkBox_label']['enabled']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').isVisible(), + state_to_restore['checkBox_label']['visible']) + self.assertEqual( + self.simple_form.getWidget('label').text(), state_to_restore['label_field']['value']) + self.assertEqual( + self.simple_form.getWidget('label').isEnabled(), + state_to_restore['label_field']['enabled']) + self.assertEqual( + self.simple_form.getWidget('label').isVisible(), + state_to_restore['label_field']['visible']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').text(), + state_to_restore['label_label']['value']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').isEnabled(), + state_to_restore['label_label']['enabled']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').isVisible(), + state_to_restore['label_label']['visible']) + + +class FormDockWidgetStateTest(FormsCommonTests, unittest.TestCase): + def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + """ + self.form = FormDockWidget() + self.add_every_widget() + self.simple_form = FormDockWidget() + self.add_two_widgets() + self.layout = self.form.widget().uiElements['groupBoxFormLayout'] + + def test_form_init_title(self): + """Tests if the FormDockWidget is created correctly with or without the title argument.""" + FormDockWidget() + FormDockWidget(title=None) + FormDockWidget(title='title') + + def test_getWidgetState_returns_QLabel_value(self): + """Check that the value of the QLabel is saved to the state""" + initial_label_value = 'test label' + self.assertEqual(self.form.getWidgetState('label_field')['value'], initial_label_value) + + final_label_value = 'final test label' + self.form.getWidget('label').setText(final_label_value) + self.assertEqual(self.form.getWidgetState('label_field')['value'], final_label_value) + + def test_saveAllWidgetStates(self): + """Check that the state of all widgets is saved to the state variable""" + self.simple_form.saveAllWidgetStates() + self.assertEqual(self.simple_form.widget().widget_states, self.state_simple_form) + + def test_restoreAllSavedWidgetStates(self): + """Check that the state of all widgets is restored from the state variable""" + state_to_restore = self.state_simple_form + self.simple_form.widget().widget_states = self.state_simple_form + self.simple_form.restoreAllSavedWidgetStates() + + self.assertEqual( + self.simple_form.getWidget('checkBox').isChecked(), + state_to_restore['checkBox_field']['value']) + self.assertEqual( + self.simple_form.getWidget('checkBox').isEnabled(), + state_to_restore['checkBox_field']['enabled']) + self.assertEqual( + self.simple_form.getWidget('checkBox').isVisible(), + state_to_restore['checkBox_field']['visible']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').text(), + state_to_restore['checkBox_label']['value']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').isEnabled(), + state_to_restore['checkBox_label']['enabled']) + self.assertEqual( + self.simple_form.getWidget('checkBox', 'label').isVisible(), + state_to_restore['checkBox_label']['visible']) + self.assertEqual( + self.simple_form.getWidget('label').text(), state_to_restore['label_field']['value']) + self.assertEqual( + self.simple_form.getWidget('label').isEnabled(), + state_to_restore['label_field']['enabled']) + self.assertEqual( + self.simple_form.getWidget('label').isVisible(), + state_to_restore['label_field']['visible']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').text(), + state_to_restore['label_label']['value']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').isEnabled(), + state_to_restore['label_label']['enabled']) + self.assertEqual( + self.simple_form.getWidget('label', 'label').isVisible(), + state_to_restore['label_label']['visible']) + + class FormDialogStatusTest(FormsCommonTests, unittest.TestCase): def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + """ self.form = FormDialog() self.add_every_widget() - self.add_every_spanning_widget() self.simple_form = FormDialog() self.add_two_widgets() self.layout = self.form.formWidget.uiElements['groupBoxFormLayout'] self.vertical_layout = self.form.formWidget.uiElements['verticalLayout'] def click_Ok(self): + """ + Clicks the ok button on the form. + + This method simulates a mouse click on the ok button in the form. + """ QTest.mouseClick(self.form.Ok, Qt.LeftButton) def click_Cancel(self): + """ + Clicks the cancel button on the form. + + This method simulates a mouse click on the cancel button in the form. + """ QTest.mouseClick(self.form.Cancel, Qt.LeftButton) def add_every_widget_to_vertical_layout(self): @@ -460,7 +668,7 @@ def add_every_widget_to_vertical_layout(self): self.form.addWidget(self.list_all_widgets[key], qlabel=None, name=None, layout='vertical') - def test_dialog_buttons_default_behaviour(self): + def test_Ok_and_Cancel_button_behaviour(self): # create the states dictionary self.set_state(1) states1 = self.form.getAllWidgetStates() @@ -623,157 +831,210 @@ def test_restoreAllSavedWidgetStates(self): state_to_restore['label_label']['visible']) -@skip_ci -class FormWidgetStateTest(FormsCommonTests, unittest.TestCase): +class AdvancedFormDialogStatusTest(FormDialogStatusTest): def setUp(self): - self.form = FormWidget() + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + + An advanced form dialog with no parent is created. + """ + self.form = AdvancedFormDialog(title='Advanced form dialog without parent') + self.layout = self.form.formWidget.uiElements['groupBoxFormLayout'] + self.vertical_layout = self.form.formWidget.uiElements['verticalLayout'] self.add_every_widget() - self.add_every_spanning_widget() - self.simple_form = FormWidget() + self.simple_form = AdvancedFormDialog() self.add_two_widgets() - self.layout = self.form.uiElements['groupBoxFormLayout'] - def test_get_name_and_role_from_key_or_widget(self): + def click_default_button(self): """ - Checks that the method `_getNameAndRoleFromKey` returns the correct name and role in - all widgets. + Clicks the default button on the form. + + This method simulates a mouse click on the default button of the form. """ - for name in self.list_all_widgets: - for role in {'field', 'label'}: - name_role = name + '_' + role - name_c, role_c = self.form._getNameAndRoleFromKey(name_role) - self.assertEqual(name_c, name) - self.assertEqual(role_c, role) - name_c, role_c = self.form._getNameAndRoleFromWidget( - self.form.getWidget(name, role)) - self.assertEqual(name_c, name) - self.assertEqual(role_c, role) + QTest.mouseClick(self.form.default_button, Qt.LeftButton) - def test_getWidgetState_returns_QLabel_value(self): - """Check that the value of the QLabel is saved to the state""" - initial_label_value = 'test label' - self.assertEqual(self.form.getWidgetState('label_field')['value'], initial_label_value) + def test_position_default_button(self): + """Checks the default button is created in the advanced dialog with and without parent. + Asserts the button's position is 1, hence is located between the form layout and + the ok and cancel buttons.""" + index = self.form.getIndexFromVerticalLayout(self.form.default_button) + self.assertEqual(index, 1) - final_label_value = 'final test label' - self.form.getWidget('label').setText(final_label_value) - self.assertEqual(self.form.getWidgetState('label_field')['value'], final_label_value) + def test_default_button_behaviour(self): + """ + Tests the behavior of the default button on the advanced dialog. - def test_saveAllWidgetStates(self): - """Check that the state of all widgets is saved to the state variable""" - self.simple_form.saveAllWidgetStates() - self.assertEqual(self.simple_form.widget_states, self.state_simple_form) + This test case opens the dialog, updates the widgets, clicks the default + button and then the Ok button. Verifies that the widgets in the dialog + are set to their default states. + """ + self.form.open() + self.set_state(0) + self.click_default_button() + self.click_Ok() + self.assertEqual(self.form.getSavedWidgetStates(), self.form.getDefaultWidgetStates()) - def test_restoreAllSavedWidgetStates(self): - """Check that the state of all widgets is restored from the state variable""" - state_to_restore = self.state_simple_form - self.simple_form.widget_states = self.state_simple_form - self.simple_form.restoreAllSavedWidgetStates() - self.assertEqual( - self.simple_form.getWidget('checkBox').isChecked(), - state_to_restore['checkBox_field']['value']) - self.assertEqual( - self.simple_form.getWidget('checkBox').isEnabled(), - state_to_restore['checkBox_field']['enabled']) - self.assertEqual( - self.simple_form.getWidget('checkBox').isVisible(), - state_to_restore['checkBox_field']['visible']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').text(), - state_to_restore['checkBox_label']['value']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').isEnabled(), - state_to_restore['checkBox_label']['enabled']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').isVisible(), - state_to_restore['checkBox_label']['visible']) - self.assertEqual( - self.simple_form.getWidget('label').text(), state_to_restore['label_field']['value']) - self.assertEqual( - self.simple_form.getWidget('label').isEnabled(), - state_to_restore['label_field']['enabled']) - self.assertEqual( - self.simple_form.getWidget('label').isVisible(), - state_to_restore['label_field']['visible']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').text(), - state_to_restore['label_label']['value']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').isEnabled(), - state_to_restore['label_label']['enabled']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').isVisible(), - state_to_restore['label_label']['visible']) +class AdvancedFormDialogWithParentStatusTest(AdvancedFormDialogStatusTest): + def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + An advanced form dialog with parent is created. + """ + self.form_parent = FormWidget() + self.form_parent.addSpanningWidget(QtWidgets.QPushButton("Open Advanced Dialog"), + 'button_advanced') + self.form = AdvancedFormDialog(parent=self.form_parent, title='Advanced form dialog', + parent_button_name='button_advanced') -@skip_ci -class FormDockWidgetStateTest(FormsCommonTests, unittest.TestCase): - def setUp(self): - self.form = FormDockWidget() + self.layout = self.form.formWidget.uiElements['groupBoxFormLayout'] + self.vertical_layout = self.form.formWidget.uiElements['verticalLayout'] self.add_every_widget() - self.add_every_spanning_widget() - self.simple_form = FormDockWidget() + for key in self.list_all_widgets: + self.form.displayWidgetValueOnParent(key) + + self.simple_form = AdvancedFormDialog() self.add_two_widgets() - self.layout = self.form.widget().uiElements['groupBoxFormLayout'] - def test_form_init_title(self): - """Tests if the FormDockWidget is created correctly with or without the title argument.""" - FormDockWidget() - FormDockWidget(title=None) - FormDockWidget(title='title') + def _test_parent_state(self, i): + """ + Gets the parent widget states and compares them with the expected states. + If the value in the parent originated from the ComboBox in the advanced dialog, + it is converted to its corresponding index in the comboBox before comparison. + """ + parent_states = self.form_parent.getAllWidgetStates() + for name in self.list_all_widgets: + if isinstance(self.list_all_widgets[name], QtWidgets.QComboBox): + value = parent_states[f'{name}_field']['value'] + parent_states[f'{name}_field']['value'] = str( + self.form.getWidget(name, 'field').findText(value)) + self.assertEqual(parent_states[f'{name}_field']['value'], + str(self.exampleState[i][f'{name}_value'])) + self.assertEqual(parent_states[f'{name}_label']['value'], name) + + def test_ok_button_behaviour(self): + """ + Tests the behavior of the Ok button on the advanced dialog. + + This test case verifies the button's behavior in different scenarios: + 1. Clicks the Ok button without changing any states and verifies that the parent + widget states remain unchanged. + 2. Changes the states and click the OK button, then verifies that the parent widget + states are updated correctly. + 3. Clicks the default button and then the OK button, and verifies that the parent widget + states are restored to their initial values. + """ + # 1. + parent_initial_states = self.form_parent.getAllWidgetStates() + self.form.open() + self.click_Ok() + parent_states = self.form_parent.getAllWidgetStates() + self.assertEqual(parent_states, parent_initial_states) + # 2. + for i in [0, 1]: + self.set_state(i) + self.form.open() + self.click_Ok() + self._test_parent_state(i) + # 3. + self.form.open() + self.click_default_button() + self.click_Ok() + parent_states = self.form_parent.getAllWidgetStates() + self.assertEqual(parent_states, parent_initial_states) - def test_getWidgetState_returns_QLabel_value(self): - """Check that the value of the QLabel is saved to the state""" - initial_label_value = 'test label' - self.assertEqual(self.form.getWidgetState('label_field')['value'], initial_label_value) + def test_cancel_button_behaviour(self): + """ + Tests the behavior of the Cancel button on the advanced dialog. + + This test case verifies the button's behavior in different scenarios: + 1. Opens the dialog, clicks the Cancel button without changing any states and verifies that + the parent-widget states remain unchanged. + 2. Opens the dialog, update the widgets and clicks the Cancel button. Verifies that the + parent-widget states remain unchanged. + 3. Opens the dialog, updates the widgets and clicks the Ok button. Then reopens the dialog, + changes the states and clicks the Cancel button. Verifies that the parent widget states are + those set before reopening the dialog. + 4. Opens the dialog, clicks the default button and then the Cancel button. Verifies that + the parent widget states remain unchanged. + """ + # 1. + parent_initial_states = self.form_parent.getAllWidgetStates() + self.form.open() + self.click_Cancel() + parent_states = self.form_parent.getAllWidgetStates() + self.assertEqual(parent_states, parent_initial_states) + # 2. + self.form.open() + self.set_state(0) + self.click_Cancel() + parent_states = self.form_parent.getAllWidgetStates() + self.assertEqual(parent_states, parent_initial_states) + # 3. + self.form.open() + self.set_state(0) + self.click_Ok() + self.form.open() + self.set_state(1) + self.click_Cancel() + self._test_parent_state(0) + # 4. + self.form.open() + self.click_default_button() + self.click_Cancel() + self._test_parent_state(0) + """ + Tests the behavior of the default button on the advanced dialog. - final_label_value = 'final test label' - self.form.getWidget('label').setText(final_label_value) - self.assertEqual(self.form.getWidgetState('label_field')['value'], final_label_value) + This test case opens the dialog, updates the widgets, clicks the default + button and then the Ok button. Verifies that the widgets in the dialog + are set to their default states. + """ + self.form.open() + self.set_state(0) + self.click_default_button() + self.click_Ok() + self.assertEqual(self.form.getSavedWidgetStates(), self.form.getDefaultWidgetStates()) - def test_saveAllWidgetStates(self): - """Check that the state of all widgets is saved to the state variable""" - self.simple_form.saveAllWidgetStates() - self.assertEqual(self.simple_form.widget().widget_states, self.state_simple_form) + def test_button_argument(self): + "Checks that the widgets are placed in the expected rows under the parent button." + self.set_state(0) + self.click_Ok() + for index, name in enumerate(self.list_all_widgets, start=1): + row = self.form_parent.getWidgetRow(name) + self.assertEqual(row, self.form.parent_button_row + index) - def test_restoreAllSavedWidgetStates(self): - """Check that the state of all widgets is restored from the state variable""" - state_to_restore = self.state_simple_form - self.simple_form.widget().widget_states = self.state_simple_form - self.simple_form.restoreAllSavedWidgetStates() - self.assertEqual( - self.simple_form.getWidget('checkBox').isChecked(), - state_to_restore['checkBox_field']['value']) - self.assertEqual( - self.simple_form.getWidget('checkBox').isEnabled(), - state_to_restore['checkBox_field']['enabled']) - self.assertEqual( - self.simple_form.getWidget('checkBox').isVisible(), - state_to_restore['checkBox_field']['visible']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').text(), - state_to_restore['checkBox_label']['value']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').isEnabled(), - state_to_restore['checkBox_label']['enabled']) - self.assertEqual( - self.simple_form.getWidget('checkBox', 'label').isVisible(), - state_to_restore['checkBox_label']['visible']) - self.assertEqual( - self.simple_form.getWidget('label').text(), state_to_restore['label_field']['value']) - self.assertEqual( - self.simple_form.getWidget('label').isEnabled(), - state_to_restore['label_field']['enabled']) - self.assertEqual( - self.simple_form.getWidget('label').isVisible(), - state_to_restore['label_field']['visible']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').text(), - state_to_restore['label_label']['value']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').isEnabled(), - state_to_restore['label_label']['enabled']) - self.assertEqual( - self.simple_form.getWidget('label', 'label').isVisible(), - state_to_restore['label_label']['visible']) +class AdvancedFormDialogNoButtonArgumentStatusTest(AdvancedFormDialogWithParentStatusTest): + def setUp(self): + """ + Set up the test environment by initialising the necessary objects and widgets. + This method is executed before each test case. + + An advanced form dialog with parent and no argument `parent_button_name` is created. + """ + self.form_parent = FormWidget() + self.form_parent.addSpanningWidget(QtWidgets.QPushButton("Open Advanced Dialog"), + 'button_advanced') + self.form = AdvancedFormDialog(parent=self.form_parent, title='Advanced form dialog') + + self.layout = self.form.formWidget.uiElements['groupBoxFormLayout'] + self.vertical_layout = self.form.formWidget.uiElements['verticalLayout'] + self.add_every_widget() + for name in self.list_all_widgets: + self.form.displayWidgetValueOnParent(name) + + self.simple_form = AdvancedFormDialog() + self.add_two_widgets() + + def test_button_argument(self): + "Checks that the widgets are placed in the expected row in the parent layout." + num_initial = self.form_parent.getNumWidgets() + self.set_state(0) + self.click_Ok() + for index, name in enumerate(self.list_all_widgets): + row = self.form_parent.getWidgetRow(name) + self.assertEqual(row, num_initial + index)