Disable profiles: security to prevent the disable of a profile associated with data (initial conditions, structures, lateral conditions, weather params, init. cond. temperature)

mesh_tab
Dylan Jeannin 2026-08-24 17:01:16 +02:00
parent 8978cc3482
commit 944f99f14b
4 changed files with 163 additions and 1 deletions

View File

@ -167,7 +167,11 @@ class InitialConditionsTemperature(SQLSubModel):
return True
def __len__(self):
return len(self._data)
return len(self.data)
@property
def data(self):
return list(filter(lambda item: not item.is_deleted(), self._data))
@property
def name(self):

View File

@ -907,6 +907,63 @@ Last export at: @date."""
def weather_parameters(self):
return self._WeatherParameters
def profile_dependencies(self, profile):
"""Return model data which directly reference *profile*.
PK-based intervals are deliberately not included: only explicit
references to the profile object prevent it from being disabled.
"""
dependencies = []
def add(kind, item, association):
dependencies.append({
"kind": kind,
"item": item,
"association": association,
})
for reach in list(self._initial_conditions._dict):
initial_conditions = self._initial_conditions.get(reach)
for data in initial_conditions.data:
if data["section"] is profile:
add("initial_condition", data, "section")
for structure in self._hydraulic_structures.lst:
if structure.input_section is profile:
add("hydraulic_structure", structure, "input_section")
if structure.output_section is profile:
add("hydraulic_structure", structure, "output_section")
for tab in self._lateral_contribution._tabs_list:
for contribution in self._lateral_contribution.get_tab(tab):
if contribution.begin_section is profile:
add("lateral_contribution", contribution, "begin_section")
if contribution.end_section is profile:
add("lateral_contribution", contribution, "end_section")
for parameter in self._WeatherParameters.lst:
if parameter.begin_section is profile:
add("weather_parameter", parameter, "begin_section")
if parameter.end_section is profile:
add("weather_parameter", parameter, "end_section")
reach_id = profile.reach.pamhyr_id
for initial_condition in self._InitialConditionsTemperature.lst:
for specification in initial_condition.data:
same_reach = specification.reach == reach_id
same_rk = (
specification.start_rk == profile.rk or
specification.end_rk == profile.rk
)
if same_reach and same_rk:
add(
"initial_condition_temperature",
specification,
"cross_section_pk",
)
return dependencies
def get_params(self, solver):
if solver in self._parameters:
return self._parameters[solver]

View File

@ -19,6 +19,7 @@
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
from View.WeatherParameters.translate import WeatherParametersTranslate
_translate = QCoreApplication.translate
@ -47,6 +48,63 @@ class GeometryTranslate(MainTranslate):
self._dict["cross_section_enabled_count"] = _translate(
"Geometry", "Cross-section enabled ({count} disabled)"
)
self._dict["profile_disable_blocked"] = _translate(
"Geometry", "The cross-section cannot be disabled."
)
self._dict["profile_disable_blocked_info"] = _translate(
"Geometry",
"It is referenced by the following data:\n{dependencies}\n\n"
"Change or remove these associations before disabling it."
)
self._dict["profile_dependency"] = _translate(
"Geometry", "{kind}{name}” ({association})"
)
self._dict["initial_condition"] = _translate(
"Geometry", "Initial condition"
)
self._dict["initial_condition_temperature"] = _translate(
"Geometry", "Initial condition temperature"
)
self._dict["hydraulic_structure"] = _translate(
"Geometry", "Hydraulic structure"
)
self._dict["lateral_contribution"] = _translate(
"Geometry", "Lateral contribution"
)
self._dict["weather_parameter"] = _translate(
"Geometry", "Weather parameter"
)
self._dict["section"] = _translate("Geometry", "cross-section")
self._dict["input_section"] = _translate(
"Geometry", "input cross-section"
)
self._dict["output_section"] = _translate(
"Geometry", "output cross-section"
)
self._dict["begin_section"] = _translate(
"Geometry", "first cross-section"
)
self._dict["end_section"] = _translate(
"Geometry", "last cross-section"
)
self._dict["cross_section_pk"] = _translate(
"Geometry", "cross-section PK"
)
weather_parameters = WeatherParametersTranslate().get_dict(
"weather_parameters"
)
self._sub_dict["weather_parameter_types"] = {
"AT": weather_parameters["air_temperature"],
"SH": weather_parameters["specific_humidity"],
"GR": weather_parameters["global_radiation"],
"RWS": weather_parameters["reference_wind_speed"],
"GT": weather_parameters["surface_temperature"],
"GFR": weather_parameters["surface_flow_rate"],
"ALB": weather_parameters["albedo"],
"SC": weather_parameters["shading_coefficient"],
"CCF": weather_parameters["cloud_cover_fraction"],
}
self._dict["transverse_abscissa"] = _translate(
"Geometry", "Transverse abscissa (m)"

View File

@ -573,6 +573,49 @@ class GeometryWindow(PamhyrWindow):
if len(rows) == 0:
return
if not enabled:
blocked = []
for row in rows:
profile = self._reach.profile(row)
dependencies = self._study.river.profile_dependencies(profile)
if len(dependencies) != 0:
blocked.append((profile, dependencies))
if len(blocked) != 0:
details = []
for profile, dependencies in blocked:
details.append(f"{profile.name}:")
for dependency in dependencies:
item = dependency["item"]
if dependency["kind"] == "weather_parameter":
name = self._trad.get_dict(
"weather_parameter_types"
).get(item.type, item.type)
else:
name = getattr(item, "name", "")
if name == "":
name = self._trad[dependency["kind"]]
details.append(
" - " +
self._trad["profile_dependency"].format(
kind=self._trad[dependency["kind"]],
name=name,
association=self._trad[
dependency["association"]
],
)
)
self._set_checkbox_state()
self.message_box(
self._trad["profile_disable_blocked"],
self._trad["profile_disable_blocked_info"].format(
dependencies="\n".join(details)
),
window_title=self._trad["warning"],
)
return
self._checkbox.setTristate(False)
self._table.enabled(rows, enabled)