diff --git a/src/lib/db/__init__.py b/src/lib/db/__init__.py
index 9bf0cd9..d8f0a4f 100644
--- a/src/lib/db/__init__.py
+++ b/src/lib/db/__init__.py
@@ -59,66 +59,66 @@ if admin is None or not admin.is_admin:
Users.register(username="ADMIN", password="123123", roles=["admin"])
# register or reset user
Users.register(username="USER", password="user")
-# register test steps
-Steps.replace(
- id=0,
- name="TEST_LEAK_TEST",
- type="leak",
- spec={
- "pre_filling_time": 5,
- "pre_filling_pressure": 1000,
- "filling_time": 5,
- "settling_time": 10,
- "settling_pressure_min_percent": 50,
- "settling_pressure_max_percent": 50,
- "test_time": 10,
- "test_pressure_min_delta": 500,
- "test_pressure": 1000,
- "test_pressure_max_delta": 500,
- "flush_time": 2,
- "flush_pressure": 5,
- },
- description="TEST_DESCRIPTION",
- archived=False,
-).execute()
-Steps.replace(
- id=1,
- name="TEST_LEAK_TEST",
- type="leak",
- spec={
- "pre_filling_time": 5,
- "pre_filling_pressure": 1000,
- "filling_time": 5,
- "settling_time": 10,
- "settling_pressure_min_percent": 50,
- "settling_pressure_max_percent": 50,
- "test_time": 10,
- "test_pressure_min_delta": 500,
- "test_pressure": 1000,
- "test_pressure_max_delta": 500,
- "flush_time": 2,
- "flush_pressure": 5,
- },
- description="TEST_DESCRIPTION",
- archived=False,
-).execute()
-Steps.replace(
- id=2,
- name="TEST_VISION_TEST",
- type="vision",
- spec={
- "recipe": "1.ini",
- },
- description="TEST_DESCRIPTION VISION_RECIPE: 1",
- archived=False,
-).execute()
+# # register test steps
+# Steps.replace(
+# id=0,
+# name="TEST_LEAK_TEST",
+# type="leak",
+# spec={
+# "pre_filling_time": 5,
+# "pre_filling_pressure": 1000,
+# "filling_time": 5,
+# "settling_time": 10,
+# "settling_pressure_min_percent": 50,
+# "settling_pressure_max_percent": 50,
+# "test_time": 10,
+# "test_pressure_min_delta": 500,
+# "test_pressure": 1000,
+# "test_pressure_max_delta": 500,
+# "flush_time": 2,
+# "flush_pressure": 5,
+# },
+# description="TEST_DESCRIPTION",
+# archived=False,
+# ).execute()
+# Steps.replace(
+# id=1,
+# name="TEST_LEAK_TEST",
+# type="leak",
+# spec={
+# "pre_filling_time": 5,
+# "pre_filling_pressure": 1000,
+# "filling_time": 5,
+# "settling_time": 10,
+# "settling_pressure_min_percent": 50,
+# "settling_pressure_max_percent": 50,
+# "test_time": 10,
+# "test_pressure_min_delta": 500,
+# "test_pressure": 1000,
+# "test_pressure_max_delta": 500,
+# "flush_time": 2,
+# "flush_pressure": 5,
+# },
+# description="TEST_DESCRIPTION",
+# archived=False,
+# ).execute()
+# Steps.replace(
+# id=2,
+# name="TEST_VISION_TEST",
+# type="vision",
+# spec={
+# "recipe": "1.ini",
+# },
+# description="TEST_DESCRIPTION VISION_RECIPE: 1",
+# archived=False,
+# ).execute()
# register test recipe
Recipes.replace(
id=0,
name="TEST",
client="TEST_CLIENT",
part_number="TEST_PART_NUMBER",
- spec={"steps": [0, 1, 2, ]},
+ spec={"steps": []},
description="TEST_DESCRIPTION",
archived=False,
).execute()
diff --git a/src/lib/db/models/steps.py b/src/lib/db/models/steps.py
index 7c73d87..3417dc6 100644
--- a/src/lib/db/models/steps.py
+++ b/src/lib/db/models/steps.py
@@ -6,10 +6,10 @@ from .base_model import BaseModel
class Steps(BaseModel):
id = AutoField(primary_key=True, unique=True, null=False)
- name = TextField(null=False)
+ name = TextField(null=True)
type = TextField(null=False)
spec = JSONField(null=False) # keys inside spec must not overlap withthe model
- description = TextField(null=False)
+ description = TextField(null=True)
archived = BooleanField(null=False, default=False)
@classmethod
diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py
index 78a2db4..c831ad7 100755
--- a/src/ui/crud/crud.py
+++ b/src/ui/crud/crud.py
@@ -6,7 +6,7 @@ from datetime import datetime
from lib.db import Crud_DB
from peewee import TextField
-from PyQt5.QtCore import Qt, pyqtSignal
+from PyQt5.QtCore import QObject, Qt, pyqtSignal
from PyQt5.QtWidgets import (QAbstractItemView, QComboBox, QDialog,
QGridLayout, QHeaderView, QLineEdit, QMessageBox,
QPlainTextEdit, QPushButton)
@@ -53,7 +53,7 @@ class Cell:
self.set_readonly(self.readonly)
self.do_autocomplete(self.autocomplete)
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
raise NotImplementedError()
def do_autocomplete(self, autocomplete):
@@ -104,7 +104,7 @@ class Line_Edit_Cell_Widget(QLineEdit, Cell):
super().__init__()
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
self.setReadOnly(readonly)
def connect_modified(self):
@@ -123,7 +123,7 @@ class Combo_Box_Cell_Widget(QComboBox, Cell):
super().__init__()
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
self.setEditable(not readonly)
def do_autocomplete(self, autocomplete):
@@ -151,11 +151,14 @@ class External_Dialog_Cell_Widget(QPushButton, Cell):
super().__init__(u"\u238B modifica")
Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
self.dialog.setWindowTitle(self.field_alias)
- self.clicked.connect(self.dialog.show)
+ self.clicked.connect(self.show_dialog)
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
self.editor.setReadOnly(readonly)
+ def show_dialog(self):
+ self.dialog.show()
+
def connect_modified(self):
self.editor.textChanged.connect(self.check_modified)
@@ -175,24 +178,31 @@ class Json_External_Dialog_Cell_Widget(External_Dialog_Cell_Widget):
class Json_External_Dialog_Editor_Cell_Widget(QPushButton, Cell):
- def __init__(self, editor_widget_instance, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
- if not isinstance(editor_widget_instance, Editor):
- raise AssertionError(f"editor_widget_instance {editor_widget_instance!r} must be a subclass of {Editor!r}")
- self.editor = editor_widget_instance
+ def __init__(self, editor_widget_class, *args, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None, **kwargs):
+ if not issubclass(editor_widget_class, Editor):
+ raise AssertionError(f"editor_widget_class {editor_widget_class!r} must be a subclass of {Editor!r}")
+ self.editor = editor_widget_class(*args, cell_widget=self, **kwargs)
+ super().__init__(u"\u238B modifica")
+ Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
self.dialog = Dialog()
self.dialog.setAttribute(Qt.WA_DeleteOnClose, on=False)
self.dialog.setCentralWidget(self.editor)
- super().__init__(u"\u238B modifica")
- Cell.__init__(self, readonly=readonly, autocomplete=autocomplete, field_name=field_name, field_alias=field_alias, field=field, row_number=row_number, crud=crud)
self.dialog.setWindowTitle(self.field_alias)
- self.clicked.connect(self.dialog.show)
+ self.clicked.connect(self.show_dialog)
+ if hasattr(self.editor, "init"):
+ self.editor.init()
- def set_readonly(self, readonly):
- self.editor.set_readonly(readonly)
+ def set_readonly(self, readonly=True):
+ self.editor.set_readonly(readonly=readonly)
def do_autocomplete(self, autocomplete):
self.editor.do_autocomplete(autocomplete)
+ def show_dialog(self):
+ if hasattr(self.editor, "showing_dialog"):
+ self.editor.showing_dialog()
+ self.dialog.show()
+
def connect_modified(self):
self.editor.connect_modified(self.check_modified)
@@ -412,6 +422,8 @@ class Crud(Widget):
for fn, cn in self.select_index.items():
readonly = self.readonly is None or self.readonly is True or (self.readonly is not False and fn in self.readonly)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=self)
+ w.set_readonly(readonly=w.readonly)
+ w.do_autocomplete(w.autocomplete)
w.modified.connect(self.set_modified)
if fn in r:
w._render(data=r[fn], row_number=rn, crud=self)
@@ -434,6 +446,8 @@ class Crud(Widget):
for fn, cn in self.select_index.items():
readonly = self.readonly is None or self.readonly is True or (self.readonly is not False and fn in self.readonly)
w = self.widget_classes.get(fn, self.default_widget_class)(readonly=readonly, autocomplete=self.autocomplete.get(fn, None), field_name=fn, field_alias=self.fields_aliases[fn], field=self.db.table_model._meta.fields.get(fn, None), row_number=rn, crud=self)
+ w.set_readonly(readonly=w.readonly)
+ w.do_autocomplete(w.autocomplete)
w.modified.connect(self.set_modified)
self.db_tw.setCellWidget(rn, cn, w)
self.db_tw.scrollToBottom()
diff --git a/src/ui/editor/editor.py b/src/ui/editor/editor.py
index 2cf9d30..38973f8 100644
--- a/src/ui/editor/editor.py
+++ b/src/ui/editor/editor.py
@@ -6,16 +6,19 @@ from ui.widget import Widget
class Editor(Widget):
- def __init__(self):
+ def __init__(self, cell_widget=None):
super().__init__()
+ self.cell_widget = cell_widget
self.spec = {}
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
for w in self.spec.values():
if isinstance(w, QComboBox):
w.setDisabled(readonly)
elif isinstance(w, QListWidget):
w.setDisabled(readonly)
+ elif isinstance(w, QCheckBox):
+ w.setDisabled(readonly)
elif isinstance(w, QObject):
w.setReadOnly(readonly)
diff --git a/src/ui/imgs/print.png b/src/ui/imgs/print.png
new file mode 100644
index 0000000..52b2a72
Binary files /dev/null and b/src/ui/imgs/print.png differ
diff --git a/src/ui/leak_step_editor/leak_step_editor.py b/src/ui/leak_step_editor/leak_step_editor.py
index a88a14c..0ae64d5 100644
--- a/src/ui/leak_step_editor/leak_step_editor.py
+++ b/src/ui/leak_step_editor/leak_step_editor.py
@@ -2,8 +2,8 @@ from ui.editor import Editor
class Leak_Step_Editor(Editor):
- def __init__(self):
- super().__init__()
+ def __init__(self, cell_widget=None):
+ super().__init__(cell_widget=cell_widget)
self.spec.update({
# pre-filling
"pre_filling_time": self.pre_filling_time_sb,
diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py
index 266f9af..1226ae8 100755
--- a/src/ui/recipe_selection/recipe_selection.py
+++ b/src/ui/recipe_selection/recipe_selection.py
@@ -49,7 +49,7 @@ class Recipe_Selection(Widget):
autocomplete={
"archived": False,
},
- widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_And_Step_Editor(), *args, **kwargs), },
+ widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_And_Step_Editor, *args, **kwargs), },
)
replace_widget(self, "crud_w", self.crud)
self.crud_modified = None
diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py
index 5c9f9a8..6610b64 100644
--- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py
+++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py
@@ -1,136 +1,139 @@
+from lib.db import Steps
+from playhouse.shortcuts import model_to_dict
from ui.editor import Editor
from ui.helpers import replace_widget
+from ui.leak_step_editor import Leak_Step_Editor
+from ui.vision_step_editor import Vision_Step_Editor
class Recipe_Spec_And_Step_Editor(Editor):
- def __init__(self):
- super().__init__()
- # self.spec.update({
- # "barcode_editor": self.barcode_editor_w,
- # "leak_editor_1": self.leak_editor_1_w,
- # "leak_editor_2": self.leak_editor_2_w,
- # "vision_editor": self.vision_editor_w,
- # "print_editor": self.print_editor_w,
- # "barcode_enabled": self.barcode_enabled_cb,
- # "leak_enabled_1": self.leak_enabled_1_cb,
- # "leak_eabled_2": self.leak_eabled_2_cb,
- # "vision_enabled": self.vision_enabled_cb,
- # "vision_enabled": self.vision_enabled_cb,
- # "print_enabled_cb": self.print_enabled_cb,
- # })
- # replace_widget(self, "barcode_editor_w", _Editor())
- # replace_widget(self, "leak_editor_1_w", _Editor())
- # replace_widget(self, "leak_editor_2_w", _Editor())
- # replace_widget(self, "vision_editor_w", _Editor())
- # replace_widget(self, "print_editor_w", _Editor())
- #
- # def do_autocomplete(self, autocomplete):
- # if autocomplete is None:
- # return
- # for k, v in autocomplete.items():
- # w = self.spec[k]
- # if isinstance(w, QCheckBox):
- # w.setChecked(bool(v))
- # elif isinstance(w, QComboBox):
- # # while w.count() > 0:
- # # w.removeItem(0)
- # # w.clear()
- # w.addItems(list(map(str, v)))
- # elif isinstance(w, QDoubleSpinBox):
- # w.setValue(float(v))
- # elif isinstance(w, QLineEdit):
- # w.setText(str(v))
- # elif isinstance(w, QListWidget):
- # # while w.count() > 0:
- # # w.takeItem(0)
- # # w.clear()
- # w.addItems(list(map(str, v)))
- # elif isinstance(w, QRadioButton):
- # w.setChecked(bool(v))
- # elif isinstance(w, QSpinBox):
- # w.setValue(int(v))
- # elif isinstance(w, QPlainTextEdit):
- # w.setPlainText(str(v))
- # elif isinstance(w, QObject):
- # raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
- # else:
- # # ignore default values
- # pass
- #
+ def __init__(self, cell_widget=None):
+ super().__init__(cell_widget=cell_widget)
+ self.map = {
+ "barcodes": {
+ "type": "barcodes",
+ "enable": self.barcode_enabled_cb,
+ "widget": "barcode_editor_w",
+ # "editor": _Editor,
+ },
+ "leak_1": {
+ "type": "leak",
+ "enable": self.leak_enabled_1_cb,
+ "widget": "leak_editor_1_w",
+ "editor": Leak_Step_Editor(),
+ },
+ "leak_2": {
+ "type": "leak",
+ "enable": self.leak_eabled_2_cb,
+ "widget": "leak_editor_2_w",
+ "editor": Leak_Step_Editor(),
+ },
+ "vision": {
+ "type": "vision",
+ "enable": self.vision_enabled_cb,
+ "widget": "vision_editor_w",
+ "editor": Vision_Step_Editor(),
+ },
+ "print": {
+ "type": "print",
+ "enable": self.print_enabled_cb,
+ "widget": "print_editor_w",
+ # "editor": _Editor,
+ },
+ }
+ if len(self.map) > 1024:
+ raise NotImplementedError("self.map must contain at most 1024 steps")
+ self.spec.update({editor_name: map["enable"] for editor_name, map in self.map.items()})
+ for editor_name, map in self.map.items():
+ editor = map.get("editor", None)
+ if editor is not None:
+ replace_widget(self, map["widget"], editor)
+ self.save_steps_b.clicked.connect(self.save_steps)
+ self.reset_steps_b.clicked.connect(self.reset_steps)
+ self.recipe_id = None
+ self.step_editors_autocomplete = {}
+
+ def set_readonly(self, readonly=True):
+ super().set_readonly(readonly=readonly)
+ for editor_name, map in self.map.items():
+ editor = map.get("editor", None)
+ if editor is not None:
+ editor.set_readonly(readonly=readonly)
+ self.save_steps_b.setDisabled(readonly)
+
+ def do_autocomplete(self, autocomplete):
+ if autocomplete is None:
+ return
+ self.step_editors_autocomplete = autocomplete.pop("step_editors", None)
+ super().do_autocomplete(autocomplete)
+ if self.step_editors_autocomplete is not None:
+ for editor_name, map in self.map.items():
+ editor = map.get("editor", None)
+ if editor is not None:
+ editor.do_autocomplete(self.step_editors_autocomplete.get(editor_name, None))
+
+ def init(self):
+ self.recipe_id = self.cell_widget.crud.data_index[self.cell_widget.row_number - 1] # - 1 because row_number starts from 1 (filters line)
+ self.get_steps()
+
+ def showing_dialog(self):
+ self.reset_steps()
+
# def connect_modified(self, check_modified):
- # for k, w in self.spec.items():
- # if isinstance(w, QCheckBox):
- # w.toggled.connect(check_modified)
- # elif isinstance(w, QComboBox):
- # w.currentTextChanged.connect(check_modified)
- # elif isinstance(w, QDoubleSpinBox):
- # w.valueChanged.connect(check_modified)
- # elif isinstance(w, QLineEdit):
- # w.textChanged.connect(check_modified)
- # elif isinstance(w, QListWidget):
- # w.currentItemChanged.connect(check_modified)
- # elif isinstance(w, QRadioButton):
- # w.toggled.connect(check_modified)
- # elif isinstance(w, QSpinBox):
- # w.valueChanged.connect(check_modified)
- # elif isinstance(w, QPlainTextEdit):
- # w.textChanged.connect(check_modified)
- # elif isinstance(w, QObject):
- # raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
- # else:
- # # ignore default values
- # pass
- #
- # def render(self, data, field_name=None, row_number=None, crud=None):
- # for k, v in data.items():
- # if k not in self.spec:
- # continue
- # w = self.spec[k]
- # if isinstance(w, QCheckBox):
- # w.setChecked(bool(v))
- # elif isinstance(w, QComboBox):
- # w.setCurrentText(str(v))
- # elif isinstance(w, QDoubleSpinBox):
- # w.setValue(float(v))
- # elif isinstance(w, QLineEdit):
- # w.setText(str(v))
- # elif isinstance(w, QListWidget):
- # w.clear()
- # w.addItems(list(map(str, v)))
- # elif isinstance(w, QRadioButton):
- # w.setChecked(bool(v))
- # elif isinstance(w, QSpinBox):
- # w.setValue(int(v))
- # elif isinstance(w, QPlainTextEdit):
- # w.setPlainText(str(v))
- # elif isinstance(w, QObject):
- # raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
- # else:
- # # ignore default values
- # pass
- #
- # def parse(self, row_number=None, crud=None):
- # ret = {}
- # for k, w in self.spec.items():
- # if isinstance(w, QCheckBox):
- # ret[k] = w.isChecked()
- # elif isinstance(w, QComboBox):
- # ret[k] = w.currentText()
- # elif isinstance(w, QDoubleSpinBox):
- # ret[k] = w.value()
- # elif isinstance(w, QLineEdit):
- # ret[k] = w.text()
- # elif isinstance(w, QListWidget):
- # ret[k] = [w.item(i).data(0) for i in range(w.count())]
- # elif isinstance(w, QRadioButton):
- # ret[k] = w.isChecked()
- # elif isinstance(w, QSpinBox):
- # ret[k] = w.value()
- # elif isinstance(w, QPlainTextEdit):
- # ret[k] = w.toPlainText()
- # elif isinstance(w, QObject):
- # raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
- # else:
- # # pass through default values
- # ret[k] = w
- # return ret
+ # super().connect_modified(check_modified)
+ # # for map in self.map.values():
+ # # editor = map.get("editor", None)
+ # # if editor is not None:
+ # # editor.connect_modified(self.check_modified)
+
+ def render(self, data, field_name=None, row_number=None, crud=None):
+ super().render(data, field_name=field_name, row_number=row_number, crud=crud)
+ steps = set(data.get("steps", set()))
+ for map in self.map.values():
+ map["enable"].setChecked(map["step"]["id"] in steps)
+
+ def parse(self, row_number=None, crud=None):
+ ret = super().parse(row_number=row_number, crud=crud)
+ ret["steps"] = []
+ for map in self.map.values():
+ if map["enable"].isChecked():
+ ret["steps"].append(map["step"]["id"])
+ return ret
+
+ @staticmethod
+ def get_step_id(recipe_id, step_n):
+ return recipe_id * 1024 + step_n
+
+ def get_steps(self):
+ for n, [editor_name, map] in enumerate(self.map.items()):
+ id = self.get_step_id(self.recipe_id, n)
+ try:
+ step = model_to_dict(Steps.get_by_id(id))
+ except Steps.DoesNotExist:
+ step = {
+ "id": id,
+ "type": map["type"],
+ "spec": {},
+ }
+ map["step"] = step
+
+ def render_steps(self):
+ for n, [editor_name, map] in enumerate(self.map.items()):
+ editor = map.get("editor", None)
+ step = map["step"]
+ if editor is not None:
+ editor.render(step["spec"])
+
+ def reset_steps(self):
+ self.get_steps()
+ self.render_steps()
+
+ def save_steps(self):
+ steps = []
+ for map in self.map.values():
+ editor = map.get("editor", None)
+ if editor is not None:
+ map["step"]["spec"] = editor.parse()
+ steps.append(map["step"])
+ Steps.replace_many(steps).execute()
+ self.reset_steps()
diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui
index 2710a3f..30efe43 100644
--- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui
+++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.ui
@@ -6,15 +6,31 @@
0
0
- 247
- 145
+ 330
+ 163
Recipe Spec And Step Editor
- -
+
-
+
+
+ Salva configurasione
+Fasi di Test
+
+
+
+ -
+
+
+ Resetta configurazione
+Fasi di Test
+
+
+
+ -
0
@@ -236,13 +252,6 @@
- -
-
-
- Salva
-
-
-
diff --git a/src/ui/recipe_spec_editor/recipe_spec_editor.py b/src/ui/recipe_spec_editor/recipe_spec_editor.py
index 3f6291d..6a14dad 100644
--- a/src/ui/recipe_spec_editor/recipe_spec_editor.py
+++ b/src/ui/recipe_spec_editor/recipe_spec_editor.py
@@ -3,15 +3,15 @@ from ui.editor import Editor
class Recipe_Spec_Editor(Editor):
- def __init__(self):
- super().__init__()
+ def __init__(self, cell_widget=None):
+ super().__init__(cell_widget=cell_widget)
self.spec.update({
"steps": self.steps_lw,
})
self.steps_lw.setDragDropMode(QAbstractItemView.InternalMove)
- def set_readonly(self, readonly):
- super().set_readonly(readonly)
+ def set_readonly(self, readonly=True):
+ super().set_readonly(readonly=readonly)
self.steps_lw.setDisabled(readonly)
self.remove_step_b.setDisabled(readonly)
self.steps_available_lw.setDisabled(readonly)
diff --git a/src/ui/recipes_management/recipes_management.py b/src/ui/recipes_management/recipes_management.py
index 1452cd8..c0b1b3f 100644
--- a/src/ui/recipes_management/recipes_management.py
+++ b/src/ui/recipes_management/recipes_management.py
@@ -24,6 +24,6 @@ class Recipes_Management(Widget):
autocomplete={
"archived": False,
},
- widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_Editor(), *args, **kwargs), },
+ widget_classes={"spec": lambda *args, **kwargs: Json_External_Dialog_Editor_Cell_Widget(Recipe_Spec_Editor, *args, **kwargs), },
)
self.layout().addWidget(self.crud, 0, 0, -1, -1)
diff --git a/src/ui/steps_management/steps_management.py b/src/ui/steps_management/steps_management.py
index 486b251..4a5735a 100644
--- a/src/ui/steps_management/steps_management.py
+++ b/src/ui/steps_management/steps_management.py
@@ -1,11 +1,8 @@
from glob import iglob
from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit,
- QPlainTextEdit, QPushButton, QRadioButton,
- QSpinBox)
-from ui.crud import (Cell, Combo_Box_Cell_Widget, Crud,
- Json_External_Dialog_Editor_Cell_Widget)
+from PyQt5.QtWidgets import QPushButton
+from ui.crud import Cell, Combo_Box_Cell_Widget, Crud
from ui.dialog import Dialog
from ui.leak_step_editor import Leak_Step_Editor
from ui.vision_step_editor import Vision_Step_Editor
@@ -15,8 +12,8 @@ from ui.widget import Widget
class Step_Spec_JEDECW(QPushButton, Cell):
def __init__(self, readonly=True, autocomplete=None, field_name=None, field_alias=None, field=None, row_number=None, crud=None):
self.editors = {
- "vision": Vision_Step_Editor(),
- "leak": Leak_Step_Editor(),
+ "vision": Vision_Step_Editor(cell_widget=self),
+ "leak": Leak_Step_Editor(cell_widget=self),
}
self.editor = None
self.editor_type = None
@@ -36,9 +33,9 @@ class Step_Spec_JEDECW(QPushButton, Cell):
self.dialog.setCentralWidget(self.editor)
self.dialog.adjustSize()
- def set_readonly(self, readonly):
+ def set_readonly(self, readonly=True):
for editor in self.editors.values():
- editor.set_readonly(readonly)
+ editor.set_readonly(readonly=readonly)
def do_autocomplete(self, autocomplete):
for editor_type, editor in self.editors.items():
diff --git a/src/ui/test/test.py b/src/ui/test/test.py
index 4d23191..297d699 100755
--- a/src/ui/test/test.py
+++ b/src/ui/test/test.py
@@ -38,11 +38,12 @@ class Test(Widget):
self.cycle_available_steps = {
# "assembly_1": Test_Assembly(self.select_step_img("assembly_1"), u"INSERIRE SENSORE"),
"autotest": Test_Assembly(None, u"ESEGUIRE PROCEDURA DI AUTOTEST", Test_Autotest()),
+ "barcodes": Test_Assembly(None, u"SCANSIONARE IL SERIALE DEL PEZZO DA COLLAUDARE", Test_Barcodes()),
"done": Test_Assembly(self.select_step_img("success"), u"COLLAUDO COMPLETATO - RIMUOVERE IL SENSORE"),
"emergency": Test_Assembly(self.select_step_img("reset_emergency"), u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\""),
"fail": Test_Assembly(self.select_step_img("fail"), u"CICLO INTERROTTO - RIMUOVERE IL SENSORE"),
"leak": Test_Assembly(None, u"ESECUZIONE TEST IN CORSO - ATTENDERE", Test_Leak(components=self.components, recipe=self.recipe, step=self.step)),
- "barcodes": Test_Assembly(None, u"SCANSIONARE IL SERIALE DEL PEZZO DA COLLAUDARE", Test_Barcodes()),
+ "print": Test_Assembly(self.select_step_img("print"), u"STAMPA ETICHETTA IN CORSO"),
"select_recipe": Test_Assembly(None, u"SELEZIONARE IL CODICE DA COLLAUDARE", Recipe_Selection()),
"vision": Test_Assembly(None, u"ESEGUIRE PROCEDURA DI AUTOTEST", Test_Vision(components=self.components, recipe=self.recipe, step=self.step)),
"wait": Test_Assembly(self.select_step_img("wait"), u"ATTENDERE - PAUSA INTER CICLO"),
@@ -58,7 +59,8 @@ class Test(Widget):
# else:
self.autotest_period = None
# INIT TEST DATA
- self.data = {}
+ self.data = {"ok": True, "overridden": False}
+ self.archived = None
# INIT PIECES COUNTER ([pieces_ok, pieces_failed])
self.pieces = [0, 0]
# CONNECT CYCLE CONTROLS
@@ -149,7 +151,8 @@ class Test(Widget):
self.step = Steps(type="select_recipe")
self.cycle_index = -1
# RESET TEST DATA
- self.data = {}
+ self.data = {"ok": True, "overridden": False}
+ self.archived = None
elif action == "fail":
self.log.info(f"cycle next: action: {action!r}")
# COUNT FAIL
@@ -158,7 +161,8 @@ class Test(Widget):
self.step = Steps(type="fail")
self.cycle_index = -1
# RESET TEST DATA
- self.data = {}
+ self.data = {"ok": True, "overridden": False}
+ self.archived = None
elif action is not None:
raise NotImplementedError(f"cycle next: action {action!r} is not a valid action")
# if action did not set the next cycle step
@@ -180,6 +184,7 @@ class Test(Widget):
self.step = self.cycle_steps[self.cycle_index]
else:
self.cycle_index = -1
+ self.archived = None
self.step = Steps(type=None)
# enable/disable cycle controls
self.change_recipe_b.setEnabled(self.recipe is not None)
@@ -192,14 +197,18 @@ class Test(Widget):
self.log.info(f"cycle next: next cycle step: {self.step!r}")
# INIT TEST DATA IF STARTING CYCLE LOOP
if self.cycle_index == 0:
- self.data = {}
+ self.data = {"ok": True, "overridden": False}
+ self.archived = None
w = self.cycle_available_steps[self.step.type]
if hasattr(w, "start"):
w.start(recipe=self.recipe, step=self.cycle_steps[self.cycle_index])
if w is not current_w:
self.setCentralWidget(w)
if self.step.type == "done":
- self.done()
+ self.archived = self.done()
+ self.next_timer.start(2000)
+ elif self.step.type == "print":
+ self.print(self.archived)
self.next_timer.start(2000)
elif self.step.type == "fail":
self.next_timer.start(2000)
@@ -213,7 +222,17 @@ class Test(Widget):
if self.recipe is None:
self.cycle_steps = None
else:
- self.cycle_steps = [Steps(type="barcodes")] + self.recipe.get_steps() + [Steps(type="done"), Steps(type="wait")]
+ steps = self.recipe.get_steps()
+ print_found = False
+ for i, step in enumerate(steps):
+ if step.type == "print":
+ steps.insert(i, Steps(type="done"))
+ print_found = True
+ break
+ if not print_found:
+ steps.append(Steps(type="done"))
+ steps.append(Steps(type="wait"))
+ self.cycle_steps = steps
# UPDATE RECIPE DISPLAY
if self.recipe is not None:
self.recipe_l.setText(self.recipe.name)
@@ -233,24 +252,30 @@ class Test(Widget):
if "leak" not in self.data:
self.data["leak"] = []
self.data["leak"].append(leak)
- self.data["overridden"] = self.data.get("overridden", False) or leak.get("overridden", False)
- self.data["ok"] = self.data.get("ok", True) and leak.get("ok", False)
+ self.data["overridden"] = self.data["overridden"] or leak.get("overridden", False)
+ self.data["ok"] = self.data["ok"] and leak.get("ok", False)
self.next()
def set_vision(self, vision=None):
if "vision" not in self.data:
self.data["vision"] = []
self.data["vision"].append(vision)
- self.data["overridden"] = self.data.get("overridden", False) or vision.get("overridden", False)
- self.data["ok"] = self.data.get("ok", True) and vision.get("ok", False)
+ self.data["overridden"] = self.data["overridden"] or vision.get("overridden", False)
+ self.data["ok"] = self.data["ok"] and vision.get("ok", False)
self.next()
def done(self, ok=True):
self.log.info("cycle done")
archived = Archive.archive(self.recipe, self.data, ok and self.data["ok"], overridden=self.data["overridden"])
self.log.info(f"cycle archived locally: {archived!r}")
+ # COUNT OK
+ self.pieces[0] += 1
+ return archived
+
+ def print(self, archived=None):
+ self.log.info("cycle print")
# LABEL PRINT
- self.components["label_printer"].print_label("EtichettaR5", context={
+ context = {
"DATAMATRIX": str(self.data.get("barcodes", {}).get("serial", "")),
"DATAMATRIX_TEXT": str(self.data.get("barcodes", {}).get("serial", "-")),
"PIECE_NUM": str(self.data.get("barcodes", {}).get("serial", "-")),
@@ -267,9 +292,8 @@ class Test(Widget):
"TTEST": "-",
"MAXLEAK": "-",
"PTESTMIN": "-",
- "RESULT_L1": str(self.data.get("leak", [{}])[0].get("results", {}).get("result", "FAIL")),
- "RESULT_L2": str(self.data.get("leak", [{}])[1].get("results", {}).get("result", "FAIL")),
- })
- self.log.info(f"cycle printed: {archived!r}")
- # COUNT OK
- self.pieces[0] += 1
+ "RESULT_L1": str(self.data.get("leak", [{}, {}])[0].get("results", {}).get("result", "FAIL")),
+ "RESULT_L2": str(self.data.get("leak", [{}, {}])[1].get("results", {}).get("result", "FAIL")),
+ }
+ self.components["label_printer"].print_label("EtichettaR5", context=context)
+ self.log.info(f"cycle printed: {context!r}")
diff --git a/src/ui/vision_step_editor/vision_step_editor.py b/src/ui/vision_step_editor/vision_step_editor.py
index 20c2c9e..5dbaf32 100644
--- a/src/ui/vision_step_editor/vision_step_editor.py
+++ b/src/ui/vision_step_editor/vision_step_editor.py
@@ -2,8 +2,8 @@ from ui.editor import Editor
class Vision_Step_Editor(Editor):
- def __init__(self):
- super().__init__()
+ def __init__(self, cell_widget=None):
+ super().__init__(cell_widget=cell_widget)
self.spec.update({
"recipe": self.vision_recipe_cb,
})