diff --git a/src/Model/D90AdisTS/D90AdisTS.py b/src/Model/D90AdisTS/D90AdisTS.py index e4953cd85b9f4ac5139ef82302dc394fb3177936..39dac26af309c4c879218fe873f5521e99e71f01 100644 --- a/src/Model/D90AdisTS/D90AdisTS.py +++ b/src/Model/D90AdisTS/D90AdisTS.py @@ -62,7 +62,7 @@ class D90AdisTS(SQLSubModel): id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, d90 REAL NOT NULL, - enabled BOOLEAN NOT NULL, + enabled BOOLEAN NOT NULL ) """) diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py index d1ab2c8d65ccd80cb793394ae5cd972d8a634d75..7ce6bc3ad0fcf011994ac1035919a95fc43c9467 100644 --- a/src/Model/D90AdisTS/D90AdisTSSpec.py +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -177,7 +177,7 @@ class D90AdisTSSpec(SQLSubModel): return self._d90 @d90.setter - def d90(self, concentration): + def d90(self, d90): self._d90 = d90 self._status.modified() diff --git a/src/View/D90AdisTS/Table.py b/src/View/D90AdisTS/Table.py new file mode 100644 index 0000000000000000000000000000000000000000..13d5555cb7a43845c940398e56f6b7aded460514 --- /dev/null +++ b/src/View/D90AdisTS/Table.py @@ -0,0 +1,217 @@ +# Table.py -- Pamhyr +# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +import logging +import traceback +from tools import trace, timer + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, +) + +from View.Tools.PamhyrTable import PamhyrTableModel + +from View.D90AdisTS.UndoCommand import ( + SetCommand, AddCommand, SetCommandSpec, + DelCommand, +) + +logger = logging.getLogger() + +_translate = QCoreApplication.translate + + +class ComboBoxDelegate(QItemDelegate): + def __init__(self, data=None, ic_spec_lst=None, trad=None, parent=None, mode="reaches"): + super(ComboBoxDelegate, self).__init__(parent) + + self._data = data + self._mode = mode + self._trad = trad + self._ic_spec_lst = ic_spec_lst + + def createEditor(self, parent, option, index): + self.editor = QComboBox(parent) + + val = [] + if self._mode == "kp": + reach_id = self._ic_spec_lst[index.row()].reach + + reach = next(filter(lambda edge: edge.id == reach_id, self._data.edges())) + + if reach_id is not None: + val = list( + map( + lambda kp: str(kp), reach.reach.get_kp() + ) + ) + else: + val = list( + map( + lambda n: n.name, self._data.edges() + ) + ) + + self.editor.addItems( + [self._trad['not_associated']] + + val + ) + + self.editor.setCurrentText(str(index.data(Qt.DisplayRole))) + return self.editor + + def setEditorData(self, editor, index): + value = index.data(Qt.DisplayRole) + self.editor.currentTextChanged.connect(self.currentItemChanged) + + def setModelData(self, editor, model, index): + text = str(editor.currentText()) + model.setData(index, text) + editor.close() + editor.deleteLater() + + def updateEditorGeometry(self, editor, option, index): + r = QRect(option.rect) + if self.editor.windowFlags() & Qt.Popup: + if editor.parent() is not None: + r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft())) + editor.setGeometry(r) + + @pyqtSlot() + def currentItemChanged(self): + self.commitData.emit(self.sender()) + + +class D90TableModel(PamhyrTableModel): + def __init__(self, river=None, data=None, **kwargs): + self._river = river + + super(D90TableModel, self).__init__(data=data, **kwargs) + + self._data = data + + def _setup_lst(self): + self._lst = self._data._data + + def rowCount(self, parent): + return len(self._lst) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + row = index.row() + column = index.column() + + if self._headers[column] is "name": + n = self._lst[row].name + if n is None or n == "": + return self._trad['not_associated'] + return n + elif self._headers[column] is "reach": + n = self._lst[row].reach + if n is None: + return self._trad['not_associated'] + return next(filter(lambda edge: edge.id == n, self._river.edges())).name + elif self._headers[column] is "start_kp": + n = self._lst[row].start_kp + if n is None: + return self._trad['not_associated'] + return n + elif self._headers[column] is "end_kp": + n = self._lst[row].end_kp + if n is None: + return self._trad['not_associated'] + return n + elif self._headers[column] is "d90": + n = self._lst[row].d90 + if n is None: + return self._trad['not_associated'] + return n + + return QVariant() + + def setData(self, index, value, role=Qt.EditRole): + if not index.isValid() or role != Qt.EditRole: + return False + + row = index.row() + column = index.column() + + try: + if self._headers[column] != "reach": + self._undo.push( + SetCommandSpec( + self._lst, row, self._headers[column], value + ) + ) + elif self._headers[column] == "reach": + print(self._river.edge(value).id) + self._undo.push( + SetCommandSpec( + self._lst, row, self._headers[column], self._river.edge(value).id + ) + ) + except Exception as e: + logger.info(e) + logger.debug(traceback.format_exc()) + + self.dataChanged.emit(index, index) + return True + + def add(self, row, parent=QModelIndex()): + self.beginInsertRows(parent, row, row - 1) + + self._undo.push( + AddCommand( + self._data, self._lst, row + ) + ) + + self.endInsertRows() + self.layoutChanged.emit() + + def delete(self, rows, parent=QModelIndex()): + self.beginRemoveRows(parent, rows[0], rows[-1]) + + self._undo.push( + DelCommand( + self._data, self._lst, rows + ) + ) + + self.endRemoveRows() + self.layoutChanged.emit() + + def undo(self): + self._undo.undo() + self.layoutChanged.emit() + + def redo(self): + self._undo.redo() + self.layoutChanged.emit() + diff --git a/src/View/D90AdisTS/TableDefault.py b/src/View/D90AdisTS/TableDefault.py new file mode 100644 index 0000000000000000000000000000000000000000..c3231d424916abef2ccb4c1790739737e44e5989 --- /dev/null +++ b/src/View/D90AdisTS/TableDefault.py @@ -0,0 +1,95 @@ +# Table.py -- Pamhyr +# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +import logging +import traceback +from tools import trace, timer + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, +) + +from View.Tools.PamhyrTable import PamhyrTableModel + +from View.D90AdisTS.UndoCommand import ( + SetCommand, +) + +logger = logging.getLogger() + +_translate = QCoreApplication.translate + +class D90TableDefaultModel(PamhyrTableModel): + def __init__(self, **kwargs): + super(D90TableDefaultModel, self).__init__(**kwargs) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + row = index.row() + column = index.column() + + if self._headers[column] is "name": + return self._data[row].name + elif self._headers[column] is "d90": + n = self._data[row].d90 + if n is None: + return self._trad['not_associated'] + return n + + return QVariant() + + def setData(self, index, value, role=Qt.EditRole): + if not index.isValid() or role != Qt.EditRole: + return False + + row = index.row() + column = index.column() + + try: + if self._headers[column] is not None: + self._undo.push( + SetCommand( + self._data, row, self._headers[column], value + ) + ) + except Exception as e: + logger.info(e) + logger.debug(traceback.format_exc()) + + self.dataChanged.emit(index, index) + return True + + def undo(self): + self._undo.undo() + self.layoutChanged.emit() + + def redo(self): + self._undo.redo() + self.layoutChanged.emit() + diff --git a/src/View/D90AdisTS/UndoCommand.py b/src/View/D90AdisTS/UndoCommand.py new file mode 100644 index 0000000000000000000000000000000000000000..f0644955f804a69300d441ff4787ac60a377ab7d --- /dev/null +++ b/src/View/D90AdisTS/UndoCommand.py @@ -0,0 +1,150 @@ +# UndoCommand.py -- Pamhyr +# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +from copy import deepcopy +from tools import trace, timer + +from PyQt5.QtWidgets import ( + QMessageBox, QUndoCommand, QUndoStack, +) + +from Model.D90AdisTS.D90AdisTS import D90AdisTS +from Model.D90AdisTS.D90AdisTSList import D90AdisTSList + + +class SetCommand(QUndoCommand): + def __init__(self, data, row, column, new_value): + QUndoCommand.__init__(self) + + self._data = data + self._row = row + self._column = column + + if self._column == "name": + self._old = self._data[self._row].name + elif self._column == "d90": + self._old = self._data[self._row].d90 + + _type = float + if column == "name": + _type = str + + self._new = _type(new_value) + + def undo(self): + if self._column == "name": + self._data[self._row].name = self._old + elif self._column == "d90": + self._data[self._row].d90 = self._old + + def redo(self): + if self._column == "name": + self._data[self._row].name = self._new + elif self._column == "d90": + self._data[self._row].d90 = self._new + +class SetCommandSpec(QUndoCommand): + def __init__(self, data, row, column, new_value): + QUndoCommand.__init__(self) + + self._data = data + self._row = row + self._column = column + + if self._column == "name": + self._old = self._data[self._row].name + elif self._column == "reach": + self._old = self._data[self._row].reach + elif self._column == "start_kp": + self._old = self._data[self._row].start_kp + elif self._column == "end_kp": + self._old = self._data[self._row].end_kp + elif self._column == "d90": + self._old = self._data[self._row].d90 + + _type = float + if column == "name": + _type = str + elif column == "reach": + _type = int + + self._new = _type(new_value) + + def undo(self): + if self._column == "name": + self._data[self._row].name = self._old + elif self._column == "reach": + self._data[self._row].reach = self._old + elif self._column == "start_kp": + self._data[self._row].start_kp = self._old + elif self._column == "end_kp": + self._data[self._row].end_kp = self._old + elif self._column == "d90": + self._data[self._row].d90 = self._old + + def redo(self): + if self._column == "name": + self._data[self._row].name = self._new + elif self._column == "reach": + self._data[self._row].reach = self._new + elif self._column == "start_kp": + self._data[self._row].start_kp = self._new + elif self._column == "end_kp": + self._data[self._row].end_kp = self._new + elif self._column == "d90": + self._data[self._row].d90 = self._new + +class AddCommand(QUndoCommand): + def __init__(self, data, ics_spec, index): + QUndoCommand.__init__(self) + + self._data = data + self._ics_spec = ics_spec + self._index = index + self._new = None + + def undo(self): + self._data.delete_i([self._index]) + + def redo(self): + if self._new is None: + self._new = self._data.new(self._index) + else: + self._data.insert(self._index, self._new) + +class DelCommand(QUndoCommand): + def __init__(self, data, ics_spec, rows): + QUndoCommand.__init__(self) + + self._data = data + self._ics_spec = ics_spec + self._rows = rows + #self._data = data + + self._ic = [] + for row in rows: + self._ic.append((row, self._ics_spec[row])) + self._ic.sort() + + def undo(self): + for row, el in self._ic: + self._data.insert(row, el) + + def redo(self): + self._data.delete_i(self._rows) + diff --git a/src/View/D90AdisTS/Window.py b/src/View/D90AdisTS/Window.py new file mode 100644 index 0000000000000000000000000000000000000000..5fffc17d68a61d9e2134c39fe9996a4f3a33c576 --- /dev/null +++ b/src/View/D90AdisTS/Window.py @@ -0,0 +1,283 @@ +# Window.py -- Pamhyr +# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +import os +import logging + +from tools import trace, timer, logger_exception + +from View.Tools.PamhyrWindow import PamhyrWindow + +from PyQt5.QtGui import ( + QKeySequence, QIcon, +) + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, QItemSelectionModel, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, QVBoxLayout, QHeaderView, QTabWidget, + QVBoxLayout, QToolBar, QAction, QToolButton, +) + +from Modules import Modules + +from View.InitialConditionsAdisTS.UndoCommand import ( + SetCommand, +) + +from View.D90AdisTS.TableDefault import ( + D90TableDefaultModel, +) + +from View.D90AdisTS.Table import ( + D90TableModel, ComboBoxDelegate, +) + +from View.D90AdisTS.translate import D90AdisTSTranslate + +from Solver.Mage import Mage8 + +_translate = QCoreApplication.translate + +logger = logging.getLogger() + + +class D90AdisTSWindow(PamhyrWindow): + _pamhyr_ui = "D90AdisTS" + _pamhyr_name = "D90 AdisTS" + + def __init__(self, data=None, study=None, config=None, parent=None): + self._data = [] + self._data.append(data) + trad = D90AdisTSTranslate() + + name = ( + trad[self._pamhyr_name] + + " - " + study.name + + " - " + self._data[0].name + ) + + super(D90AdisTSWindow, self).__init__( + title=name, + study=study, + config=config, + trad=trad, + parent=parent + ) + + self._hash_data.append(data) + + self._d90_adists_lst = study.river.d90_adists + + self.setup_table() + + self.ui.setWindowTitle(self._title) + + def setup_table(self): + + path_icons = os.path.join(self._get_ui_directory(), f"ressources") + + table_default = self.find(QTableView, f"tableView") + + self._table = D90TableDefaultModel( + table_view=table_default, + table_headers=self._trad.get_dict("table_headers"), + editable_headers=["name", "d90"], + delegates={}, + data=self._data, + undo=self._undo_stack, + trad=self._trad + ) + + table_default.setModel(self._table) + table_default.setSelectionBehavior(QAbstractItemView.SelectRows) + table_default.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + table_default.setAlternatingRowColors(True) + + layout = self.find(QVBoxLayout, f"verticalLayout_1") + toolBar = QToolBar() + layout.addWidget(toolBar) + + action_add = QAction(self) + action_add.setIcon(QIcon(os.path.join(path_icons, f"add.png"))) + action_add.triggered.connect(self.add) + action_delete = QAction(self) + action_delete.setIcon(QIcon(os.path.join(path_icons, f"del.png"))) + action_delete.triggered.connect(self.delete) + + toolBar.addAction(action_add) + toolBar.addAction(action_delete) + + self.table_spec = QTableView() + layout.addWidget(self.table_spec) + + self._delegate_reach = ComboBoxDelegate( + trad=self._trad, + data=self._study.river, + ic_spec_lst=self._data[0]._data, + parent=self, + mode="reaches" + ) + self._delegate_kp = ComboBoxDelegate( + trad=self._trad, + data=self._study.river, + ic_spec_lst=self._data[0]._data, + parent=self, + mode="kp" + ) + + self._table_spec = D90TableModel( + table_view=self.table_spec, + table_headers=self._trad.get_dict("table_headers_spec"), + editable_headers=["name", "reach", "start_kp", "end_kp", "d90"], + delegates={ + "reach": self._delegate_reach, + "start_kp": self._delegate_kp, + "end_kp": self._delegate_kp + }, + data=self._data[0], + undo=self._undo_stack, + trad=self._trad, + river=self._study.river + ) + + self.table_spec.setModel(self._table_spec) + self.table_spec.setSelectionBehavior(QAbstractItemView.SelectRows) + self.table_spec.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + self.table_spec.setAlternatingRowColors(True) + + selectionModel = self.table_spec.selectionModel() + index = self.table_spec.model().index(0, 0) + + selectionModel.select( + index, + QItemSelectionModel.Rows | + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Select + ) + self.table_spec.scrollTo(index) + + def index_selected_row(self): + #table = self.find(QTableView, f"tableView") + table = self.table_spec + rows = table.selectionModel()\ + .selectedRows() + + if len(rows) == 0: + return 0 + + return rows[0].row() + + def index_selected_rows(self): + #table = self.find(QTableView, f"tableView") + table = self.table_spec + return list( + # Delete duplicate + set( + map( + lambda i: i.row(), + table.selectedIndexes() + ) + ) + ) + + def move_up(self): + row = self.index_selected_row() + self._table.move_up(row) + self._update() + + def move_down(self): + row = self.index_selected_row() + self._table.move_down(row) + self._update() + + def _copy(self): + rows = list( + map( + lambda row: row.row(), + self.tableView.selectionModel().selectedRows() + ) + ) + + table = list( + map( + lambda eic: list( + map( + lambda k: eic[1][k], + ["kp", "discharge", "elevation"] + ) + ), + filter( + lambda eic: eic[0] in rows, + enumerate(self._ics.lst()) + ) + ) + ) + + self.copyTableIntoClipboard(table) + + def _paste(self): + header, data = self.parseClipboardTable() + + if len(data) + len(header) == 0: + return + + logger.debug( + "IC: Paste: " + + f"header = {header}, " + + f"data = {data}" + ) + + try: + row = self.index_selected_row() + # self._table.paste(row, header, data) + self._table.paste(row, [], data) + except Exception as e: + logger_exception(e) + + self._update() + + def _undo(self): + self._table.undo() + self._update() + + def _redo(self): + self._table.redo() + self._update() + + def add(self): + rows = self.index_selected_rows() + if len(self._data[0]._data) == 0 or len(rows) == 0: + self._table_spec.add(0) + else: + self._table_spec.add(rows[0]) + + def delete(self): + print("del") + rows = self.index_selected_rows() + if len(rows) == 0: + print("len 0") + return + self._table_spec.delete(rows) diff --git a/src/View/D90AdisTS/translate.py b/src/View/D90AdisTS/translate.py new file mode 100644 index 0000000000000000000000000000000000000000..5a7bbd755d514a6d628c3828d95883296bf13d95 --- /dev/null +++ b/src/View/D90AdisTS/translate.py @@ -0,0 +1,46 @@ +# translate.py -- Pamhyr +# Copyright (C) 2023-2024 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 <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import QCoreApplication + +from View.Translate import MainTranslate + +_translate = QCoreApplication.translate + + +class D90AdisTSTranslate(MainTranslate): + def __init__(self): + super(D90AdisTSTranslate, self).__init__() + + self._dict["D90 AdisTS"] = _translate( + "D90AdisTS", "D90 AdisTS") + + self._dict["kp"] = self._dict["unit_kp"] + + self._sub_dict["table_headers"] = { + "name": self._dict["name"], + "d90": _translate("Unit", "D90"), + } + + self._sub_dict["table_headers_spec"] = { + "name": self._dict["name"], + "reach": self._dict["reach"], + "start_kp": _translate("Unit", "Start_KP (m)"), + "end_kp": _translate("Unit", "End_KP (m)"), + "d90": _translate("Unit", "D90"), + } diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index 12d9af6798387b768f78f877e3bc8a282b4327d0..c61fae9072100a0ec3c1e952ffa67fe2cb8f2209 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -77,6 +77,7 @@ from View.Results.ReadingResultsDialog import ReadingResultsDialog from View.Debug.Window import ReplWindow from View.OutputKpAdisTS.Window import OutputKpAdisTSWindow from View.Pollutants.Window import PollutantsWindow +from View.D90AdisTS.Window import D90AdisTSWindow # Optional internal display of documentation for make the application # package lighter... @@ -869,17 +870,23 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ############### def open_d90(self): + if len(self._study.river.d90_adists.lst) != 0: + d90_default = self._study.river.d90_adists.lst[0] + else: + d90_default = self._study.river.d90_adists.new(0) + if self.sub_window_exists( - PollutantsWindow, - data=[self._study, None] + D90AdisTSWindow, + data=[self._study, None, d90_default] ): return - Pollutants = PollutantsWindow( + D90AdisTS = D90AdisTSWindow( study=self._study, - parent=self + parent=self, + data=d90_default ) - Pollutants.show() + D90AdisTS.show() def open_pollutants(self): if self.sub_window_exists( diff --git a/src/View/ui/D90AdisTS.ui b/src/View/ui/D90AdisTS.ui new file mode 100644 index 0000000000000000000000000000000000000000..b4fe3e2d6777785e701a5c7771e11d6ce77952af --- /dev/null +++ b/src/View/ui/D90AdisTS.ui @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1024</width> + <height>576</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QWidget" name="layoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"/> + </item> + <item> + <widget class="QTableView" name="tableView"/> + </item> + </layout> + </widget> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QWidget" name="verticalLayoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout_1"/> + </widget> + <widget class="QWidget" name="verticalLayoutWidget_2"> + <layout class="QVBoxLayout" name="verticalLayout_2"/> + </widget> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1024</width> + <height>22</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <widget class="QToolBar" name="toolBar"> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tests_cases/Enlargement/Enlargement.pamhyr b/tests_cases/Enlargement/Enlargement.pamhyr index 9aa6c32eaddadc52309022f8de7ef26e5bb9a78a..ae39194e16d126cba23500f15e4cad5347be997e 100644 Binary files a/tests_cases/Enlargement/Enlargement.pamhyr and b/tests_cases/Enlargement/Enlargement.pamhyr differ