Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cdd06f2

Browse files
committedFeb 5, 2025
Converted lifecycle list view to a table.
1 parent b20030c commit cdd06f2

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
@@ -531,6 +531,7 @@ def save_plan(plan: Plan) -> QgsFeature:
531531
document.plan_id = plan_id
532532
save_document(document)
533533

534+
# Save lifecycles
534535
for lifecycle in plan.lifecycles:
535536
lifecycle.plan_id = feature["id"]
536537
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()

‎arho_feature_template/gui/dialogs/plan_attribute_form.ui

+68-69
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
<rect>
6262
<x>0</x>
6363
<y>0</y>
64-
<width>218</width>
65-
<height>306</height>
64+
<width>829</width>
65+
<height>569</height>
6666
</rect>
6767
</property>
6868
<layout class="QVBoxLayout" name="verticalLayout_4">
@@ -128,16 +128,6 @@
128128
</property>
129129
</widget>
130130
</item>
131-
<item row="3" column="0">
132-
<widget class="QLabel" name="label_5">
133-
<property name="text">
134-
<string>Organisaatio*:</string>
135-
</property>
136-
</widget>
137-
</item>
138-
<item row="3" column="1">
139-
<widget class="CodeComboBox" name="organisation_combo_box"/>
140-
</item>
141131
<item row="4" column="0">
142132
<widget class="QLabel" name="tyyppiLabel">
143133
<property name="text">
@@ -155,6 +145,33 @@
155145
</property>
156146
</widget>
157147
</item>
148+
<item row="5" column="0">
149+
<widget class="QLabel" name="elinkaarenTilaLabel">
150+
<property name="text">
151+
<string>Elinkaaren tila*:</string>
152+
</property>
153+
<property name="buddy">
154+
<cstring>lifecycle_status_combo_box</cstring>
155+
</property>
156+
</widget>
157+
</item>
158+
<item row="5" column="1">
159+
<widget class="CodeComboBox" name="lifecycle_status_combo_box">
160+
<property name="toolTip">
161+
<string>Kaavan elinkaaren tila</string>
162+
</property>
163+
</widget>
164+
</item>
165+
<item row="3" column="0">
166+
<widget class="QLabel" name="label_5">
167+
<property name="text">
168+
<string>Organisaatio*:</string>
169+
</property>
170+
</widget>
171+
</item>
172+
<item row="3" column="1">
173+
<widget class="CodeComboBox" name="organisation_combo_box"/>
174+
</item>
158175
</layout>
159176
</item>
160177
<item>
@@ -321,91 +338,72 @@
321338
</item>
322339
</layout>
323340
</widget>
324-
<widget class="QWidget" name="lifecycle_status_tab">
341+
<widget class="QWidget" name="lifecycles_tab">
325342
<attribute name="title">
326343
<string>Elinkaaret</string>
327344
</attribute>
328345
<widget class="QGroupBox" name="groupBox_2">
329346
<property name="geometry">
330347
<rect>
331-
<x>10</x>
348+
<x>0</x>
332349
<y>10</y>
333-
<width>831</width>
334-
<height>571</height>
350+
<width>801</width>
351+
<height>561</height>
335352
</rect>
336353
</property>
337354
<property name="title">
338-
<string>Elinkaarien tilat</string>
355+
<string>Elinkaaret</string>
339356
</property>
340357
<widget class="QWidget" name="verticalLayoutWidget">
341358
<property name="geometry">
342359
<rect>
343-
<x>10</x>
360+
<x>30</x>
344361
<y>30</y>
345-
<width>301</width>
346-
<height>531</height>
362+
<width>631</width>
363+
<height>461</height>
347364
</rect>
348365
</property>
349-
<layout class="QVBoxLayout" name="verticalLayout_8">
366+
<layout class="QVBoxLayout" name="verticalLayout_5">
350367
<item>
351-
<layout class="QFormLayout" name="formLayout_3">
352-
<item row="0" column="0">
353-
<widget class="QLabel" name="label_9">
354-
<property name="text">
355-
<string>Elinkaaren tila:</string>
356-
</property>
357-
</widget>
358-
</item>
359-
<item row="0" column="1">
360-
<widget class="CodeComboBox" name="lifecycle_status_combo_box">
361-
<property name="toolTip">
362-
<string>Kaavan elinkaaren tila</string>
363-
</property>
364-
</widget>
365-
</item>
366-
<item row="1" column="0">
367-
<widget class="QLabel" name="label_10">
368-
<property name="text">
369-
<string>Alkupäivämäärä:</string>
370-
</property>
371-
</widget>
372-
</item>
373-
<item row="1" column="1">
374-
<widget class="QDateEdit" name="lifecycle_start_date"/>
375-
</item>
376-
<item row="2" column="0">
377-
<widget class="QLabel" name="label_11">
378-
<property name="text">
379-
<string>Loppupäivämäärä:</string>
380-
</property>
381-
</widget>
382-
</item>
383-
<item row="2" column="1">
384-
<widget class="QDateEdit" name="lifecycle_end_date"/>
385-
</item>
386-
<item row="3" column="0">
387-
<widget class="QPushButton" name="add_lifecycle_button">
388-
<property name="text">
389-
<string>Tallenna elinkaari</string>
390-
</property>
391-
</widget>
392-
</item>
393-
</layout>
368+
<widget class="QTableWidget" name="lifecycle_table"/>
394369
</item>
395370
</layout>
396371
</widget>
397372
<widget class="QWidget" name="verticalLayoutWidget_2">
398373
<property name="geometry">
399374
<rect>
400-
<x>330</x>
375+
<x>689</x>
401376
<y>30</y>
402-
<width>491</width>
403-
<height>531</height>
377+
<width>81</width>
378+
<height>461</height>
404379
</rect>
405380
</property>
406-
<layout class="QVBoxLayout" name="verticalLayout_9">
381+
<layout class="QVBoxLayout" name="verticalLayout_8">
407382
<item>
408-
<widget class="QListView" name="lifecycle_list"/>
383+
<widget class="QPushButton" name="delete_lifecycle_button">
384+
<property name="sizePolicy">
385+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
386+
<horstretch>0</horstretch>
387+
<verstretch>0</verstretch>
388+
</sizepolicy>
389+
</property>
390+
<property name="text">
391+
<string>Poista</string>
392+
</property>
393+
</widget>
394+
</item>
395+
<item>
396+
<widget class="QPushButton" name="add_lifecycle_button">
397+
<property name="sizePolicy">
398+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
399+
<horstretch>0</horstretch>
400+
<verstretch>0</verstretch>
401+
</sizepolicy>
402+
</property>
403+
<property name="text">
404+
<string>Lisää</string>
405+
</property>
406+
</widget>
409407
</item>
410408
</layout>
411409
</widget>
@@ -449,6 +447,7 @@
449447
<tabstop>name_line_edit</tabstop>
450448
<tabstop>description_text_edit</tabstop>
451449
<tabstop>plan_type_combo_box</tabstop>
450+
<tabstop>lifecycle_status_combo_box</tabstop>
452451
<tabstop>mGroupBox</tabstop>
453452
<tabstop>record_number_line_edit</tabstop>
454453
<tabstop>producers_plan_identifier_line_edit</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.