Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save entries by default in the Form Dialog #97

Merged
merged 32 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
906dd76
Add functionality of default saving in a new example
DanicaSTFC Oct 19, 2023
c143250
Save states and restore states as a default in FormDialog
DanicaSTFC Oct 20, 2023
071aa0c
Add all widgets to example 3 and set state method
DanicaSTFC Oct 20, 2023
9473391
Add unit test for state changes in form dialog --- not finished
DanicaSTFC Oct 20, 2023
2e05d97
Unit tests working
DanicaSTFC Oct 26, 2023
0538ef5
Modify and tidy example
DanicaSTFC Oct 26, 2023
46231b5
Add minor changes
DanicaSTFC Oct 26, 2023
d2cfb9a
Add changes from pre-commit
DanicaSTFC Oct 26, 2023
ffe74e4
Fix first cancel call bug
DanicaSTFC Oct 30, 2023
00dbb7a
Save default values one by one in `_addWidget`
DanicaSTFC Oct 30, 2023
6be5a9c
Close dialog when Ok is clicked and add example file for methods
DanicaSTFC Oct 31, 2023
4c5ca41
Add example state to tests, add docstring to set_state
DanicaSTFC Oct 31, 2023
540f27e
ii changed to i in test set_state
DanicaSTFC Nov 17, 2023
006e4a9
Improve applyDefaultWidgetValuesToState with docstring and new name
DanicaSTFC Nov 17, 2023
54235ec
Change docstring to restoreAllSavedWidgetStates
DanicaSTFC Nov 17, 2023
424d6b4
Pre-commit run
DanicaSTFC Nov 17, 2023
92d1332
Fix issues with unit tests
lauramurgatroyd Nov 21, 2023
94f172e
Fix issues with session label
lauramurgatroyd Nov 21, 2023
d6d2cc6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 21, 2023
73f419c
Fix formatting
lauramurgatroyd Nov 21, 2023
ccdf0fa
Remove unused imports
lauramurgatroyd Nov 21, 2023
05ff037
remove prints
lauramurgatroyd Nov 21, 2023
d3bf171
Add default widget state as a larger dictionary
DanicaSTFC Nov 23, 2023
90ea8e8
Polish test_dialog_buttons_default_behaviour
DanicaSTFC Nov 23, 2023
1ecc16a
pre-commit run
DanicaSTFC Nov 23, 2023
69701cd
improve docstring and other minor things
DanicaSTFC Nov 23, 2023
1afac70
merge origin main (remove widgets)
DanicaSTFC Nov 23, 2023
6643167
Attempt to make remove widget and save default states compatible, not…
DanicaSTFC Nov 24, 2023
970be18
Polish code and run pre-commit
DanicaSTFC Dec 4, 2023
53104e8
Merge branch 'main' of github.com:TomographicImaging/eqt
DanicaSTFC Dec 4, 2023
e99a648
Merge fix_unit_tests
DanicaSTFC Dec 4, 2023
f9a342b
Change method name and remove qlabel from default state dictionary
DanicaSTFC Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions eqt/ui/FormDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(self, parent=None, title=None):
self.setWindowTitle(title)
# add button box to the UI
self.formWidget.uiElements['verticalLayout'].addWidget(bb)
bb.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self._onOk)
bb.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self._onCancel)

@property
Expand All @@ -35,14 +36,27 @@ def Cancel(self):
'''returns a reference to the Dialog Cancel button to connect its signals'''
return self.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel)

def _onOk(self):
'''saves the widget states and calls `onOk`'''
self.saveAllWidgetStates()
self.onOk()
self.close()

DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
def _onCancel(self):
'''calls onCancel and closes the FormDialog'''
'''calls `onCancel`, restores the previously saved states if existing and
closes the FormDialog'''
self.onCancel()
self.restoreAllSavedWidgetStates()
self.close()

def onOk(self):
'''Called when the dialog's "Ok" button is clicked.
Can be redefined to add additional functionality on "Ok"'''
pass

