Skip to content
Snippets Groups Projects

Implement ProtocolTemplateEditor

Merged Samuel GAIST requested to merge 210_implement_protocoltemplate_editor into v2
@@ -23,11 +23,165 @@
# #
###############################################################################
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QComboBox
from PyQt5.QtWidgets import QFormLayout
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QHeaderView
from PyQt5.QtWidgets import QInputDialog
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QScrollArea
from PyQt5.QtWidgets import QStyledItemDelegate
from PyQt5.QtWidgets import QTableWidget
from PyQt5.QtWidgets import QTableWidgetItem
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
from ..utils import frozen
from ..backend.assetmodel import AssetType
from ..backend.assetmodel import AssetModel
from .editor import AbstractAssetEditor
class DataformatDelegate(QStyledItemDelegate):
def __init__(self, dataformat_model, parent=None):
super(DataformatDelegate, self).__init__(parent)
self.dataformat_model = dataformat_model
def createEditor(self, parent, options, index):
combobox = QComboBox(parent)
combobox.setModel(self.dataformat_model)
return combobox
class SetWidget(QWidget):
dataChanged = pyqtSignal()
deletionRequested = pyqtSignal()
def __init__(self, dataformat_model, parent=None):
super(SetWidget, self).__init__(parent)
self.dataformat_model = dataformat_model
delegate = DataformatDelegate(self.dataformat_model)
self.delete_button = QPushButton(self.tr("-"))
self.delete_button.setFixedSize(30, 30)
delete_layout = QHBoxLayout()
delete_layout.addStretch(1)
delete_layout.addWidget(self.delete_button)
self.name_lineedit = QLineEdit()
self.template_lineedit = QLineEdit()
self.view_lineedit = QLineEdit()
self.outputs_tablewidget = QTableWidget()
self.outputs_tablewidget.verticalHeader().setVisible(False)
self.outputs_tablewidget.setColumnCount(2)
self.outputs_tablewidget.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch
)
self.outputs_tablewidget.setHorizontalHeaderLabels(
[self.tr("Name"), self.tr("Type")]
)
self.outputs_tablewidget.setItemDelegateForColumn(1, delegate)
self.outputs_tablewidget.setMinimumHeight(200)
self.add_button = QPushButton(self.tr("+"))
self.add_button.setFixedSize(30, 30)
self.remove_button = QPushButton(self.tr("-"))
self.remove_button.setFixedSize(30, 30)
self.remove_button.setEnabled(False)
button_layout = QHBoxLayout()
button_layout.addStretch(1)
button_layout.addWidget(self.add_button)
button_layout.addWidget(self.remove_button)
outputs_layout = QVBoxLayout()
outputs_layout.addWidget(self.outputs_tablewidget, 2)
outputs_layout.addLayout(button_layout)
self.form_layout = QFormLayout()
self.form_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
self.form_layout.addRow(self.tr("Name"), self.name_lineedit)
self.form_layout.addRow(self.tr("Outputs"), outputs_layout)
self.name_lineedit.textChanged.connect(self.dataChanged)
self.outputs_tablewidget.cellChanged.connect(self.dataChanged)
self.outputs_tablewidget.itemSelectionChanged.connect(
self.__on_item_selection_changed
)
layout = QVBoxLayout(self)
layout.addLayout(delete_layout)
layout.addLayout(self.form_layout)
self.delete_button.clicked.connect(self.deletionRequested)
self.add_button.clicked.connect(self.__add_output)
self.remove_button.clicked.connect(self.__remove_outputs)
def __add_output(self):
new_row = self.outputs_tablewidget.rowCount()
self.outputs_tablewidget.setRowCount(new_row + 1)
name_item = QTableWidgetItem(self.tr("Change_me"))
type_item = QTableWidgetItem(self.dataformat_model.index(0).data())
self.outputs_tablewidget.setItem(new_row, 0, name_item)
self.outputs_tablewidget.setItem(new_row, 1, type_item)
self.outputs_tablewidget.scrollToItem(type_item)
self.dataChanged.emit()
def __remove_outputs(self):
selected_items = self.outputs_tablewidget.selectedItems()
rows = []
while selected_items:
item = selected_items.pop()
rows.append(item.row())
rows = set(sorted(rows))
while rows:
row = rows.pop()
self.outputs_tablewidget.removeRow(row)
self.dataChanged.emit()
def __on_item_selection_changed(self):
self.remove_button.setEnabled(bool(self.outputs_tablewidget.selectedItems()))
def dump(self):
json_data = {"name": self.name_lineedit.text()}
outputs = {}
for i in range(self.outputs_tablewidget.rowCount()):
outputs[
self.outputs_tablewidget.item(i, 0).text()
] = self.outputs_tablewidget.item(i, 1).text()
json_data["outputs"] = outputs
return json_data
def load(self, json_data):
self.name_lineedit.setText(json_data["name"])
outputs = json_data["outputs"]
self.outputs_tablewidget.setRowCount(len(outputs))
row = 0
for name, type_ in json_data["outputs"].items():
name_item = QTableWidgetItem(name)
type_item = QTableWidgetItem(type_)
self.outputs_tablewidget.setItem(row, 0, name_item)
self.outputs_tablewidget.setItem(row, 1, type_item)
row += 1
def name(self):
"""Name of the set"""
return self.name_lineedit.text()
@frozen
class ProtocolTemplateEditor(AbstractAssetEditor):
def __init__(self, parent=None):
@@ -35,10 +189,112 @@ class ProtocolTemplateEditor(AbstractAssetEditor):
self.setObjectName(self.__class__.__name__)
self.set_title(self.tr("Protocol Template"))
self.set_widgets = []
self.dataformat_model = AssetModel()
self.dataformat_model.asset_type = AssetType.DATAFORMAT
container_widget = QWidget()
self.container_widget_layout = QVBoxLayout(container_widget)
self.container_widget_layout.addStretch(1)
self.scroll_area = QScrollArea()
self.scroll_area.setWidget(container_widget)
self.scroll_area.setWidgetResizable(True)
self.add_set_button = QPushButton(self.tr("+"))
self.add_set_button.setFixedSize(30, 30)
self.layout().addWidget(self.scroll_area, 1)
self.layout().addWidget(self.add_set_button, 1)
self.add_set_button.clicked.connect(self.__add_set)
def set_prefix_root(self, prefix):
"""Re-impl"""
self.dataformat_model.prefix_path = prefix
def __on_remove_requested(self):
"""Remove the widget clicked"""
self.__remove_widget(self.sender())
def __remove_widget(self, widget):
"""Removes the widget that which signal triggered this slot"""
self.container_widget_layout.removeWidget(widget)
self.set_widgets.pop(self.set_widgets.index(widget))
widget.setParent(None)
self.dataChanged.emit()
def __add_set(self):
"""Add a new set
:param content dict: dictionary to load
"""
set_names = [widget.name() for widget in self.set_widgets]
while True:
name, ok_pressed = QInputDialog.getText(
self, self.tr("Set name"), self.tr("Name")
)
if not ok_pressed:
break
if ok_pressed and name not in set_names:
self.__load_json(
{
"sets": [
{
"name": name,
"outputs": {
"Change_me": self.dataformat_model.index(0).data()
},
}
]
}
)
self.dataChanged.emit()
break
def __show_latest_set(self):
"""Ensure that the latest set is visible"""
if self.set_widgets:
self.scroll_area.ensureWidgetVisible(self.set_widgets[-1], 10, 10)
def __load_json(self, json_object):
"""Load the json object passed as parameter"""
for set_ in json_object["sets"]:
set_widget = SetWidget(self.dataformat_model)
set_widget.load(set_)
self.set_widgets.append(set_widget)
index = self.container_widget_layout.count() - 1
self.container_widget_layout.insertWidget(index, set_widget, 2)
set_widget.dataChanged.connect(self.dataChanged)
set_widget.deletionRequested.connect(self.__on_remove_requested)
if self.set_widgets:
QTimer.singleShot(100, self.__show_latest_set)
def _load_json(self, json_object):
"""Load the json object passed as parameter"""
pass
self.blockSignals(True)
while self.set_widgets:
widget = self.set_widgets[0]
self.__remove_widget(widget)
self.blockSignals(False)
self.__load_json(json_object)
def _dump_json(self):
"""Returns the json representation of the asset"""
return {}
return {
"schema_version": 1,
"sets": [widget.dump() for widget in self.set_widgets],
}
Loading