5
5
6
6
from qgis .core import QgsApplication
7
7
from qgis .PyQt import uic
8
- from qgis .PyQt .QtCore import Qt
8
+ from qgis .PyQt .QtCore import QDate , Qt
9
9
from qgis .PyQt .QtGui import QStandardItem , QStandardItemModel
10
10
from qgis .PyQt .QtWidgets import (
11
11
QComboBox ,
12
12
QDateEdit ,
13
13
QDialog ,
14
14
QDialogButtonBox ,
15
15
QLineEdit ,
16
- QListView ,
17
16
QPushButton ,
18
17
QSizePolicy ,
19
18
QSpacerItem ,
19
+ QStyledItemDelegate ,
20
+ QTableWidget ,
20
21
QTextEdit ,
22
+ QTreeWidgetItem ,
23
+ QWidget ,
21
24
)
22
25
23
26
from arho_feature_template .core .models import Document , Plan , RegulationGroup , RegulationGroupLibrary
26
29
from arho_feature_template .gui .components .general_regulation_group_widget import GeneralRegulationGroupWidget
27
30
from arho_feature_template .gui .components .plan_document_widget import DocumentWidget
28
31
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
29
35
from arho_feature_template .project .layers .code_layers import (
30
36
LifeCycleStatusLayer ,
31
37
OrganisationLayer ,
36
42
if TYPE_CHECKING :
37
43
from qgis .PyQt .QtWidgets import QLineEdit , QPushButton , QTextEdit , QVBoxLayout
38
44
39
- from arho_feature_template .gui .components .code_combobox import CodeComboBox , HierarchicalCodeComboBox
45
+ from arho_feature_template .gui .components .code_combobox import HierarchicalCodeComboBox
40
46
41
47
ui_path = resources .files (__package__ ) / "plan_attribute_form.ui"
42
48
FormClass , _ = uic .loadUiType (ui_path )
43
49
44
50
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
+
45
95
class PlanAttributeForm (QDialog , FormClass ): # type: ignore
46
96
permanent_identifier_line_edit : QLineEdit
47
97
name_line_edit : QLineEdit
48
98
organisation_combo_box : CodeComboBox
49
99
description_text_edit : QTextEdit
50
100
plan_type_combo_box : HierarchicalCodeComboBox
51
- # lifecycle_status_combo_box: CodeComboBox
101
+ lifecycle_status_combo_box : CodeComboBox
52
102
record_number_line_edit : QLineEdit
53
103
producers_plan_identifier_line_edit : QLineEdit
54
104
matter_management_identifier_line_edit : QLineEdit
@@ -62,11 +112,9 @@ class PlanAttributeForm(QDialog, FormClass): # type: ignore
62
112
documents_layout : QVBoxLayout
63
113
add_document_btn : QPushButton
64
114
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
70
118
71
119
button_box : QDialogButtonBox
72
120
@@ -124,10 +172,13 @@ def __init__(self, plan: Plan, _regulation_group_libraries: list[RegulationGroup
124
172
self .add_document_btn .clicked .connect (self .add_new_document )
125
173
self .add_document_btn .setIcon (QgsApplication .getThemeIcon ("mActionAdd.svg" ))
126
174
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 )
131
182
132
183
self .button_box .button (QDialogButtonBox .Ok ).setEnabled (False )
133
184
self .button_box .accepted .connect (self ._on_ok_clicked )
@@ -136,6 +187,24 @@ def __init__(self, plan: Plan, _regulation_group_libraries: list[RegulationGroup
136
187
137
188
def _check_required_fields (self ) -> None :
138
189
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
+
139
208
if (
140
209
self .name_line_edit .text () != ""
141
210
and self .plan_type_combo_box .value () is not None
@@ -144,6 +213,7 @@ def _check_required_fields(self) -> None:
144
213
and all (document_widget .is_ok () for document_widget in self .document_widgets )
145
214
# and self.lifecycle_status_combo_box.value() is not None
146
215
# and self.lifecycle_model.rowCount() > 0
216
+ and has_valid_lifecycle_row # Ensure there's at least one valid lifecycle row
147
217
):
148
218
ok_button .setEnabled (True )
149
219
else :
@@ -209,45 +279,72 @@ def delete_document(self, document_widget: DocumentWidget):
209
279
210
280
# ---
211
281
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 )
217
289
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 )
221
294
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
+ )
226
330
227
- # Optionally, check required fields again
228
331
self ._check_required_fields ()
229
332
230
333
def into_lifecycle_model (self ) -> list [LifeCycle ]:
231
334
lifecycles = []
232
335
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 ))
251
348
252
349
return lifecycles
253
350
@@ -271,5 +368,4 @@ def into_model(self) -> Plan:
271
368
272
369
def _on_ok_clicked (self ):
273
370
self .model = self .into_model ()
274
- # self.lifecycle_model = self.into_lifecycle_model()
275
371
self .accept ()
0 commit comments