def onCancel(self):
'''Called when the dialog's "Cancel" button is clicked.
Can be redefined to add additional functionality on "Cancel"'''
Can be redefined to add additional functionality on "Cancel"'''
pass

@property
Expand Down
24 changes: 20 additions & 4 deletions eqt/ui/UIFormWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def addSeparator(self, name):
def _addWidget(self, name, qwidget, qlabel=None):
formLayout = self.uiElements['groupBoxFormLayout']

# create the default values
if not hasattr(self, 'widget_default'):
self.widget_default={}
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved

# Create the widgets:

widgetno = self.num_widgets
Expand All @@ -117,6 +121,9 @@ def _addWidget(self, name, qwidget, qlabel=None):
field = f'{name}_field'
self.widgets[field] = qwidget

# add the default value of the qwidget
self.widget_default[field]=self.getWidgetState(qwidget)['value']

if qlabel is not None:
# add the label
label = f'{name}_label'
Expand All @@ -125,19 +132,27 @@ def _addWidget(self, name, qwidget, qlabel=None):
qlabel = QtWidgets.QLabel(self.uiElements['groupBox'])
qlabel.setText(txt)
formLayout.setWidget(widgetno, QtWidgets.QFormLayout.LabelRole, qlabel)

# save a reference to label widgets in the dictionary
self.widgets[label] = qlabel

field_form_role = QtWidgets.QFormLayout.FieldRole

# add the default value of the qlabel
self.widget_default[label]=self.getWidgetState(qlabel,label)['value']

else:
# In the case we don't have a qlabel, set a spanning widget:
field_form_role = QtWidgets.QFormLayout.SpanningRole

formLayout.setWidget(widgetno, field_form_role, qwidget)
self.num_widgets += 1

def applyWidgetValuesToState(self):
self.saveAllWidgetStates()
for state_key in self.widget_default.keys():
self.widget_states[state_key]['value']=self.widget_default[state_key]

DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
def getAllWidgetStates(self):
'''
Returns
Expand Down Expand Up @@ -299,10 +314,11 @@ def restoreAllSavedWidgetStates(self):
Restore all widgets in the form to the state saved by `saveAllWidgetStates()`.
If `saveAllWidgetStates()` method was not previously invoked, do nothing.
'''
if hasattr(self, 'widget_states'):
self.applyWidgetStates(self.widget_states)

if not hasattr(self, 'widget_states'):
self.applyWidgetValuesToState()
self.applyWidgetStates(self.widget_states)
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved


class FormWidget(QtWidgets.QWidget, UIFormWidget):
def __init__(self, parent=None):
# dockWidgetContents = QtWidgets.QWidget()
Expand Down
51 changes: 51 additions & 0 deletions examples/dialog_example_3_save_default.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import sys

from PySide2 import QtWidgets

from eqt.ui import FormDialog

import utilitiesForExamples as utex


class MainUI(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)

pb = QtWidgets.QPushButton(self)
pb.setText("Open Dialog with form layout")
pb.clicked.connect(lambda: self.executeDialog())

layout = QtWidgets.QHBoxLayout()
layout.addWidget(pb)
widg = QtWidgets.QWidget()
widg.setLayout(layout)

self.setCentralWidget(widg)
self.dialog = FormDialog(parent=self, title='Example')
self.openFormDialog()

self.show()

def openFormDialog(self):
utex.addWidgetsToExample(self.dialog)
# redefine the onOk and onCancel functions
self.dialog.onOk = self.accepted
self.dialog.onCancel = self.rejected

def accepted(self):
print("States saved")

def rejected(self):
print("States rejected")

# open dialog function when the parent button is clicked
def executeDialog(self):
self.dialog.open()


if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)

window = MainUI()

sys.exit(app.exec_())
26 changes: 26 additions & 0 deletions examples/utilitiesForExamples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from PySide2 import QtWidgets
from eqt.ui.UISliderWidget import UISliderWidget

def addWidgetsToExample(form):
'''
Adds a spanning widget and every type of widget to a form
'''
# add a spanning widget
form.addSpanningWidget(QtWidgets.QLabel("Input Values: "), 'input_title')
# add all widgets
form.addWidget(QtWidgets.QLabel('Label'), 'Label: ', 'label')
form.addWidget(QtWidgets.QCheckBox('check me'), 'CheckBox: ', 'checkBox')
combobox_list = ['choice 1', 'choice 2']
form.addWidget(QtWidgets.QComboBox(), 'ComboBox: ', 'comboBox')
form.getWidget('comboBox').addItems(combobox_list)
form.addWidget(QtWidgets.QDoubleSpinBox(), 'DoubleSpinBox: ', 'doubleSpinBox')
form.addWidget(QtWidgets.QSpinBox(), 'SpinBox: ', 'spinBox')
form.addWidget(QtWidgets.QSlider(), 'Slider: ', 'slider')
form.addWidget(UISliderWidget(QtWidgets.QLabel()), 'UISlider: ', 'uiSliderWidget')
form.addWidget(QtWidgets.QRadioButton('select me'), 'RadioButton: ', 'radioButton')
form.addWidget(QtWidgets.QTextEdit('write text here'), 'TextEdit: ', 'textEdit')
form.addWidget(QtWidgets.QPlainTextEdit('write text here'), 'PlainTextEdit: ',
'plainTextEdit')
form.addWidget(QtWidgets.QLineEdit('write text here'), 'LineEdit: ', 'lineEdit')
form.addWidget(QtWidgets.QPushButton('Click me'), 'Button: ', 'button')

97 changes: 97 additions & 0 deletions test/test__formUI_status_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from unittest import mock

from PySide2 import QtWidgets
from PySide2.QtCore import Qt
from PySide2.QtTest import QTest

from eqt.ui.FormDialog import FormDialog
from eqt.ui.UIFormWidget import FormDockWidget, FormWidget
Expand All @@ -13,9 +15,29 @@

class FormsCommonTests(metaclass=abc.ABCMeta):
"""Common tests for all Form types"""

@abc.abstractmethod
def setUp(self):
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,
'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,
'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}
]
return state

def add_every_widget(self):
"""Generate every widget and add it to `self.form`"""
Expand All @@ -39,6 +61,44 @@ def add_two_widgets(self):
form.addWidget(QtWidgets.QLabel('test label'), 'Label: ', 'label')
form.addWidget(QtWidgets.QCheckBox('test checkbox'), 'CheckBox: ', 'checkBox')

def set_state(self, ii):
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
"""
Applies the values saved in `self.exampleState` at position `ii` to the widgets in the form.

Parameters
----------------
ii: int
"""
state=self.exampleState
# set the states
# QLabel
self.form.getWidget('label').setText(state[ii]['label_value'])
# QCheckBox
self.form.getWidget('checkBox').setChecked(state[ii]['checkbox_value'])
# QComboBox
combobox_list = ['test', 'test2']
self.form.getWidget('comboBox').addItems(combobox_list)
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
self.form.getWidget('comboBox').setCurrentIndex(state[ii]['combobox_value'])
# QDoubleSpinBox
self.form.getWidget('doubleSpinBox').setValue(state[ii]['doubleSpinBox_value'])
# QSpinBox
self.form.getWidget('spinBox').setValue(state[ii]['spinBox_value'])
# QSlider
self.form.getWidget('slider').setValue(state[ii]['slider_value'])
# UISlider
self.form.getWidget('uiSliderWidget').setValue(state[ii]['uislider_value'])
# QRadioButton
self.form.getWidget('radioButton').setChecked(state[ii]['radio_value'])
# QTextEdit
self.form.getWidget('textEdit').setText(state[ii]['textEdit_value'])
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
# QPlainTextEdit
self.form.getWidget('plainTextEdit').setPlainText(state[ii]['plainTextEdit_value'])
# QLineEdit
self.form.getWidget('lineEdit').setText(state[ii]['lineEdit_value'])
# QPushButton
self.form.getWidget('button').setCheckable(True)
self.form.getWidget('button').setChecked(state[ii]['pushButton_value'])

def test_getWidgetState_returns_visibility(self):
"""
Check that the visibility of the widget is saved to the state
Expand Down Expand Up @@ -296,6 +356,43 @@ def setUp(self):
self.simple_form = FormDialog()
self.add_two_widgets()

def click_Ok(self):
QTest.mouseClick(self.form.Ok, Qt.LeftButton)

def click_Cancel(self):
QTest.mouseClick(self.form.Cancel, Qt.LeftButton)

def test_save_states_default(self):
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
# test both states are working
# state1
self.set_state(1)
states1 = self.form.getAllWidgetStates()
self.assertEqual(states1, self.form.getAllWidgetStates())
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
# state0
self.set_state(0)
states0 = self.form.getAllWidgetStates()
self.assertNotEqual(states1, self.form.getAllWidgetStates())
self.assertEqual(states0, self.form.getAllWidgetStates())
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
DanicaSTFC marked this conversation as resolved.
Show resolved Hide resolved
# check state 0 and 1 are not saved when Cancel is pressed
self.click_Cancel()
self.assertNotEqual(states0, self.form.getAllWidgetStates())
self.assertNotEqual(states1, self.form.getAllWidgetStates())
# save state 0
self.set_state(0)
self.assertEqual(states0, self.form.getAllWidgetStates())
self.click_Ok()
self.assertEqual(states0, self.form.getAllWidgetStates())
# save state 1
self.set_state(1)
self.assertEqual(states1, self.form.getAllWidgetStates())
self.click_Ok()
self.assertEqual(states1, self.form.getAllWidgetStates())
# change to state 0 without saving
self.set_state(0)
self.assertEqual(states0, self.form.getAllWidgetStates())
self.click_Cancel()
self.assertEqual(states1, self.form.getAllWidgetStates())

def test_getWidgetState_returns_QLabel_value(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we have decided on the method for applying the default widget values, please add a test for this.

Copy link
Collaborator Author

@DanicaSTFC DanicaSTFC Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After our discussion from yesterday, I do not think it is worth adding a test as I just invoked your methods. What do you think? (see new commits from today)

"""Check that the value of the QLabel is saved to the state"""
initial_label_value = 'Label: '
Expand Down