Skip to content

Commit 8e0ab38

Browse files
nmaarnioLKajan
authored andcommitted
disable UI add/edit/delete UI elements when plan is locked
Disabled only minimum number of elements. Forms can still be opened and inspected, but form save buttons are disabled.
1 parent a27365e commit 8e0ab38

9 files changed

Lines changed: 77 additions & 27 deletions

File tree

arho_feature_template/core/plan_manager.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
lock_plan_layers,
9595
plan_layers_temporarily_unlocked,
9696
unlock_plan_layers,
97-
update_lock_status_if_needed,
9897
)
9998
from arho_feature_template.utils.localization_utils import get_localized_text
10099
from arho_feature_template.utils.misc_utils import (
@@ -152,13 +151,16 @@ class PlanManager(QObject):
152151
project_loaded = pyqtSignal()
153152
project_cleared = pyqtSignal()
154153
plan_identifier_set = pyqtSignal(str)
154+
plan_lock_status_changed = pyqtSignal(bool) # True = now locked, false = now unlocked
155155

156156
def __init__(self):
157157
super().__init__()
158158
self.json_plan_path = None
159159
self.json_plan_outline_path = None
160160
self.json_plan_matter_path = None
161161

162+
self.plan_locked = False # Change this only through `update_lock_status` method
163+
162164
self.plan_feature_libraries = []
163165
self.regulation_group_libraries = []
164166

@@ -300,7 +302,7 @@ def _initialize_plan_feature_libraries(self):
300302
self.new_feature_dock.initialize_plan_feature_libraries(self.plan_feature_libraries)
301303

302304
def open_manage_plans(self):
303-
dialog = ManagePlans(self.regulation_group_libraries)
305+
dialog = ManagePlans(self.regulation_group_libraries, self)
304306
if dialog.exec():
305307
selected_plan = dialog.selected_plan
306308
# If the active plan was changed, update state
@@ -318,6 +320,20 @@ def open_import_features_dialog(self):
318320
)
319321
self.import_features_form.show()
320322

323+
def update_lock_status(self, plan_model: Plan):
324+
"""If input plan is the active plan, applies locked/unlocked state from the given model."""
325+
if plan_model.id_ == get_active_plan_id():
326+
if plan_model.locked:
327+
lock_plan_layers()
328+
self.plan_locked = True
329+
else:
330+
unlock_plan_layers()
331+
self.plan_locked = False
332+
self.plan_lock_status_changed.emit(plan_model.locked)
333+
334+
self.regulation_groups_dock.update_lock_status(plan_model.locked)
335+
self.new_feature_dock.update_lock_status(plan_model.locked)
336+
321337
@use_wait_cursor
322338
def update_active_plan_regulation_group_library(self):
323339
self.active_plan_regulation_group_library = regulation_group_library_from_active_plan()
@@ -348,7 +364,9 @@ def manage_libraries(self):
348364
self.initialize_libraries()
349365

350366
def _open_regulation_group_form(self, regulation_group: RegulationGroup):
351-
regulation_group_form = PlanRegulationGroupForm(regulation_group, self.active_plan_regulation_group_library)
367+
regulation_group_form = PlanRegulationGroupForm(
368+
regulation_group, self.active_plan_regulation_group_library, not self.plan_locked
369+
)
352370

353371
if regulation_group_form.exec_():
354372
model = regulation_group_form.model
@@ -486,7 +504,7 @@ def edit_plan(self):
486504
if plan_id is not None:
487505
self.update_active_plan_regulation_group_library()
488506

489-
update_lock_status_if_needed(plan_model)
507+
self.update_lock_status(plan_model)
490508

