Skip to content

Commit 7a82825

Browse files
Mtk112nmaarnio
authored andcommitted
Converted lifecycle list view to a table.
1 parent 1ebb154 commit 7a82825

File tree

3 files changed

+210
-114
lines changed

3 files changed

+210
-114
lines changed

arho_feature_template/core/plan_manager.py

+1
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ def save_plan(plan: Plan) -> QgsFeature:
528528
document.plan_id = plan_id
529529
save_document(document)
530530

531+
# Save lifecycles
531532
for lifecycle in plan.lifecycles:
532533
lifecycle.plan_id = feature["id"]
533534
save_lifecycle(lifecycle)

arho_feature_template/gui/dialogs/plan_attribute_form.py

+141-45
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55

66
from qgis.core import QgsApplication
77
from qgis.PyQt import uic
8-
from qgis.PyQt.QtCore import Qt
8+
from qgis.PyQt.QtCore import QDate, Qt
99
from qgis.PyQt.QtGui import QStandardItem, QStandardItemModel
1010
from qgis.PyQt.QtWidgets import (
1111
QComboBox,
1212
QDateEdit,
1313
QDialog,
1414
QDialogButtonBox,
1515
QLineEdit,
16-
QListView,
1716
QPushButton,
1817
QSizePolicy,
1918
QSpacerItem,
19+
QStyledItemDelegate,
20+
QTableWidget,
2021
QTextEdit,
22+
QTreeWidgetItem,
23+
QWidget,
2124
)
2225

