diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 905b2701..e2d52da0 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -58,7 +58,8 @@ class ProfileXYZ(Profile, SQLSubModel): num=0, nb_point: int = 0, code1: int = 0, code2: int = 0, - status=None, owner_scenario=-1): + status=None, owner_scenario=-1, + enabled=True): """ProfileXYZ constructor Args: @@ -90,6 +91,7 @@ class ProfileXYZ(Profile, SQLSubModel): self.time_l = 0.0 self._station = [] self.station_up_to_date = False + self._enabled = bool(enabled) self._get_water_limits_cache = {} self._get_water_limits_ac_cache = {} @@ -108,6 +110,7 @@ class ProfileXYZ(Profile, SQLSubModel): code1 INTEGER NOT NULL, code2 INTEGER NOT NULL, sl INTEGER, + enabled BOOLEAN NOT NULL DEFAULT TRUE, {Scenario.create_db_add_scenario()}, {Scenario.create_db_add_scenario_fk()}, FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id), @@ -152,6 +155,13 @@ class ProfileXYZ(Profile, SQLSubModel): "ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE" ) + if major == "0" and int(minor) <=2: + if int(release) < 9: + execute( + "ALTER TABLE geometry_profileXYZ " + + "ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT TRUE" + ) + return cls._update_submodel(execute, version, data) @classmethod @@ -237,7 +247,7 @@ class ProfileXYZ(Profile, SQLSubModel): table = execute( "SELECT pamhyr_id, ind, deleted, name, rk, num, " + - "code1, code2, sl, scenario " + + "code1, code2, sl, scenario, enabled " + "FROM geometry_profileXYZ " + f"WHERE reach = {reach.id} " + f"AND scenario = {scenario.id} " + @@ -258,6 +268,7 @@ class ProfileXYZ(Profile, SQLSubModel): code2 = next(it) sl = next(it) owner_scenario = next(it) + enabled = (next(it) == 1) profile = cls( id=pid, ind=ind, num=num, @@ -265,7 +276,8 @@ class ProfileXYZ(Profile, SQLSubModel): code1=code1, code2=code2, reach=reach, status=status, - owner_scenario=owner_scenario + owner_scenario=owner_scenario, + enabled=enabled ) if deleted: profile.set_as_deleted() @@ -318,12 +330,12 @@ class ProfileXYZ(Profile, SQLSubModel): execute( "INSERT OR REPLACE INTO " + "geometry_profileXYZ(pamhyr_id, deleted, ind, name, reach, " + - "rk, num, code1, code2, sl, scenario) " + + "rk, num, code1, code2, sl, scenario, enabled) " + "VALUES (" + f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " + f"{ind}, '{self._db_format(self._name)}', " + f"{self.reach.pamhyr_id}, {self.rk}, {self.num}, " + - f"{self.code1}, {self.code1}, {sl}, {self._status.scenario_id}" + + f"{self.code1}, {self.code1}, {sl}, {self._status.scenario_id}, {self._db_format(self._enabled)}" + ")" ) @@ -390,7 +402,8 @@ class ProfileXYZ(Profile, SQLSubModel): name=self.name, rk=self.rk, reach=self.reach, - status=self._status + status=self._status, + enabled=self.is_enabled ) if self.is_deleted(): new_p.set_as_deleted() @@ -410,7 +423,8 @@ class ProfileXYZ(Profile, SQLSubModel): name=self.name, rk=self.rk, reach=new_reach, - status=self._status + status=self._status, + enabled=self.is_enabled ) if self.is_deleted(): new_p.set_as_deleted() @@ -1131,7 +1145,8 @@ class ProfileXYZ(Profile, SQLSubModel): p = ProfileXYZ(name=self.name, rk=self.rk, reach=self.reach, - status=self._status) + status=self._status, + enabled=self.is_enabled) for i, k in enumerate(self.points): p.insert_point(i, k.copy()) @@ -1165,3 +1180,16 @@ class ProfileXYZ(Profile, SQLSubModel): break self._points = points self.modified() + + @property + def is_enabled(self): + return self._enabled + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, value): + self._enabled = bool(value) + self.modified() diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py index d2fea850..04f1144e 100644 --- a/src/Model/Geometry/Reach.py +++ b/src/Model/Geometry/Reach.py @@ -157,6 +157,14 @@ class Reach(SQLSubModel): def profiles(self, profiles): self._profiles = profiles + @property + def enabled_profiles(self): + return list(filter(lambda p: p.is_enabled, self.profiles)) + + @property + def number_enabled_profiles(self): + return len(self.enabled_profiles) + def get_profiles_from_rk(self, rk): return list( filter( diff --git a/src/Model/Study.py b/src/Model/Study.py index ded212ba..de86b428 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -46,7 +46,7 @@ logger = logging.getLogger() class Study(SQLModel): - _version = "0.2.7" + _version = "0.2.9" _sub_classes = [ Scenario, diff --git a/src/View/Geometry/Table.py b/src/View/Geometry/Table.py index 847722d9..20b8ac01 100644 --- a/src/View/Geometry/Table.py +++ b/src/View/Geometry/Table.py @@ -64,15 +64,20 @@ class GeometryReachTableModel(PamhyrTableModel): if not index.isValid(): return QVariant() + profile = self._data.profile(index.row()) + + if role == Qt.BackgroundRole and not profile.is_enabled: + return QColor(190, 190, 190) + if role == Qt.DisplayRole and index.column() == 0: - return self._data.profile(index.row()).name + return profile.name if role == Qt.DisplayRole and index.column() == 1: - rk = self._data.profile(index.row()).rk + rk = profile.rk return f"{rk:.4f}" if role == Qt.DisplayRole and index.column() == 2: - return str(self._data.profile(index.row()).nb_points) + return str(profile.nb_points) if role == Qt.TextAlignmentRole: return Qt.AlignHCenter | Qt.AlignVCenter @@ -155,6 +160,14 @@ class GeometryReachTableModel(PamhyrTableModel): self.endRemoveRows() self.layoutChanged.emit() + def enabled(self, rows, enabled): + self._undo.push( + SetEnabledCommand( + self._data, rows, enabled + ) + ) + self.layoutChanged.emit() + def sort_profiles(self, _reverse): self.layoutAboutToBeChanged.emit() diff --git a/src/View/Geometry/Translate.py b/src/View/Geometry/Translate.py index 1b3702da..c7e74e62 100644 --- a/src/View/Geometry/Translate.py +++ b/src/View/Geometry/Translate.py @@ -44,6 +44,9 @@ class GeometryTranslate(MainTranslate): self._dict["cross_sections"] = _translate("Geometry", "cross-sections") self._dict["profile"] = _translate("Geometry", "cross-section") self._dict["profiles"] = _translate("Geometry", "cross-sections") + self._dict["cross_section_enabled_count"] = _translate( + "Geometry", "Cross-section enabled ({count} disabled)" + ) self._dict["transverse_abscissa"] = _translate( "Geometry", "Transverse abscissa (m)" diff --git a/src/View/Geometry/UndoCommand.py b/src/View/Geometry/UndoCommand.py index 71e9c313..f14bfef8 100644 --- a/src/View/Geometry/UndoCommand.py +++ b/src/View/Geometry/UndoCommand.py @@ -68,6 +68,27 @@ class SetRKCommand(SetDataCommand): self._reach.profile(self._index).rk = self._new +class SetEnabledCommand(QUndoCommand): + def __init__(self, reach, rows, enabled): + QUndoCommand.__init__(self) + + self._profiles = [reach.profile(row) for row in rows] + self._old = [profile.is_enabled for profile in self._profiles] + self._new = bool(enabled) + + @staticmethod + def _set_enabled(profile, enabled): + profile.enabled = enabled + + def undo(self): + for profile, enabled in zip(self._profiles, self._old): + self._set_enabled(profile, enabled) + + def redo(self): + for profile in self._profiles: + self._set_enabled(profile, self._new) + + class AddCommand(QUndoCommand): def __init__(self, reach, index): QUndoCommand.__init__(self) diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index 19e84363..f96121ca 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -99,6 +99,7 @@ class GeometryWindow(PamhyrWindow): self._profile_window = [] self.setup_table() + self.setup_checkbox() self.setup_plots() self.setup_statusbar() self.setup_connections() @@ -124,6 +125,10 @@ class GeometryWindow(PamhyrWindow): table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) table.setAlternatingRowColors(True) + def setup_checkbox(self): + self._checkbox = self.find(QCheckBox, "checkBox_enabled") + self._set_checkbox_state() + def setup_plots(self): self.setup_plots_xy() self.setup_plots_rkc() @@ -223,6 +228,9 @@ class GeometryWindow(PamhyrWindow): .selectionChanged\ .connect(self.select_current_profile) + if not self._study.is_read_only(): + self._checkbox.clicked.connect(self._set_profiles_state) + self._table.layoutChanged.connect(self.update_redraw) def update(self): @@ -525,6 +533,48 @@ class GeometryWindow(PamhyrWindow): self._plot_ac.draw() self.tableView.model().blockSignals(False) + self._set_checkbox_state() + + def index_selected_rows(self): + return [ + index.row() + for index in self.tableView.selectionModel().selectedRows() + ] + + def _set_checkbox_state(self): + rows = self.index_selected_rows() + editable = not self._study.is_read_only() + disabled_count = self._reach.number_profiles - self._reach.number_enabled_profiles + self._checkbox.setText( + self._trad["cross_section_enabled_count"].format( + count=disabled_count + ) + ) + + self._checkbox.setEnabled(editable and len(rows) > 0) + if len(rows) == 0: + self._checkbox.setTristate(False) + self._checkbox.setChecked(False) + return + + states = { + self._reach.profile(row).is_enabled + for row in rows + } + if len(states) == 1: + self._checkbox.setTristate(False) + self._checkbox.setChecked(states.pop()) + else: + self._checkbox.setTristate(True) + self._checkbox.setCheckState(Qt.PartiallyChecked) + + def _set_profiles_state(self, enabled): + rows = self.index_selected_rows() + if len(rows) == 0: + return + + self._checkbox.setTristate(False) + self._table.enabled(rows, enabled) def add(self): if len(self.tableView.selectedIndexes()) == 0: diff --git a/src/View/ui/GeometryReach.ui b/src/View/ui/GeometryReach.ui index 8c80a7bf..c87ed1db 100644 --- a/src/View/ui/GeometryReach.ui +++ b/src/View/ui/GeometryReach.ui @@ -24,10 +24,20 @@ Qt::Horizontal - + + + + + Cross-section enabled (0 disabled) + + + true + + +