From 1ed5d69bf4f9336faf52ee70823d4d4f6002032a Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Mon, 10 Nov 2025 16:15:40 +0100 Subject: [PATCH] GeoTIFF: Prepare view integration. --- src/View/GeoTIFF/Edit/Window.py | 102 +++++++++++++++++++++++++++ src/View/GeoTIFF/List.py | 96 +++++++++++++++++++++++++ src/View/GeoTIFF/Translate.py | 35 ++++++++++ src/View/GeoTIFF/UndoCommand.py | 81 +++++++++++++++++++++ src/View/GeoTIFF/Window.py | 120 ++++++++++++++++++++++++++++++++ 5 files changed, 434 insertions(+) create mode 100644 src/View/GeoTIFF/Edit/Window.py create mode 100644 src/View/GeoTIFF/List.py create mode 100644 src/View/GeoTIFF/Translate.py create mode 100644 src/View/GeoTIFF/UndoCommand.py create mode 100644 src/View/GeoTIFF/Window.py diff --git a/src/View/GeoTIFF/Edit/Window.py b/src/View/GeoTIFF/Edit/Window.py new file mode 100644 index 00000000..f3ede26a --- /dev/null +++ b/src/View/GeoTIFF/Edit/Window.py @@ -0,0 +1,102 @@ +# Window.py -- Pamhyr +# Copyright (C) 2024-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +import logging + +from Modules import Modules +from View.Tools.PamhyrWindow import PamhyrWindow + +from PyQt5.QtWidgets import ( + QLabel, QPlainTextEdit, QPushButton, + QCheckBox, +) + +from View.GeoTIFF.Translate import GeoTIFFTranslate +from View.GeoTIFF.UndoCommand import ( + SetCommand +) + +logger = logging.getLogger() + + +class EditGeoTIFFWindow(PamhyrWindow): + _pamhyr_ui = "EditGeoTIFF" + _pamhyr_name = "Edit GeoTIFF" + + def __init__(self, study=None, config=None, add_file=None, + trad=None, undo=None, parent=None): + + name = trad[self._pamhyr_name] + " - " + study.name + super(EditGeoTIFFWindow, self).__init__( + title=name, + study=study, + config=config, + options=[], + parent=parent + ) + + self._geotiff = geotiff + self._hash_data.append(self._geotiff) + + self._undo = undo + + self.setup_values() + self.setup_connection() + + def setup_values(self): + self.set_check_box("checkBox", self._geotiff.enabled) + self.set_line_edit_text("lineEdit_name", self._geotiff.name) + self.set_line_edit_text("lineEdit_path", self._geotiff.description) + self.set_plaintext_edit_text("plainTextEdit", self._geotiff.text) + + if self._study.is_read_only(): + self.set_check_box_enable("checkBox", False) + self.set_line_edit_enable("lineEdit_name", False) + self.set_line_edit_enable("lineEdit_path", False) + self.set_plaintext_edit_enable("plainTextEdit", False) + + def setup_connection(self): + self.find(QPushButton, "pushButton_cancel")\ + .clicked.connect(self.close) + self.find(QPushButton, "pushButton_ok")\ + .clicked.connect(self.accept) + + def accept(self): + if self._study.is_editable(): + is_enabled = self.get_check_box("checkBox") + name = self.get_line_edit_text("lineEdit_name") + path = self.get_line_edit_text("lineEdit_path") + coord_bottom = self.get_plaintext_edit_text("plainTextEdit") + coord_top = self.get_plaintext_edit_text("plainTextEdit") + coord_left = self.get_plaintext_edit_text("plainTextEdit") + coord_right = self.get_plaintext_edit_text("plainTextEdit") + + self._undo.push( + SetCommand( + self._geotiff, enabled=is_enabled, + name=name, description=description, + coordinates_bottom=coord_bottom, + coordinates_top=coord_top, + coordinates_left=coord_left, + coordinates_right=coord_right, + ) + ) + + self._propagate_update(key=Modules.GEOTIFF) + + self.close() diff --git a/src/View/GeoTIFF/List.py b/src/View/GeoTIFF/List.py new file mode 100644 index 00000000..8bb158aa --- /dev/null +++ b/src/View/GeoTIFF/List.py @@ -0,0 +1,96 @@ +# List.py -- Pamhyr +# Copyright (C) 2024-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +import logging + +from functools import reduce +from tools import trace, timer + +from PyQt5.QtCore import ( + Qt, QVariant, +) + +from PyQt5.QtGui import ( + QColor, QBrush, +) + +from View.Tools.PamhyrList import PamhyrListModel +from View.GeoTIFF.UndoCommand import ( + AddCommand, DelCommand +) + +logger = logging.getLogger() + + +class ListModel(PamhyrListModel): + def get_true_data_row(self, row): + el = self._data.get(row) + + return next( + map( + lambda e: e[0], + filter( + lambda e: e[1] == el, + enumerate(self._data._lst) + ) + ), 0 + ) + + def data(self, index, role): + row = index.row() + column = index.column() + + file = self._data.files[row] + + if role == Qt.ForegroundRole: + color = Qt.gray + + if file.is_enabled(): + color = QColor("black") + else: + color = QColor("grey") + + return QBrush(color) + + if role == Qt.ItemDataRole.DisplayRole: + text = f"{file.name}: '{file.path}'" + + if not file.is_enabled(): + text += " (disabled)" + + return text + + return QVariant() + + def add(self, row): + row = self.get_true_data_row(row) + + self._undo.push( + AddCommand( + self._data, row + ) + ) + self.update() + + def delete(self, row): + self._undo.push( + DelCommand( + self._data, self._data.files[row] + ) + ) + self.update() diff --git a/src/View/GeoTIFF/Translate.py b/src/View/GeoTIFF/Translate.py new file mode 100644 index 00000000..fe39460f --- /dev/null +++ b/src/View/GeoTIFF/Translate.py @@ -0,0 +1,35 @@ +# Translate.py -- Pamhyr +# Copyright (C) 2024-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import QCoreApplication +from View.Translate import MainTranslate + +_translate = QCoreApplication.translate + + +class GeoTIFFTranslate(MainTranslate): + def __init__(self): + super(AddFileTranslate, self).__init__() + + self._dict["GeoTIFF files"] = _translate( + "GeoTIFF", "GeoTIFF files" + ) + + self._dict["Edit additional file"] = _translate( + "GeoTIFF", "Edit GeoTIFF file" + ) diff --git a/src/View/GeoTIFF/UndoCommand.py b/src/View/GeoTIFF/UndoCommand.py new file mode 100644 index 00000000..9e26c1be --- /dev/null +++ b/src/View/GeoTIFF/UndoCommand.py @@ -0,0 +1,81 @@ +# UndoCommand.py -- Pamhyr +# Copyright (C) 2024-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +from tools import trace, timer + +from PyQt5.QtWidgets import ( + QMessageBox, QUndoCommand, QUndoStack, +) + + +class SetCommand(QUndoCommand): + def __init__(self, geotiff, **kwargs): + QUndoCommand.__init__(self) + + self._geotiff = geotiff + self._new = kwargs + self._old = None + + def undo(self): + f = self._geotiff + + for key in self._old: + f[key] = self._old[key] + + def redo(self): + f = self._geotiff + + if self._old is None: + self._old = {} + for key in self._new: + self._old[key] = f[key] + + for key in self._new: + f[key] = self._new[key] + + +class AddCommand(QUndoCommand): + def __init__(self, files, row): + QUndoCommand.__init__(self) + + self._files = files + self._row = row + self._new = None + + def undo(self): + self._new.set_as_deleted() + + def redo(self): + if self._new is None: + self._new = self._files.new(self._row) + else: + self._new.set_as_not_deleted() + + +class DelCommand(QUndoCommand): + def __init__(self, files, line): + QUndoCommand.__init__(self) + + self._files = files + self._line = line + + def undo(self): + self._line.set_as_not_deleted() + + def redo(self): + self._line.set_as_deleted() diff --git a/src/View/GeoTIFF/Window.py b/src/View/GeoTIFF/Window.py new file mode 100644 index 00000000..98d1d058 --- /dev/null +++ b/src/View/GeoTIFF/Window.py @@ -0,0 +1,120 @@ +# Window.py -- Pamhyr +# Copyright (C) 2024-2025 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# -*- coding: utf-8 -*- + +from tools import trace, timer + +from PyQt5.QtWidgets import ( + QAction, QListView, +) + +from View.Tools.PamhyrWindow import PamhyrWindow + +from View.GeoTIFF.List import ListModel +from View.GeoTIFF.Translate import GeoTIFFTranslate +from View.GeoTIFF.Edit.Window import EditGeoTIFFWindow + + +class GeoTIFFListWindow(PamhyrWindow): + _pamhyr_ui = "GeoTIFFList" + _pamhyr_name = "GeoTIFF files" + + def __init__(self, study=None, config=None, + parent=None): + trad = GeoTIFFTranslate() + name = trad[self._pamhyr_name] + " - " + study.name + + super(GeoTIFFListWindow, self).__init__( + title=name, + study=study, + config=config, + trad=trad, + options=[], + parent=parent + ) + + self.setup_list() + self.setup_connections() + + def setup_list(self): + lst = self.find(QListView, f"listView") + self._list = ListModel( + list_view=lst, + data=self._study.river.geotiff, + undo=self._undo_stack, + trad=self._trad, + ) + + def setup_connections(self): + if self._study.is_editable(): + self.find(QAction, "action_add").triggered.connect(self.add) + self.find(QAction, "action_delete").triggered.connect(self.delete) + + self.find(QAction, "action_edit").triggered.connect(self.edit) + + def update(self): + self._list.update() + + def selected_rows(self): + lst = self.find(QListView, f"listView") + return list(map(lambda i: i.row(), lst.selectedIndexes())) + + def add(self): + rows = self.selected_rows() + if len(rows) > 0: + row = rows[0] + else: + row = 0 + + self._list.add(row) + + def delete(self): + rows = self.selected_rows() + if len(rows) == 0: + return + + self._list.delete(rows[0]) + + def edit(self): + rows = self.selected_rows() + + for row in rows: + add_file = self._study.river.geotiff.files[row] + + if self.sub_window_exists( + EditGeoTIFFWindow, + data=[self._study, self._config, add_file] + ): + continue + + win = EditGeoTIFFWindow( + study=self._study, + config=self._config, + add_file=add_file, + trad=self._trad, + undo=self._undo_stack, + parent=self, + ) + win.show() + + def _undo(self): + self._undo_stack.undo() + self.update() + + def _redo(self): + self._undo_stack.redo() + self.update()