Files
Submissions-App/src/submissions/frontend/widgets/equipment_usage.py
2024-07-25 08:41:44 -05:00

196 lines
7.5 KiB
Python

'''
Creates forms that the user can enter equipment info into.
'''
from pprint import pformat
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (QDialog, QComboBox, QCheckBox,
QLabel, QWidget, QVBoxLayout, QDialogButtonBox, QGridLayout)
from backend.db.models import Equipment, BasicSubmission, Process
from backend.validators.pydant import PydEquipment, PydEquipmentRole, PydTips
import logging
from typing import List
logger = logging.getLogger(f"submissions.{__name__}")
class EquipmentUsage(QDialog):
def __init__(self, parent, submission: BasicSubmission):
super().__init__(parent)
self.submission = submission
self.setWindowTitle(f"Equipment Checklist - {submission.rsl_plate_num}")
self.used_equipment = self.submission.get_used_equipment()
self.kit = self.submission.extraction_kit
# logger.debug(f"Existing equipment: {self.used_equipment}")
self.opt_equipment = submission.submission_type.get_equipment()
# logger.debug(f"EquipmentRoles: {self.opt_equipment}")
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.populate_form()
def populate_form(self):
"""
Create form widgets
"""
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
label = self.LabelRow(parent=self)
self.layout.addWidget(label)
# logger.debug("Creating widgets for equipment")
for eq in self.opt_equipment:
widg = eq.to_form(parent=self, used=self.used_equipment)
self.layout.addWidget(widg)
widg.update_processes()
self.layout.addWidget(self.buttonBox)
def parse_form(self) -> List[PydEquipment]:
"""
Pull info from all RoleComboBox widgets
Returns:
List[PydEquipment]: All equipment pulled from widgets
"""
output = []
for widget in self.findChildren(QWidget):
match widget:
case RoleComboBox():
if widget.check.isChecked():
output.append(widget.parse_form())
case _:
pass
logger.debug(f"parsed output of Equsage form: {pformat(output)}")
try:
return [item.strip() for item in output if item is not None]
except AttributeError:
return [item for item in output if item is not None]
class LabelRow(QWidget):
def __init__(self, parent) -> None:
super().__init__(parent)
self.layout = QGridLayout()
self.check = QCheckBox()
self.layout.addWidget(self.check, 0, 0)
self.check.stateChanged.connect(self.check_all)
for iii, item in enumerate(["Role", "Equipment", "Process", "Tips"], start=1):
l = QLabel(item)
l.setMaximumWidth(200)
l.setMinimumWidth(200)
self.layout.addWidget(l, 0, iii, alignment=Qt.AlignmentFlag.AlignRight)
self.setLayout(self.layout)
def check_all(self):
"""
Toggles all checkboxes in the form
"""
for object in self.parent().findChildren(QCheckBox):
object.setChecked(self.check.isChecked())
class RoleComboBox(QWidget):
def __init__(self, parent, role: PydEquipmentRole, used: list) -> None:
super().__init__(parent)
# self.layout = QHBoxLayout()
self.layout = QGridLayout()
self.role = role
self.check = QCheckBox()
if role.name in used:
self.check.setChecked(False)
else:
self.check.setChecked(True)
self.check.stateChanged.connect(self.toggle_checked)
self.box = QComboBox()
self.box.setMaximumWidth(200)
self.box.setMinimumWidth(200)
self.box.addItems([item.name for item in role.equipment])
self.box.currentTextChanged.connect(self.update_processes)
self.process = QComboBox()
self.process.setMaximumWidth(200)
self.process.setMinimumWidth(200)
self.process.setEditable(False)
self.process.currentTextChanged.connect(self.update_tips)
self.layout.addWidget(self.check, 0, 0)
label = QLabel(f"{role.name}:")
label.setMinimumWidth(200)
label.setMaximumWidth(200)
label.setAlignment(Qt.AlignmentFlag.AlignLeft)
self.layout.addWidget(label, 0, 1)
self.layout.addWidget(self.box, 0, 2)
self.layout.addWidget(self.process, 0, 3)
self.setLayout(self.layout)
self.toggle_checked()
def update_processes(self):
"""
Changes processes when equipment is changed
"""
equip = self.box.currentText()
# logger.debug(f"Updating equipment: {equip}")
equip2 = [item for item in self.role.equipment if item.name == equip][0]
# logger.debug(f"Using: {equip2}")
self.process.clear()
self.process.addItems([item for item in equip2.processes if item in self.role.processes])
def update_tips(self):
"""
Changes what tips are available when process is changed
"""
process = self.process.currentText().strip()
# logger.debug(f"Checking process: {process} for equipment {self.role.name}")
process = Process.query(name=process)
if process.tip_roles:
for iii, tip_role in enumerate(process.tip_roles):
widget = QComboBox()
tip_choices = [item.name for item in tip_role.instances]
widget.setEditable(False)
widget.addItems(tip_choices)
# logger.debug(f"Tiprole: {tip_role.__dict__}")
widget.setObjectName(f"tips_{tip_role.name}")
widget.setMinimumWidth(200)
widget.setMaximumWidth(200)
self.layout.addWidget(widget, iii, 4)
else:
widget = QLabel("")
widget.setMinimumWidth(200)
widget.setMaximumWidth(200)
self.layout.addWidget(widget, 0, 4)
def parse_form(self) -> PydEquipment | None:
"""
Creates PydEquipment for values in form
Returns:
PydEquipment|None: PydEquipment matching form
"""
eq = Equipment.query(name=self.box.currentText())
tips = [PydTips(name=item.currentText(), role=item.objectName().lstrip("tips").lstrip("_")) for item in
self.findChildren(QComboBox) if item.objectName().startswith("tips")]
logger.debug(tips)
try:
return PydEquipment(
name=eq.name,
processes=[self.process.currentText().strip()],
role=self.role.name,
asset_number=eq.asset_number,
nickname=eq.nickname,
tips=tips
)
except Exception as e:
logger.error(f"Could create PydEquipment due to: {e}")
def toggle_checked(self):
"""
If this equipment is disabled, the input fields will be disabled.
"""
for widget in self.findChildren(QWidget):
match widget:
case QCheckBox():
continue
case _:
if self.check.isChecked():
widget.setEnabled(True)
else:
widget.setEnabled(False)