491509
def edit_plan_matter(self):
492510
plan_matter_layer = PlanMatterLayer.get_from_project()
@@ -612,6 +630,7 @@ def _plan_feature_geom_digitized(self, feature: QgsFeature):
612630
self.regulation_group_libraries,
613631
self.plan_feature_libraries,
614632
self.active_plan_regulation_group_library,
633+
not self.plan_locked,
615634
)
616635
if attribute_form.exec_() and save_plan_object(attribute_form.model) is not None:
617636
self.update_active_plan_regulation_group_library()
@@ -627,6 +646,7 @@ def edit_plan_feature(self, feature: QgsFeature, layer_name: str):
627646
self.regulation_group_libraries,
628647
self.plan_feature_libraries,
629648
self.active_plan_regulation_group_library,
649+
not self.plan_locked,
630650
)
631651
if attribute_form.exec_() and save_plan_object(attribute_form.model) is not None:
632652
self.update_active_plan_regulation_group_library()
@@ -700,13 +720,8 @@ def set_active_plan(self, plan_id: str | None) -> None:
700720
else:
701721
layer.show_all_features()
702722

703-
plan_feat = PlanLayer.get_feature_by_id(plan_id)
704-
if plan_feat:
705-
locked = plan_feat["locked"]
706-
if locked:
707-
lock_plan_layers()
708-
else:
709-
unlock_plan_layers()
723+
plan_model = PlanLayer.model_from_feature(PlanLayer.get_feature_by_id(plan_id))
724+
self.update_lock_status(plan_model)
710725
else:
711726
self.plan_unset.emit()
712727
for layer in plan_layers:

arho_feature_template/gui/dialogs/manage_plans.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from arho_feature_template.utils.layer_utils import (
1919
plan_layers_temporarily_unlocked,
2020
temporary_subset,
21-
update_lock_status_if_needed,
2221
)
2322
from arho_feature_template.utils.localization_utils import get_localized_text
2423
from arho_feature_template.utils.misc_utils import (
@@ -31,7 +30,8 @@
3130
if TYPE_CHECKING:
3231
from qgis.gui import QgsFilterLineEdit
3332

34-
from arho_feature_template.core.models import Plan
33+
from arho_feature_template.core.models import Plan, RegulationGroupLibrary
34+
from arho_feature_template.core.plan_manager import PlanManager
3535

3636
ui_path = resources.files(__package__) / "manage_plans.ui"
3737
FormClass, _ = uic.loadUiType(ui_path)
@@ -44,7 +44,7 @@ class ManagePlans(QDialog, FormClass): # type: ignore
4444
UNLOCKED_ICON: QIcon = QgsApplication.getThemeIcon("unlocked.svg")
4545

4646
@use_wait_cursor
47-
def __init__(self, regulation_group_libraries):
47+
def __init__(self, regulation_group_libraries: list[RegulationGroupLibrary], plan_manager_ref: PlanManager):
4848
super().__init__()
4949
self.setupUi(self)
5050

@@ -57,6 +57,7 @@ def __init__(self, regulation_group_libraries):
5757

5858
# INIT
5959
self.regulation_group_libraries = regulation_group_libraries
60+
self.plan_manager_ref = plan_manager_ref
6061
self.selected_plan = None
6162
self.plan_layer = PlanLayer.get_from_project()
6263
self.previously_in_edit_mode = self.plan_layer.isEditable()
@@ -157,7 +158,7 @@ def _on_row_double_clicked(self, item: QTableWidgetItem):
157158
):
158159
save_plan(edited_plan)
159160

160-
update_lock_status_if_needed(edited_plan)
161+
self.plan_manager_ref.update_lock_status(edited_plan)
161162
self._update_plan_row(item.row(), edited_plan)
162163

163164
def _on_new_plan_button_clicked(self):

