Skip to content

Commit d073936

Browse files
committed
Merge remote-tracking branch 'origin/release/4.5'
2 parents 97b77a6 + 95d5a47 commit d073936

File tree

8 files changed

+189
-230
lines changed

8 files changed

+189
-230
lines changed

core/shared/psector.py

Lines changed: 31 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -966,31 +966,7 @@ def insert_or_update_new_psector(self, from_tab_change=False):
966966

967967
workcat_id = tools_qt.get_text(self.dlg_plan_psector, 'tab_general_workcat_id')
968968
status_id = tools_qt.get_combo_value(self.dlg_plan_psector, 'tab_general_status')
969-
active = tools_qt.get_widget_value(self.dlg_plan_psector, 'tab_general_active')
970-
971-
# Prevent deactivating or archiving the last active psector
972-
# Only check if THIS psector is currently active
973-
if self.update:
974-
psector_id = tools_qt.get_text(self.dlg_plan_psector, 'tab_general_psector_id')
975-
sql = f"SELECT active FROM plan_psector WHERE psector_id = {psector_id}"
976-
result = tools_db.get_row(sql)
977-
current_active = result[0] if result else False
978-
979-
# Only validate if this psector is currently active
980-
if current_active:
981-
trying_to_archive = status_id in ('5', '6', '7', 5, 6, 7)
982-
trying_to_deactivate = not active
983-
984-
if trying_to_archive or trying_to_deactivate:
985-
sql = "SELECT COUNT(*) FROM plan_psector WHERE active IS TRUE AND status NOT IN ('5', '6', '7')"
986-
result = tools_db.get_row(sql)
987-
active_count = result[0] if result else 0
988-
989-
if active_count <= 1:
990-
msg = "Cannot deactivate or archive the last active psector. At least one psector must remain active."
991-
tools_qgis.show_warning(msg, dialog=self.dlg_plan_psector)
992-
return
993-
969+
994970
# Check if psector status is "Executed" (status_id == 5) and has no workcat_id
995971
if int(status_id) == 5 and workcat_id in (None, 'null', ''):
996972
msg = "Psector '{0}' has no workcat_id value set. Do you want to continue with the default value?"
@@ -1484,41 +1460,6 @@ def refresh_table(self, dialog, widget):
14841460
if str(widget.model().record(row).value('tab_general_psector_id')) != tools_qt.get_text(dialog, 'tab_general_psector_id'):
14851461
widget.hideRow(i)
14861462

