Skip to content

Commit 51f6787

Browse files
committed
Return FormWidget from WidgetBuilder.create_form
Add error window to `FormWidget`
1 parent 2e5e1b4 commit 51f6787

File tree

3 files changed

+77
-35
lines changed

3 files changed

+77
-35
lines changed

qt_jsonschema_form/form.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ def get_schema_type(schema: dict) -> str:
1818

1919
class WidgetBuilder:
2020
default_widget_map = {
21-
"boolean": {"checkbox": widgets.CheckboxWidget, "enum": widgets.EnumWidget},
22-
"object": {"object": widgets.ObjectWidget, "enum": widgets.EnumWidget},
23-
"number": {"spin": widgets.SpinDoubleWidget, "text": widgets.TextWidget, "enum": widgets.EnumWidget},
24-
"string": {"textarea": widgets.TextAreaWidget, "text": widgets.TextWidget, "password": widgets.PasswordWidget,
25-
"filepath": widgets.FilepathWidget, "colour": widgets.ColorWidget, "enum": widgets.EnumWidget},
26-
"integer": {"spin": widgets.SpinWidget, "text": widgets.TextWidget, "range": widgets.IntegerRangeWidget,
27-
"enum": widgets.EnumWidget},
28-
"array": {"array": widgets.ArrayWidget, "enum": widgets.EnumWidget}
21+
"boolean": {"checkbox": widgets.CheckboxSchemaWidget, "enum": widgets.EnumSchemaWidget},
22+
"object": {"object": widgets.ObjectSchemaWidget, "enum": widgets.EnumSchemaWidget},
23+
"number": {"spin": widgets.SpinDoubleSchemaWidget, "text": widgets.TextSchemaWidget, "enum": widgets.EnumSchemaWidget},
24+
"string": {"textarea": widgets.TextAreaSchemaWidget, "text": widgets.TextSchemaWidget, "password": widgets.PasswordWidget,
25+
"filepath": widgets.FilepathSchemaWidget, "colour": widgets.ColorSchemaWidget, "enum": widgets.EnumSchemaWidget},
26+
"integer": {"spin": widgets.SpinSchemaWidget, "text": widgets.TextSchemaWidget, "range": widgets.IntegerRangeSchemaWidget,
27+
"enum": widgets.EnumSchemaWidget},
28+
"array": {"array": widgets.ArraySchemaWidget, "enum": widgets.EnumSchemaWidget}
2929
}
3030