arho_feature_template/gui/dialogs/plan_feature_form.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def __init__(
4040
regulation_group_libraries: list[RegulationGroupLibrary],
4141
plan_feature_libraries: list[PlanFeatureLibrary] | None = None,
4242
active_plan_regulation_groups_library: RegulationGroupLibrary | None = None,
43+
enable_save: bool = True, # noqa: FBT001, FBT002
4344
template_form: bool = False, # noqa: FBT001, FBT002
4445
):
4546
super().__init__()
@@ -104,6 +105,11 @@ def __init__(
104105

105106
self.button_box.accepted.connect(self._on_ok_clicked)
106107

108+
if not enable_save:
109+
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
110+
tooltip = "Kaavasuunnitelma on lukittu, kaavakohdetta ei voi muokata."
111+
self.button_box.button(QDialogButtonBox.Ok).setToolTip(tooltip)
112+
107113
def _init_save_to_library_button(self) -> None:
108114
if self.plan_feature_libraries:
109115
self.plan_object_menu = QMenu()

arho_feature_template/gui/dialogs/plan_regulation_group_form.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def __init__(
5252
self,
5353
regulation_group: RegulationGroup,
5454
active_plan_regulation_groups_library: RegulationGroupLibrary | None,
55+
enable_save: bool = True, # noqa: FBT001, FBT002
5556
):
5657
super().__init__()
5758
self.setupUi(self)
@@ -154,6 +155,11 @@ def __init__(
154155
self.regulation_group_info_tab.layout().insertLayout(1, layout)
155156
self.setWindowTitle("Muokkaa kaavamääräysryhmää")
156157

158+
if not enable_save:
159+
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
160+
tooltip = "Kaavasuunnitelma on lukittu, kaavamääräysryhmää ei voi muokata."
161+
self.button_box.button(QDialogButtonBox.Ok).setToolTip(tooltip)
162+
157163
def initialize_regulation_library(self):
158164
"""Initializes the tree menu for regulations."""
159165
# Map ID to widget to be able to assign parent widgets

arho_feature_template/gui/docks/new_feature_dock.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ def __init__(self, parent=None) -> None:
5555

5656
TemplateManager.signal_manager.feature_object_added_to_library.connect(self.update_template_list)
5757

58+
def update_lock_status(self, locked: bool): # noqa: FBT001
59+
self.new_feature_grid.setEnabled(not locked)
60+
if locked:
61+
self.new_feature_grid.setToolTip("Kaavasuunnitelma on lukittu, kaavakohteita ei voi lisätä.")
62+
else:
63+
self.new_feature_grid.setToolTip("")
64+
5865
def initialize_plan_feature_libraries(self, plan_feature_libraries: list[PlanFeatureLibrary]):
5966
self.plan_feature_libraries = plan_feature_libraries
6067
self.library_selection.clear()

arho_feature_template/gui/docks/plan_features_dock.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ def _open_form(self, index: QModelIndex):
309309
plan_feature_libraries=self.plan_manager_ref.plan_feature_libraries,
310310
regulation_group_libraries=self.plan_manager_ref.regulation_group_libraries,
311311
active_plan_regulation_groups_library=self.plan_manager_ref.active_plan_regulation_group_library,
312+
enable_save=not self.plan_manager_ref.plan_locked,
312313
)
313314
if form.exec():
314315
updated_plan_feature_model = form.model

arho_feature_template/gui/docks/regulation_groups_dock.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ def __init__(self, parent=None):
123123

124124
self.selection_model = self.table.selectionModel()
125125

126+
self.plan_locked = False
127+
126128
def initialize(self):
127129
# Connect feat remove signals for each plan object layer so the linked plan object counts
128130
# stay updated
@@ -153,6 +155,21 @@ def _connect_signals(self):
153155
self.add_selected_action.triggered.connect(self.on_add_selected_btn_clicked)
154156
self.filter_line.textChanged.connect(self._filter_table)
155157

158+
def update_lock_status(self, locked: bool): # noqa: FBT001
159+
self.plan_locked = locked
160+
self.new_btn.setEnabled(not locked)
161+
self.delete_btn.setEnabled(not locked)
162+
self.modify_selected_features_btn.setEnabled(not locked)
163+
164+
if locked:
165+
self.new_btn.setToolTip("Kaavasuunnitelma on lukittu, kaavamääräysryhmiä ei voi lisätä.")
166+
self.delete_btn.setToolTip("Kaavasuunnitelma on lukittu, kaavamääräysryhmiä ei voi poistaa.")
167+
self.modify_selected_features_btn.setToolTip("Kaavasuunnitelma on lukittu, kaavakohteita ei voi muokata.")
168+
else:
169+
self.new_btn.setToolTip("")
170+
self.delete_btn.setToolTip("")
171+
self.modify_selected_features_btn.setToolTip("")
172+
156173
def _filter_table(self):
157174
# Set text filter
158175
search_text = self.filter_line.text()
@@ -341,11 +358,13 @@ def _open_context_menu(self, pos: QPoint):
341358
self._on_highlight_plan_objects,
342359
)
343360
menu.addSeparator()
344-
menu.addAction(
361+
del_action = menu.addAction(
345362
QgsApplication.getThemeIcon("mActionDeleteSelected.svg"),
346363
"Poista kaavamääräysryhmä" if nr_of_selected_groups == 1 else "Poista valitut kaavamääräysryhmät",
347364
self.on_delete_btn_clicked,
348365
)
366+
del_action.setEnabled(not self.plan_locked)
367+
349368
menu.exec_(self.table.viewport().mapToGlobal(pos))
350369

351370
def _on_select_plan_objects(self):

arho_feature_template/plugin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ def initGui(self) -> None: # noqa N802
475475
self.plan_manager.plan_unset.connect(self.on_active_plan_unset)
476476
self.plan_manager.project_loaded.connect(self.on_project_loaded)
477477
self.plan_manager.project_cleared.connect(self.on_project_cleared)
478+
self.plan_manager.plan_lock_status_changed.connect(self.on_plan_lock_status_changed)
478479
if SettingsManager.get_data_exchange_layer_enabled():
479480
self.plan_manager.plan_identifier_set.connect(self.update_ryhti_buttons)
480481
self.plan_manager.plan_identifier_set.connect(self.validation_dock.on_permanent_identifier_set)
@@ -575,6 +576,9 @@ def on_project_cleared(self):
575576
for action in self.plan_matter_depending_actions:
576577
action.setEnabled(False)
577578

579+
def on_plan_lock_status_changed(self, locked: bool): # noqa: FBT001
580+
self.import_features_action.setEnabled(not locked)
581+
578582
def unload(self) -> None:
579583
"""Removes the plugin menu item and icon from QGIS GUI."""
580584
# Handle signals

arho_feature_template/utils/layer_utils.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
from qgis.core import QgsVectorLayer
44

5-
from arho_feature_template.core.models import Plan
65
from arho_feature_template.project.layers.plan_layers import PlanLayer, plan_layers
7-
from arho_feature_template.utils.misc_utils import get_active_plan_id
86

97

108
def lock_plan_layers():
9+
"""NOTE: Should be used from PlanManager if not temporary, otherwise PlanManager.plan_locked gets out of sync."""
1110
for layer in plan_layers:
1211
vlayer = layer.get_from_project()
1312
if vlayer is None:
@@ -20,6 +19,7 @@ def lock_plan_layers():
2019

2120

2221
def unlock_plan_layers(start_editing_plan_layer: bool = True): # noqa: FBT001, FBT002
22+
"""NOTE: Should be used from PlanManager if not temporary, otherwise PlanManager.plan_locked gets out of sync."""
2323
for layer in plan_layers:
2424
vlayer = layer.get_from_project()
2525
if vlayer is None:
@@ -31,15 +31,6 @@ def unlock_plan_layers(start_editing_plan_layer: bool = True): # noqa: FBT001,
3131
PlanLayer.get_from_project().startEditing()
3232

3333

34-
def update_lock_status_if_needed(edited_plan_model: Plan):
35-
"""If edited plan is the active plan, applies locked/unlocked state from the given model."""
36-
if edited_plan_model.id_ == get_active_plan_id():
37-
if edited_plan_model.locked:
38-
lock_plan_layers()
39-
else:
40-
unlock_plan_layers()
41-
42-
4334
@contextmanager
4435
def plan_layers_temporarily_unlocked():
4536
"""Ensures layers are editable and returns to locked afterwards if they were locked before."""

0 commit comments

Comments
 (0)