1487-
def validate_psector_status_change(self, model: QSqlTableModel, row: int, record: QSqlRecord) -> bool:
1488-
"""
1489-
Validate psector changes in manager table
1490-
Prevents deactivating or archiving the last active psector
1491-
"""
1492-
table_name = model.tableName()
1493-
1494-
# Only validate for main psector table
1495-
if 'v_ui_plan_psector' not in str(table_name):
1496-
return True
1497-
1498-
old_active = model.record(row).value('active')
1499-
new_active = record.value('active')
1500-
new_status = record.value('status')
1501-
1502-
trying_to_deactivate = (old_active and not new_active)
1503-
archived_statuses = ['5', '6', '7', 5, 6, 7,
1504-
'MADE OPERATIONAL (ARCHIVED)', 'COMISSIONED (ARCHIVED)', 'CANCELED (ARCHIVED)']
1505-
trying_to_archive = (str(new_status) in [str(s) for s in archived_statuses] or new_status in archived_statuses)
1506-
1507-
if trying_to_deactivate or trying_to_archive:
1508-
sql = "SELECT COUNT(*) FROM plan_psector WHERE active IS TRUE AND status NOT IN ('5', '6', '7')"
1509-
result = tools_db.get_row(sql)
1510-
active_count = result[0] if result else 0
1511-
1512-
if active_count <= 1:
1513-
msg = "Cannot deactivate or archive the last active psector. At least one psector must remain active."
1514-
dialog = getattr(self, 'dlg_psector_mng', None) or getattr(self, 'dlg_plan_psector', None)
1515-
tools_qgis.show_warning(msg, dialog=dialog)
1516-
model.revertAll()
1517-
model.select()
1518-
return False
1519-
1520-
return True
1521-
15221463
def manage_update_model_relations(self, model: QSqlTableModel, row: int, record: QSqlRecord):
15231464
"""
15241465
Manage update model relations - INSERT if new, UPDATE if exists
@@ -1531,10 +1472,6 @@ def manage_update_model_relations(self, model: QSqlTableModel, row: int, record:
15311472
table_name = model.tableName()
15321473
if not table_name:
15331474
return
1534-
1535-
# Validate psector status changes
1536-
if not self.validate_psector_status_change(model, row, record):
1537-
return
15381475

15391476
# Build column lists and values for UPSERT operation
15401477
columns = []
@@ -1856,7 +1793,6 @@ def set_toggle_active(self, dialog, qtbl_psm):
18561793
msg = "Any record selected"
18571794
tools_qgis.show_warning(msg, dialog=dialog)
18581795
return
1859-
cur_psector = tools_gw.get_config_value('plan_psector_current')
18601796
for i in range(0, len(selected_list)):
18611797
row = selected_list[i].row()
18621798
psector_id = qtbl_psm.model().record(row).value("psector_id")
@@ -1867,31 +1803,9 @@ def set_toggle_active(self, dialog, qtbl_psm):
18671803
msg = f"Cannot set the active state of archived psector {psector_id}. Please unarchive it first."
18681804
tools_qgis.show_warning(msg, dialog=dialog)
18691805
return
1870-
if cur_psector and cur_psector[0] is not None and psector_id == int(cur_psector[0]):
1871-
msg = "The active state of the current psector cannot be changed. Current psector: {0}"
1872-
msg_params = (cur_psector[0],)
1873-
tools_qgis.show_warning(msg, dialog=dialog, msg_params=msg_params)
1874-
return
1875-
# Check if trying to deactivate the last active psector
1876-
if active:
1877-
# Count total active non-archived psectors
1878-
sql_check = "SELECT COUNT(*) FROM plan_psector WHERE active IS TRUE"
1879-
result = tools_db.get_row(sql_check)
1880-
active_count = result[0] if result else 0
1881-
1882-
# If this is the only active psector, block the change
1883-
if active_count <= 1:
1884-
msg = "Cannot deactivate the last active psector. At least one psector must remain active."
1885-
tools_qgis.show_warning(msg, dialog=dialog)
1886-
return
1887-
1806+
18881807
if active:
18891808
sql += f"UPDATE plan_psector SET active = False WHERE psector_id = {psector_id};"
1890-
# Remove from selector
1891-
sql += f"DELETE FROM selector_psector WHERE psector_id = {psector_id} AND cur_user = current_user;"
1892-
msg = f"Psector {psector_id} removed from selector"
1893-
tools_qgis.show_info(msg, dialog=dialog)
1894-
selector_updated = True
18951809
else:
18961810
sql = ("UPDATE config_param_user "
18971811
"SET value = True "
@@ -1941,7 +1855,7 @@ def restore_psector(self, dialog, qtbl_psm):
19411855
json_result = tools_gw.execute_procedure('gw_fct_plan_recover_archived', body)
19421856
if not json_result or 'body' not in json_result or 'data' not in json_result['body']:
19431857
return
1944-
1858+
19451859
# Refresh the table to show updated status
19461860
self._filter_table(dialog, qtbl_psm, dialog.txt_name, dialog.chk_active, dialog.chk_archived, 'v_ui_plan_psector')
19471861

@@ -1960,17 +1874,11 @@ def update_current_psector(self, dialog, qtbl, scenario_type, col_id_name):
19601874
row = selected_list[0].row()
19611875
model = qtbl.model()
19621876
col_id = tools_qt.get_col_index_by_col_name(qtbl, col_id_name)
1963-
col_active = tools_qt.get_col_index_by_col_name(qtbl, 'active')
1877+
col_parent_id = tools_qt.get_col_index_by_col_name(qtbl, 'parent_id')
19641878

19651879
# Access the data using the model's index method
19661880
scenario_id = model.index(row, col_id).data()
1967-
active = model.index(row, col_active).data()
1968-
1969-
# Verify that the selected psector is active
1970-
if not active:
1971-
msg = f"Cannot set psector {scenario_id} as current. It is inactive. Please activate it first."
1972-
tools_qgis.show_warning(msg, dialog=dialog)
1973-
return
1881+
parent_id = model.index(row, col_parent_id).data()
19741882

19751883
# Prepare the JSON body for gw_fct_set_toggle_current
19761884
extras = f'"type": "{scenario_type}", "id": "{scenario_id}"'
@@ -1990,8 +1898,12 @@ def update_current_psector(self, dialog, qtbl, scenario_type, col_id_name):
19901898

19911899
cur_psector = tools_gw.get_config_value('plan_psector_current')
19921900
sql = f"DELETE FROM selector_psector WHERE psector_id = {scenario_id} AND cur_user = current_user; "
1901+
if parent_id and parent_id is not None:
1902+
sql += f"DELETE FROM selector_psector WHERE psector_id = {parent_id} AND cur_user = current_user; "
19931903
if cur_psector and cur_psector[0] is not None:
1994-
sql += f"INSERT INTO selector_psector (psector_id, cur_user) VALUES ({scenario_id}, current_user);"
1904+
sql += f"INSERT INTO selector_psector (psector_id, cur_user) VALUES ({scenario_id}, current_user) ON CONFLICT (psector_id, cur_user) DO NOTHING;"
1905+
if parent_id and parent_id is not None:
1906+
sql += f"INSERT INTO selector_psector (psector_id, cur_user) VALUES ({parent_id}, current_user) ON CONFLICT (psector_id, cur_user) DO NOTHING;"
19951907
tools_db.execute_sql(sql)
19961908

19971909
# Load existing psector
@@ -2037,7 +1949,14 @@ def _toggle_canvas_filter(self):
20371949
Toggles the filter on or off based on checkbox state.
20381950
Saves visibility state, connects/disconnects filter, and updates the table.
20391951
"""
2040-
if self.dlg_psector_mng.chk_filter_canvas.isChecked():
1952+
try:
1953+
is_checked = self.dlg_psector_mng.chk_filter_canvas.isChecked()
1954+
except RuntimeError:
1955+
msg = tools_qt.tr("Please close all 'Psector manager' dialogs and try again")
1956+
tools_qgis.show_warning(msg)
1957+
return
1958+
1959+
if is_checked:
20411960
# Save initial visibility of target layer
20421961
self._save_visibility_state('ve_plan_psector')
20431962