3131
default_widget_variants = {
@@ -45,24 +45,31 @@ def __init__(self, validator_cls=None):
4545
self.widget_map = deepcopy(self.default_widget_map)
4646
self.validator_cls = validator_cls
4747

48-
def create_form(self, schema: dict, ui_schema: dict, state=None) -> widgets.WidgetMixin:
48+
def create_form(self, schema: dict, ui_schema: dict, state=None) -> widgets.SchemaWidgetMixin:
4949
validator_cls = self.validator_cls
5050
if validator_cls is None:
5151
validator_cls = validator_for(schema)
5252

5353
validator_cls.check_schema(schema)
5454
validator = validator_cls(schema)
55-
widget = self.create_widget(schema, ui_schema, state)
55+
schema_widget = self.create_widget(schema, ui_schema, state)
56+
form = widgets.FormWidget(schema_widget)
5657

5758
def validate(data):
58-
for err in validator.iter_errors(data):
59-
widget.handle_error(err.path, err)
59+
form.clear_errors()
60+
errors = [*validator.iter_errors(data)]
6061

61-
widget.on_changed.connect(validate)
62+
if errors:
63+
form.display_errors(errors)
6264

63-
return widget
65+
for err in errors:
66+
schema_widget.handle_error(err.path, err)
67+
68+
schema_widget.on_changed.connect(validate)
69+
70+
return form
6471

65-
def create_widget(self, schema: dict, ui_schema: dict, state=None) -> widgets.WidgetMixin:
72+
def create_widget(self, schema: dict, ui_schema: dict, state=None) -> widgets.SchemaWidgetMixin:
6673
schema_type = get_schema_type(schema)
6774

6875
try:

qt_jsonschema_form/widgets.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .utils import iter_layout_widgets, state_property, is_concrete_schema
99

1010

11-
class WidgetMixin:
11+
class SchemaWidgetMixin:
1212
on_changed = Signal()
1313

1414
VALID_COLOUR = '#ffffff'
@@ -53,7 +53,7 @@ def _set_valid_state(self, error: Exception = None):
5353
self.setToolTip("" if error is None else error.message) # TODO
5454

5555

56-
class TextWidget(WidgetMixin, QtWidgets.QLineEdit):
56+
class TextSchemaWidget(SchemaWidgetMixin, QtWidgets.QLineEdit):
5757

5858
def configure(self):
5959
self.textChanged.connect(self.on_changed.emit)
@@ -67,15 +67,15 @@ def state(self, state: str):
6767
self.setText(state)
6868

6969

70-
class PasswordWidget(TextWidget):
70+
class PasswordWidget(TextSchemaWidget):
7171

7272
def configure(self):
7373
super().configure()
7474

7575
self.setEchoMode(self.Password)
7676

7777

78-
class TextAreaWidget(WidgetMixin, QtWidgets.QTextEdit):
78+
class TextAreaSchemaWidget(SchemaWidgetMixin, QtWidgets.QTextEdit):
7979

8080
@state_property
8181
def state(self) -> str:
@@ -89,7 +89,7 @@ def configure(self):
8989
self.textChanged.connect(lambda: self.on_changed.emit(self.state))
9090

9191

92-
class CheckboxWidget(WidgetMixin, QtWidgets.QCheckBox):
92+
class CheckboxSchemaWidget(SchemaWidgetMixin, QtWidgets.QCheckBox):
9393

9494
@state_property
9595
def state(self) -> bool:
@@ -103,7 +103,7 @@ def configure(self):
103103
self.stateChanged.connect(lambda _: self.on_changed.emit(self.state))
104104

105105

106-
class SpinDoubleWidget(WidgetMixin, QtWidgets.QDoubleSpinBox):
106+
class SpinDoubleSchemaWidget(SchemaWidgetMixin, QtWidgets.QDoubleSpinBox):
107107

108108
@state_property
109109
def state(self) -> float:
@@ -117,7 +117,7 @@ def configure(self):
117117
self.valueChanged.connect(self.on_changed.emit)
118118

119119

120-
class SpinWidget(WidgetMixin, QtWidgets.QSpinBox):
120+
class SpinSchemaWidget(SchemaWidgetMixin, QtWidgets.QSpinBox):
121121

122122
@state_property
123123
def state(self) -> int:
@@ -131,7 +131,7 @@ def configure(self):
131131
self.valueChanged.connect(self.on_changed.emit)
132132

133133

134-
class IntegerRangeWidget(WidgetMixin, QtWidgets.QSlider):
134+
class IntegerRangeSchemaWidget(SchemaWidgetMixin, QtWidgets.QSlider):
135135

136136
def __init__(self, schema: dict, ui_schema: dict, widget_builder: 'WidgetBuilder'):
137137
super().__init__(schema, ui_schema, widget_builder, orientation=QtCore.Qt.Horizontal)
@@ -209,7 +209,7 @@ def mousePressEvent(self, event):
209209
return super(QColorButton, self).mousePressEvent(event)
210210

211211

212-
class ColorWidget(WidgetMixin, QColorButton):
212+
class ColorSchemaWidget(SchemaWidgetMixin, QColorButton):
213213
"""Widget representation of a string with the 'color' format keyword."""
214214

215215
def configure(self):
@@ -224,7 +224,7 @@ def state(self, data: str):
224224
self.setColor(data)
225225

226226

227-
class FilepathWidget(WidgetMixin, QtWidgets.QWidget):
227+
class FilepathSchemaWidget(SchemaWidgetMixin, QtWidgets.QWidget):
228228

229229
def __init__(self, schema: dict, ui_schema: dict, widget_builder: 'WidgetBuilder'):
230230
super().__init__(schema, ui_schema, widget_builder)
@@ -298,7 +298,7 @@ def __init__(self, widget: QtWidgets.QWidget, controls: ArrayControlsWidget):
298298
self.controls = controls
299299

300300

301-
class ArrayWidget(WidgetMixin, QtWidgets.QWidget):
301+
class ArraySchemaWidget(SchemaWidgetMixin, QtWidgets.QWidget):
302302

303303
@property
304304
def rows(self) -> List[ArrayRowWidget]:
@@ -434,7 +434,7 @@ def widget_on_changed(self, row: ArrayRowWidget, value):
434434
self.on_changed.emit(self.state)
435435

436436

437-
class ObjectWidget(WidgetMixin, QtWidgets.QGroupBox):
437+
class ObjectSchemaWidget(SchemaWidgetMixin, QtWidgets.QGroupBox):
438438

439439
def __init__(self, schema: dict, ui_schema: dict, widget_builder: 'WidgetBuilder'):
440440
super().__init__(schema, ui_schema, widget_builder)
@@ -485,7 +485,7 @@ def populate_from_schema(self, schema: dict, ui_schema: dict, widget_builder: 'W
485485
return widgets
486486

487487

488-
class EnumWidget(WidgetMixin, QtWidgets.QComboBox):
488+
class EnumSchemaWidget(SchemaWidgetMixin, QtWidgets.QComboBox):
489489

490490
@state_property
491491
def state(self):
@@ -507,5 +507,40 @@ def configure(self):
507507
self.currentIndexChanged.connect(lambda _: self.on_changed.emit(self.state))
508508

509509
def _index_changed(self, index: int):
510-
value = self.itemData(index)
511-
self.on_changed.emit(self.state)
510+
self.on_changed.emit(self.state)
511+
512+
513+
class FormWidget(QtWidgets.QWidget):
514+
515+
def __init__(self, widget):
516+
super().__init__()
517+
layout = QtWidgets.QVBoxLayout()
518+
self.setLayout(layout)
519+
520+
self.error_widget = QtWidgets.QGroupBox()
521+
self.error_widget.setTitle("Errors")
522+
self.error_layout = QtWidgets.QVBoxLayout()
523+
self.error_widget.setLayout(self.error_layout)
524+
self.error_widget.hide()
525+
526+
layout.addWidget(self.error_widget)
527+
layout.addWidget(widget)
528+
529+
self.widget = widget
530+
531+
def display_errors(self, errors: List[Exception]):
532+
self.error_widget.show()
533+
534+
layout = self.error_widget.layout()
535+
while True:
536+
item = layout.takeAt(0)
537+
if not item:
538+
break
539+
item.widget().deleteLater()
540+
541+
for err in errors:
542+
widget = QtWidgets.QLabel(f"<b>.{'.'.join(err.path)}</b> {err.message}")
543+
layout.addWidget(widget)
544+
545+
def clear_errors(self):
546+
self.error_widget.hide()

test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
}
6262

6363
}
64-
w = wb.create_form(s, uis)
65-
w.state = {
64+
form = wb.create_form(s, uis)
65+
form.state = {
6666
"schema_path": "/home/angus/PycharmProjects/qt-jsonschema-form/qt_jsonschema_form/__pycache__/__init__.cpython-37.pyc",
6767
"integerRangeSteps": 60,
6868
"sky_colour": "#8f5902",
@@ -71,9 +71,9 @@
7171
"Bob"
7272
]
7373
}
74-
w.show()
75-
w.on_changed.connect(lambda d: print(dumps(d, indent=4)))
74+
form.show()
75+
form.widget.on_changed.connect(lambda d: print(dumps(d, indent=4)))
7676

77-
print(w)
77+
print(form)
7878
app.exec_()
7979

0 commit comments

Comments
 (0)