2326
from arho_feature_template.core.models import Document, Plan, RegulationGroup, RegulationGroupLibrary
@@ -26,6 +29,9 @@
2629
from arho_feature_template.gui.components.general_regulation_group_widget import GeneralRegulationGroupWidget
2730
from arho_feature_template.gui.components.plan_document_widget import DocumentWidget
2831
from arho_feature_template.core.models import LifeCycle, Plan, RegulationGroup, RegulationGroupLibrary
32+
from arho_feature_template.gui.components.code_combobox import CodeComboBox
33+
from arho_feature_template.gui.components.plan_regulation_group_widget import RegulationGroupWidget
34+
from arho_feature_template.gui.components.tree_with_search_widget import TreeWithSearchWidget
2935
from arho_feature_template.project.layers.code_layers import (
3036
LifeCycleStatusLayer,
3137
OrganisationLayer,
@@ -36,19 +42,63 @@
3642
if TYPE_CHECKING:
3743
from qgis.PyQt.QtWidgets import QLineEdit, QPushButton, QTextEdit, QVBoxLayout
3844

39-
from arho_feature_template.gui.components.code_combobox import CodeComboBox, HierarchicalCodeComboBox
45+
from arho_feature_template.gui.components.code_combobox import HierarchicalCodeComboBox
4046

4147
ui_path = resources.files(__package__) / "plan_attribute_form.ui"
4248
FormClass, _ = uic.loadUiType(ui_path)
4349

4450

51+
class LifecycleTableModel(QStandardItemModel):
52+
def __init__(self, status_options, parent=None):
53+
super().__init__(parent)
54+
self.status_options = status_options
55+
56+
def flags(self, index):
57+
if index.column() == 0: # "Elinkaaren tila" - editable combo box
58+
return Qt.ItemIsSelectable | Qt.ItemIsEnabled
59+
60+
if index.column() in (1, 2): # Dates
61+
return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable
62+
return super().flags(index)
63+
64+
65+
class LifecycleDelegate(QStyledItemDelegate):
66+
def create_editor(self, parent, option, index):
67+
if index.column() == 0: # Status column
68+
lifecycle_combo_box = CodeComboBox(parent)
69+
lifecycle_combo_box.populate_from_code_layer(LifeCycleStatusLayer)
70+
return lifecycle_combo_box
71+
if index.column() in (1, 2): # Dates columns
72+
date_edit = QDateEdit(parent)
73+
date_edit.setDisplayFormat("yyyy-MM-dd")
74+
date_edit.setCalendarPopup(True)
75+
return date_edit
76+
return super().createEditor(parent, option, index)
77+
78+
def set_editor_data(self, editor, index):
79+
if isinstance(editor, CodeComboBox) and index.column() == 0:
80+
value = index.data(Qt.EditRole)
81+
if value is not None:
82+
editor.set_value(value)
83+
elif isinstance(editor, QDateEdit) and index.column() in (1, 2):
84+
value = index.data(Qt.EditRole)
85+
if value:
86+
editor.setDate(QDate.fromString(value, "yyyy-MM-dd"))
87+
88+
def set_model_data(self, editor, model, index):
89+
if isinstance(editor, CodeComboBox) and index.column() == 0:
90+
model.setData(index, editor.value(), Qt.EditRole)
91+
if isinstance(editor, QDateEdit) and index.column() in (1, 2):
92+
model.setData(index, editor.date().toString("yyyy-MM-dd"), Qt.EditRole)
93+
94+
4595
class PlanAttributeForm(QDialog, FormClass): # type: ignore
4696
permanent_identifier_line_edit: QLineEdit
4797
name_line_edit: QLineEdit
4898
organisation_combo_box: CodeComboBox
4999
description_text_edit: QTextEdit
50100
plan_type_combo_box: HierarchicalCodeComboBox
51-
# lifecycle_status_combo_box: CodeComboBox
101+
lifecycle_status_combo_box: CodeComboBox
52102
record_number_line_edit: QLineEdit
53103
producers_plan_identifier_line_edit: QLineEdit
54104
matter_management_identifier_line_edit: QLineEdit
@@ -62,11 +112,9 @@ class PlanAttributeForm(QDialog, FormClass): # type: ignore
62112
documents_layout: QVBoxLayout
63113
add_document_btn: QPushButton
64114

65-
lifecycle_status_combo_box: CodeComboBox
66-
lifecycle_start_date: QDateEdit
67-
lifecycle_end_date: QDateEdit
68-
add_lifecycle_button: QPushButton
69-
lifecycle_list: QListView
115+
lifecycle_table: QTableWidget
116+
add_lifecycle: QPushButton
117+
delete_lifecycle: QPushButton
70118

71119
button_box: QDialogButtonBox
72120

@@ -124,10 +172,13 @@ def __init__(self, plan: Plan, _regulation_group_libraries: list[RegulationGroup
124172
self.add_document_btn.clicked.connect(self.add_new_document)
125173
self.add_document_btn.setIcon(QgsApplication.getThemeIcon("mActionAdd.svg"))
126174

127-
# Lifecycles
128-
self.lifecycle_model = QStandardItemModel()
129-
self.lifecycle_list.setModel(self.lifecycle_model)
130-
self.add_lifecycle_button.clicked.connect(self.save_lifecycle)
175+
# Lifecycle table setup
176+
self.lifecycle_table.setColumnCount(3) # Three columns: Status, Start Date, End Date
177+
self.lifecycle_table.setHorizontalHeaderLabels(["Elinkaaren tila", "Alkupvm", "Loppupvm"])
178+
self.lifecycle_table.setRowCount(0) # No rows initially
179+
180+
self.add_lifecycle_button.clicked.connect(self.add_lifecycle_row)
181+
self.delete_lifecycle_button.clicked.connect(self.delete_lifecycle_row)
131182

132183
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
133184
self.button_box.accepted.connect(self._on_ok_clicked)
@@ -136,6 +187,24 @@ def __init__(self, plan: Plan, _regulation_group_libraries: list[RegulationGroup
136187

137188
def _check_required_fields(self) -> None:
138189
ok_button = self.button_box.button(QDialogButtonBox.Ok)
190+
191+
# Check if all required fields are filled and lifecycle table has at least one valid row
192+
has_valid_lifecycle_row = False
193+
for row in range(self.lifecycle_table.rowCount()):
194+
status_item = self.lifecycle_table.cellWidget(row, 0)
195+
start_date_item = self.lifecycle_table.cellWidget(row, 1)
196+
end_date_item = self.lifecycle_table.cellWidget(row, 2)
197+
198+
if (
199+
status_item
200+
and status_item.value() is not None
201+
and start_date_item
202+
and start_date_item.date()
203+
and (end_date_item and end_date_item.date() or True)
204+
):
205+
has_valid_lifecycle_row = True
206+
break
207+
139208
if (
140209
self.name_line_edit.text() != ""
141210
and self.plan_type_combo_box.value() is not None
@@ -144,6 +213,7 @@ def _check_required_fields(self) -> None:
144213
and all(document_widget.is_ok() for document_widget in self.document_widgets)
145214
# and self.lifecycle_status_combo_box.value() is not None
146215
# and self.lifecycle_model.rowCount() > 0
216+
and has_valid_lifecycle_row # Ensure there's at least one valid lifecycle row
147217
):
148218
ok_button.setEnabled(True)
149219
else:
@@ -209,45 +279,72 @@ def delete_document(self, document_widget: DocumentWidget):
209279

210280
# ---
211281

212-
def save_lifecycle(self):
213-
# Get values from the widgets
214-
status = self.lifecycle_status_combo_box.currentText() # Get the selected text from the combo box
215-
start_date = self.lifecycle_start_date.date().toString("yyyy-MM-dd") # Format the QDate as a string
216-
end_date = self.lifecycle_end_date.date().toString("yyyy-MM-dd") if self.lifecycle_end_date.date() else None
282+
def add_lifecycle_row(self):
283+
row_position = self.lifecycle_table.rowCount()
284+
self.lifecycle_table.insertRow(row_position)
285+
286+
status = CodeComboBox(self)
287+
status.populate_from_code_layer(LifeCycleStatusLayer)
288+
self.lifecycle_table.setCellWidget(row_position, 0, status)
217289

218-
# Format the lifecycle entry
219-
date_range = f"{start_date} - {end_date}" if end_date else start_date
220-
lifecycle_entry = f"{status} | {date_range}"
290+
start_date_edit = QDateEdit(self)
291+
start_date_edit.setDisplayFormat("yyyy-MM-dd")
292+
start_date_edit.setCalendarPopup(True)
293+
self.lifecycle_table.setCellWidget(row_position, 1, start_date_edit)
221294

222-
# Add to the model
223-
item = QStandardItem(lifecycle_entry)
224-
item.setData(self.lifecycle_status_combo_box.value(), Qt.UserRole + 1)
225-
self.lifecycle_model.appendRow(item)
295+
end_date_edit = QDateEdit(self)
296+
end_date_edit.setDisplayFormat("yyyy-MM-dd")
297+
end_date_edit.setCalendarPopup(True)
298+
self.lifecycle_table.setCellWidget(row_position, 2, end_date_edit)
299+
300+
self.lifecycle_table.resizeRowsToContents()
301+
self.lifecycle_table.resizeColumnsToContents()
302+
303+
def delete_lifecycle_row(self):
304+
selected_rows = self.lifecycle_table.selectionModel().selectedRows()
305+
306+
if selected_rows:
307+
row_position = selected_rows[0].row()
308+
self.lifecycle_table.removeRow(row_position)
309+
self._check_required_fields()
310+
311+
def save_lifecycle(self):
312+
for row in range(self.lifecycle_table.rowCount()):
313+
status = self.lifecycle_table.cellWidget(row, 0)
314+
start_date_item = self.lifecycle_table.cellWidget(row, 1)
315+
end_date_item = self.lifecycle_table.cellWidget(row, 2)
316+
317+
if status and start_date_item:
318+
status = status.value() if status.value() is not None else ""
319+
start_date = start_date_item.date().toString("yyyy-MM-dd") if start_date_item.date() else ""
320+
end_date = end_date_item.date().toString("yyyy-MM-dd") if end_date_item.date() else None
321+
322+
lifecycle_model_item = QStandardItem(status)
323+
lifecycle_model_item.setData(status.value(), Qt.UserRole + 1)
324+
start_date_model_item = QStandardItem(start_date)
325+
end_date_model_item = QStandardItem(end_date if end_date else "")
326+
327+
self.lifecycle_table.model().appendRow(
328+
[lifecycle_model_item, start_date_model_item, end_date_model_item]
329+
)
226330

227-
# Optionally, check required fields again
228331
self._check_required_fields()
229332

230333
def into_lifecycle_model(self) -> list[LifeCycle]:
231334
lifecycles = []
232335

233-
for row in range(self.lifecycle_model.rowCount()):
234-
item = self.lifecycle_model.item(row)
235-
if item:
236-
lifecycle_entry = item.text()
237-
parts = lifecycle_entry.split(" | ")
238-
date_range = parts[1]
239-
date_parts = date_range.split(" - ")
240-
start_date = date_parts[0]
241-
end_date = date_parts[1] if len(date_parts) > 1 else None # End date is optional
242-
243-
# Add the lifecycle to the list
244-
lifecycles.append(
245-
LifeCycle(
246-
status_id=item.data(Qt.UserRole + 1),
247-
starting_at=start_date,
248-
ending_at=end_date,
249-
)
250-
)
336+
# Iterate through the rows in lifecycle_table
337+
for row in range(self.lifecycle_table.rowCount()):
338+
status_item = self.lifecycle_table.cellWidget(row, 0)
339+
start_date_item = self.lifecycle_table.cellWidget(row, 1)
340+
end_date_item = self.lifecycle_table.cellWidget(row, 2)
341+
342+
if status_item and start_date_item:
343+
status_id = status_item.value()
344+
start_date = start_date_item.date().toString("yyyy-MM-dd") if start_date_item.date() else ""
345+
end_date = end_date_item.date().toString("yyyy-MM-dd") if end_date_item.date() else None
346+
347+
lifecycles.append(LifeCycle(status_id=status_id, starting_at=start_date, ending_at=end_date))
251348

252349
return lifecycles
253350

@@ -271,5 +368,4 @@ def into_model(self) -> Plan:
271368

272369
def _on_ok_clicked(self):
273370
self.model = self.into_model()
274-
# self.lifecycle_model = self.into_lifecycle_model()
275371
self.accept()

0 commit comments

Comments
 (0)