@@ -2346,6 +2265,11 @@ def psector_merge(self):
23462265
tools_qgis.show_warning(msg, dialog=self.dlg_psector_mng)
23472266
return
23482267

2268+
if len(selected_list) == 1:
2269+
msg = "Merge requires at least 2 psectors to be selected"
2270+
tools_qgis.show_info(msg, dialog=self.dlg_psector_mng)
2271+
return
2272+
23492273
for i in range(0, len(selected_list)):
23502274
row = selected_list[i].row()
23512275
archived = self.qtbl_psm.model().record(row).value("archived")
@@ -2545,7 +2469,9 @@ def _check_for_layers(self):
25452469
return all_checked
25462470

25472471
def _manage_tab_feature_buttons(self):
2548-
return
2472+
""" Update rel_feature_type when tab changes to ensure buttons work on all tabs """
2473+
feature_type = tools_gw.get_signal_change_tab(self.dlg_plan_psector, self.excluded_layers)
2474+
self.rel_feature_type = feature_type
25492475

25502476
def _reset_snapping(self):
25512477
tools_qgis.disconnect_snapping(True, self.emit_point, self.vertex_marker)
@@ -2572,14 +2498,14 @@ def _toggle_feature_psector(self, dialog, idx):
25722498
tab_idx = dialog.tab_feature.currentIndex()
25732499
feature_type = dialog.tab_feature.tabText(tab_idx).lower()
25742500
qtbl_feature = dialog.findChild(QTableView, f"tbl_psector_x_{feature_type}")
2575-
2501+
25762502
# Get psector_id from dialog (works for both new and existing psectors)
25772503
selected_psector = tools_qt.get_text(dialog, 'tab_general_psector_id')
25782504
if not selected_psector:
25792505
msg = "Psector ID not found"
25802506
tools_qgis.show_warning(msg, dialog=dialog)
25812507
return
2582-
2508+
25832509
list_tables = {'arc': self.tablename_psector_x_arc, 'node': self.tablename_psector_x_node,
25842510
'connec': self.tablename_psector_x_connec, 'gully': self.tablename_psector_x_gully}
25852511

@@ -2594,7 +2520,7 @@ def _toggle_feature_psector(self, dialog, idx):
25942520
model = qtbl_feature.model()
25952521
for i in range(0, len(selected_list)):
25962522
row = selected_list[i].row()
2597-
2523+
25982524
# Handle both QSqlTableModel and QStandardItemModel
25992525
if isinstance(model, QSqlTableModel):
26002526
feature_id = model.record(row).value(f"{feature_type}_id")
@@ -2609,11 +2535,11 @@ def _toggle_feature_psector(self, dialog, idx):
26092535
doable = model.data(doable_idx)
26102536
else:
26112537
continue
2612-
2538+
26132539
# Skip if we couldn't get required data
26142540
if feature_id is None or state is None:
26152541
continue
2616-
2542+
26172543
if doable:
26182544
sql += f"UPDATE {list_tables[feature_type]} SET doable = False WHERE {feature_type}_id = '{feature_id}' AND psector_id = {selected_psector} AND state = '{state}';"
26192545
else:

core/threads/import_inp/import_epanet_task.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class GwImportInpTask(GwTask):
4949
PROGRESS_CATALOGS = 30
5050
PROGRESS_NONVISUAL = 50
5151
PROGRESS_VISUAL = 90
52+
PROGRESS_MUNICIPALITY = 95
5253
PROGRESS_SOURCES = 97
5354
PROGRESS_END = 100
5455

@@ -117,10 +118,12 @@ def run(self) -> bool:
117118
self._manage_visual()
118119

119120
if self.update_municipality:
121+
self.progress_changed.emit("Municipality", self.PROGRESS_VISUAL, "Updating municipality...", False)
120122
self._update_municipality()
123+
self.progress_changed.emit("Municipality", self.PROGRESS_MUNICIPALITY, "done!", True)
121124

122125
if self.network.num_sources > 0:
123-
self.progress_changed.emit("Sources", self.PROGRESS_VISUAL, "Importing sources...", False)
126+
self.progress_changed.emit("Sources", self.PROGRESS_MUNICIPALITY, "Importing sources...", False)
124127
self._save_sources()
125128
self.progress_changed.emit("Sources", self.PROGRESS_SOURCES, "done!", True)
126129

@@ -445,6 +448,18 @@ def _create_new_varc_catalogs(self) -> None:
445448
continue
446449

447450
if self.manage_nodarcs.get(varc_type):
451+
# Create the 'VARC' if it doesn't exist
452+
execute_sql("""
453+
INSERT INTO cat_feature (
454+
id, feature_class, feature_type, shortcut_key, parent_layer,
455+
child_layer, descript, link_path, code_autofill, active,
456+
addparam, inventory_vdefault
457+
) VALUES (
458+
'VARC', 'VARC', 'ARC', NULL, 've_arc',
459+
've_arc_varc', 'Virtual Arc', NULL, true, true,
460+
NULL, NULL
461+
) ON CONFLICT DO NOTHING;
462+
""", commit=self.force_commit)
448463
# Just create the 'VARC' catalog to temporarly insert them as varcs
449464
execute_sql("""
450465
INSERT INTO cat_arc (id, arc_type, matcat_id, dint)
@@ -1402,9 +1417,16 @@ def _manage_nodarcs(self) -> str:
14021417
def _update_municipality(self):
14031418
""" Update the muni_id of all features getting the spatial intersection with the municipality """
14041419

1405-
sql = """
1406-
UPDATE node n SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom) LIMIT 1) WHERE EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom));
1407-
UPDATE arc a SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom) LIMIT 1) WHERE EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom));
1420+
sql = f"""
1421+
UPDATE node n
1422+
SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom) LIMIT 1)
1423+
WHERE workcat_id = '{self.workcat}' AND sector_id = {self.sector}
1424+
AND EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom));
1425+
1426+
UPDATE arc a
1427+
SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom) LIMIT 1)
1428+
WHERE workcat_id = '{self.workcat}' AND sector_id = {self.sector}
1429+
AND EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom));
14081430
"""
14091431
execute_sql(sql, commit=self.force_commit)
14101432

core/threads/import_inp/import_swmm_task.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class GwImportInpTask(GwTask):
8585
PROGRESS_CATALOGS = 30
8686
PROGRESS_NONVISUAL = 50
8787
PROGRESS_VISUAL = 90
88+
PROGRESS_MUNICIPALITY = 95
8889
PROGRESS_SOURCES = 97
8990
PROGRESS_END = 100
9091

@@ -160,7 +161,9 @@ def run(self) -> bool:
160161
self._manage_visual()
161162

162163
if self.update_municipality:
164+
self.progress_changed.emit("Municipality", self.PROGRESS_VISUAL, "Updating municipality...", False)
163165
self._update_municipality()
166+
self.progress_changed.emit("Municipality", self.PROGRESS_MUNICIPALITY, "done!", True)
164167

165168
self._manage_others()
166169

@@ -522,6 +525,18 @@ def _create_new_varc_catalogs(self) -> None:
522525
continue
523526

524527
if self.manage_flwreg.get(varc_type):
528+
# Create the 'VARC' if it doesn't exist
529+
execute_sql("""
530+
INSERT INTO cat_feature (
531+
id, feature_class, feature_type, shortcut_key, parent_layer,
532+
child_layer, descript, link_path, code_autofill, active,
533+
addparam, inventory_vdefault
534+
) VALUES (
535+
'VARC', 'VARC', 'ARC', NULL, 've_arc',
536+
've_arc_varc', 'Virtual Arc', NULL, true, true,
537+
NULL, NULL
538+
) ON CONFLICT DO NOTHING;
539+
""", commit=self.force_commit)
525540
# Just create the 'VARC' catalog to temporarly insert them as varcs
526541
execute_sql("""
527542
INSERT INTO cat_arc (id, arc_type, shape, geom1)
@@ -2109,9 +2124,16 @@ def get_subc_geom(subc):
21092124
def _update_municipality(self):
21102125
""" Update the muni_id of all features getting the spatial intersection with the municipality """
21112126

2112-
sql = """
2113-
UPDATE node n SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom) LIMIT 1) WHERE EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom));
2114-
UPDATE arc a SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom) LIMIT 1) WHERE EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom));
2127+
sql = f"""
2128+
UPDATE node n
2129+
SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom) LIMIT 1)
2130+
WHERE workcat_id = '{self.workcat}' AND sector_id = {self.sector}
2131+
AND EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, n.the_geom));
2132+
2133+
UPDATE arc a
2134+
SET muni_id = (SELECT m.muni_id FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom) LIMIT 1)
2135+
WHERE workcat_id = '{self.workcat}' AND sector_id = {self.sector}
2136+
AND EXISTS (SELECT 1 FROM ext_municipality m WHERE ST_Intersects(m.the_geom, a.the_geom));
21152137
"""
21162138
execute_sql(sql, commit=self.force_commit)
21172139

0 commit comments

Comments
 (0)