diff --git a/src/Model/River.py b/src/Model/River.py index a2afe35a6a6de3272b41e2c04055a233fccbc803..d95ad699ce120c1b493cacba7374f45f4fc42980 100644 --- a/src/Model/River.py +++ b/src/Model/River.py @@ -10,6 +10,7 @@ from Model.Geometry.Reach import Reach from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList from Model.LateralContribution.LateralContributionList import LateralContributionList from Model.Stricklers.StricklersList import StricklersList +from Model.Section.SectionList import SectionList class RiverNode(Node): def __init__(self, id:str, name:str, @@ -62,6 +63,7 @@ class River(Graph): self._boundary_condition = BoundaryConditionList(status=self._status) self._lateral_contribution = LateralContributionList(status=self._status) self._stricklers = StricklersList(status=self._status) + self._sections = SectionList(status=self._status) @property def boundary_condition(self): @@ -72,9 +74,13 @@ class River(Graph): return self._lateral_contribution @property - def striklers(self): + def stricklers(self): return self._stricklers + @property + def sections(self): + return self._sections + def has_current_reach(self): return self._current_reach is not None diff --git a/src/Model/Section/Section.py b/src/Model/Section/Section.py new file mode 100644 index 0000000000000000000000000000000000000000..d7749a9d84a8615f6f77e2e006c708d3162566f7 --- /dev/null +++ b/src/Model/Section/Section.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +from tools import trace, timer + + +class Section(object): + def __init__(self, name:str = "", status = None): + super(Section, self).__init__() + + self._status = status + + self._name = name + self._edge = None + self._begin_kp = 0.0 + self._end_kp = 0.0 + self._begin_strickler = None + self._end_strickler = None + + @property + def name(self): + return self._name + + @name.setter + def name(self, name): + self._name = name + self._status.modified() + + @property + def edge(self): + return self._edge + + @edge.setter + def edge(self, edge): + self._edge = edge + if (edge is not None and + self._begin_kp == 0.0 and + self._end_kp == 0.0): + self._begin_kp = self._edge.reach.get_kp_min() + self._end_kp = self._edge.reach.get_kp_max() + self._status.modified() + + def has_edge(self): + return self._edge is not None + + @property + def begin_kp(self): + return self._begin_kp + + @begin_kp.setter + def begin_kp(self, begin_kp): + if self._edge is None: + self._begin_kp = begin_kp + else: + _min = self._edge.reach.get_kp_min() + _max = self._edge.reach.get_kp_max() + + if _min <= begin_kp <= _max: + self._begin_kp = begin_kp + + self._status.modified() + + @property + def end_kp(self): + return self._end_kp + + @end_kp.setter + def end_kp(self, end_kp): + if self._edge is None: + self._end_kp = end_kp + else: + _min = self._edge.reach.get_kp_min() + _max = self._edge.reach.get_kp_max() + + if _min <= end_kp <= _max: + self._end_kp = end_kp + + self._status.modified() + + @property + def begin_strickler(self): + return self._begin_strickler + + @begin_strickler.setter + def begin_strickler(self, stricklers): + self._begin_strickler = strickler + self._status.modified() + + @property + def end_strickler(self): + return self._end_strickler + + @end_strickler.setter + def end_strickler(self, stricklers): + self._end_strickler = strickler + self._status.modified() diff --git a/src/Model/Section/SectionList.py b/src/Model/Section/SectionList.py new file mode 100644 index 0000000000000000000000000000000000000000..63d02c45b53fa221d9cc03baea66596bffba4c64 --- /dev/null +++ b/src/Model/Section/SectionList.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +from copy import copy +from tools import trace, timer + +from Model.Section.Section import Section + +class SectionList(object): + def __init__(self, status = None): + super(SectionList, self).__init__() + + self._status = status + self._sections = [] + + def __len__(self): + return len(self._sections) + + @property + def sections(self): + return self._sections.copy() + + def get(self, row): + return self._sections[row] + + def set(self, row, new): + self._sections[row] = new + self._status.modified() + + def new(self, index): + n = Section(self._status) + self._sections.insert(index, n) + self._status.modified() + return n + + def insert(self, index, new): + self._sections.insert(index, new) + self._status.modified() + + def delete(self, sections): + for section in sections: + self._sections.remove(section) + self._status.modified() + + def delete_i(self, indexes): + sections = list( + map( + lambda x: x[1], + filter( + lambda x: x[0] in indexes, + enumerate(self._tabs[lst]) + ) + ) + ) + self.delete(sections) + + def sort(self, reverse=False, key=None): + self._sections.sort(reverse=reverse, key=key) + self._status.modified() + + def move_up(self, index): + if index < len(self._sections): + next = index - 1 + + l = self._sections + l[index], l[next] = l[next], l[index] + self._status.modified() + + def move_down(self, index): + if index >= 0: + prev = index + 1 + + l = self._sections + l[index], l[prev] = l[prev], l[index] + self._status.modified() diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index 5761149b8d3cf9cc91183b2622f0147b567b1560..5c7035303136ec61b3ec63ece7ebcb036a3933cf 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -25,6 +25,7 @@ from View.Geometry.Window import GeometryWindow from View.BoundaryCondition.Window import BoundaryConditionWindow from View.LateralContribution.Window import LateralContributionWindow from View.Stricklers.Window import StricklersWindow +from View.Sections.Window import SectionsWindow from Model.Study import Study @@ -127,6 +128,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): "action_toolBar_lateral_contrib": self.open_lateral_contrib, "action_toolBar_spills": lambda: self.open_dummy("Deversement"), "action_toolBar_stricklers": self.open_stricklers, + "action_toolBar_sections": self.open_sections, "action_toolBar_building": lambda: self.open_dummy("Ouvrages"), } @@ -341,6 +343,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ) self.strick.show() + def open_sections(self): + self.sections = SectionsWindow( + study = self.model, + parent=self + ) + self.sections.show() + # TODO: Delete me ! ############### # DUMMY STUFF # diff --git a/src/View/Sections/Table.py b/src/View/Sections/Table.py new file mode 100644 index 0000000000000000000000000000000000000000..d5385cf4d9254aa22c64c0010c5e405519868501 --- /dev/null +++ b/src/View/Sections/Table.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- + +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.Sections.UndoCommand import ( + SetNameCommand, SetEdgeCommand, + SetBeginCommand, SetEndCommand, + SetBeginStricklerCommand, SetEndStricklerCommand, + AddCommand, DelCommand, SortCommand, + MoveCommand, PasteCommand, DuplicateCommand, +) + +from View.Sections.translate import * + +_translate = QCoreApplication.translate + +class ComboBoxDelegate(QItemDelegate): + def __init__(self, data=None, mode="stricklers", parent=None): + super(ComboBoxDelegate, self).__init__(parent) + + self._data = data + self._mode = mode + + def createEditor(self, parent, option, index): + self.editor = QComboBox(parent) + + if self._mode == "stricklers": + self.editor.addItems( + [_translate("Sections", "Not defined")] + + list( + map( + lambda s: s.name, + self._data.stricklers.stricklers + ) + ) + ) + else: # "edge" + self.editor.addItems( + [_translate("Sections", "Not associate")] + + self._data.edges_names() + ) + + self.editor.setCurrentText(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 and 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 TableModel(QAbstractTableModel): + def __init__(self, data=None, undo=None): + super(QAbstractTableModel, self).__init__() + self._headers = list(table_headers.keys()) + self._data = data + self._undo = undo + self._sections = self._data.sections + + def flags(self, index): + options = Qt.ItemIsEnabled | Qt.ItemIsSelectable + options |= Qt.ItemIsEditable + + return options + + def rowCount(self, parent): + return len(self._sections) + + def columnCount(self, parent): + return len(self._headers) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + row = index.row() + column = index.column() + + if self._headers[column] == "name": + return self._sections.get(row).name + elif self._headers[column] == "edge": + n = self._sections.get(row).edge + if n is None: + return _translate("Sections", "Not associate") + return n.name + elif self._headers[column] == "begin_kp": + return self._sections.get(row).begin_kp + elif self._headers[column] == "end_kp": + return self._sections.get(row).end_kp + elif self._headers[column] == "begin_strickler": + return self._sections.get(row).begin_strickler + elif self._headers[column] == "end_strickler": + return self._sections.get(row).end_strickler + + return QVariant() + + def headerData(self, section, orientation, role): + if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal: + return table_headers[self._headers[section]] + + 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() + + if self._headers[column] == "name": + self._undo.push( + SetNameCommand( + self._sections, row, value + ) + ) + elif self._headers[column] == "edge": + self._undo.push( + SetEdgeCommand( + self._sections, row, self._data.edge(value) + ) + ) + elif self._headers[column] == "begin_kp": + self._undo.push( + SetBeginCommand( + self._sections, row, value + ) + ) + elif self._headers[column] == "end_kp": + self._undo.push( + SetEndCommand( + self._sections, row, value + ) + ) + elif self._headers[column] == "begin_stricklers": + self._undo.push( + SetBeginStricklerCommand( + self._sections, row, value + ) + ) + elif self._headers[column] == "end_stricklers": + self._undo.push( + SetEndStricklerCommand( + self._sections, row, value + ) + ) + + self.dataChanged.emit(index, index) + return True + + def add(self, row, parent=QModelIndex()): + self.beginInsertRows(parent, row, row - 1) + + self._undo.push( + AddCommand( + self._sections, row + ) + ) + + self.endInsertRows() + self.layoutChanged.emit() + + def delete(self, rows, parent=QModelIndex()): + self.beginRemoveRows(parent, rows[0], rows[-1]) + + self._undo.push( + DelCommand( + self._sections, rows + ) + ) + + self.endRemoveRows() + self.layoutChanged.emit() + + def sort(self, _reverse, parent=QModelIndex()): + self.layoutAboutToBeChanged.emit() + + self._undo.push( + SortCommand( + self._sections, False + ) + ) + + self.layoutAboutToBeChanged.emit() + self.layoutChanged.emit() + + def move_up(self, row, parent=QModelIndex()): + if row <= 0: + return + + target = row + 2 + + self.beginMoveRows(parent, row - 1, row - 1, parent, target) + + self._undo_stack.push( + MoveCommand( + self._sections, "up", row + ) + ) + + self.endMoveRows() + self.layoutChanged.emit() + + def move_down(self, index, parent=QModelIndex()): + if row > len(self._sections): + return + + target = row + + self.beginMoveRows(parent, row + 1, row + 1, parent, target) + + self._undo_stack.push( + MoveCommand( + self._sections, "down", row + ) + ) + + self.endMoveRows() + 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/Sections/UndoCommand.py b/src/View/Sections/UndoCommand.py new file mode 100644 index 0000000000000000000000000000000000000000..b6cb445a6be521c008c63434d522b6623ef56fbe --- /dev/null +++ b/src/View/Sections/UndoCommand.py @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- + +from copy import deepcopy +from tools import trace, timer + +from PyQt5.QtWidgets import ( + QMessageBox, QUndoCommand, QUndoStack, +) + +from Model.Section.Section import Section +from Model.Section.SectionList import SectionList + +class SetNameCommand(QUndoCommand): + def __init__(self, sections, index, new_value): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).name + self._new = new_value + + def undo(self): + self._sections.get(self._index).name = self._old + + def redo(self): + self._sections.get(self._index).name = self._new + +class SetBeginCommand(QUndoCommand): + def __init__(self, sections, index, new_value): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).begin_kp + self._new = new_value + + def undo(self): + self._sections.get(self._index).begin_kp = float(self._old) + + def redo(self): + self._sections.get(self._index).begin_kp = float(self._new) + +class SetEndCommand(QUndoCommand): + def __init__(self, sections, index, new_value): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).end_kp + self._new = new_value + + def undo(self): + self._sections.get(self._index).end_kp = float(self._old) + + def redo(self): + self._sections.get(self._index).end_kp = float(self._new) + + +class SetBeginStricklerCommand(QUndoCommand): + def __init__(self, sections, index, new_value): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).begin_strickler + self._new = new_value + + def undo(self): + self._sections.get(self._index).begin_strickler = self._old + + def redo(self): + self._sections.get(self._index).begin_strickler = self._new + +class SetEndStricklerCommand(QUndoCommand): + def __init__(self, sections, index, new_value): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).end_strickler + self._new = new_value + + def undo(self): + self._sections.get(self._index).end_strickler = self._old + + def redo(self): + self._sections.get(self._index).end_strickler = self._new + + +class SetEdgeCommand(QUndoCommand): + def __init__(self, sections, index, edge): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._old = self._sections.get(self._index).edge + self._new = edge + + def undo(self): + self._sections.get(self._index).edge = self._old + + def redo(self): + self._sections.get(self._index).edge = self._new + +class AddCommand(QUndoCommand): + def __init__(self, sections, index): + QUndoCommand.__init__(self) + + self._sections = sections + self._index = index + self._new = None + + def undo(self): + self._sections.delete_i([self._index]) + + def redo(self): + if self._new is None: + self._new = self._sections.new(self._index) + else: + self._sections.insert(self._index, self._new) + +class DelCommand(QUndoCommand): + def __init__(self, sections, rows): + QUndoCommand.__init__(self) + + self._sections = sections + self._rows = rows + + self._section = [] + for row in rows: + self._section.append((row, self._sections.get(row))) + self._section.sort() + + def undo(self): + for row, el in self._section: + self._sections.insert(row, el) + + def redo(self): + self._sections.delete_i(self._rows) + +class SortCommand(QUndoCommand): + def __init__(self, sections, _reverse): + QUndoCommand.__init__(self) + + self._sections = sections + self._reverse = _reverse + + self._old = self._sections.sections + self._indexes = None + + def undo(self): + ll = self._sections.sections + self._sections.sort( + key=lambda x: self._indexes[ll.index(x)] + ) + + def redo(self): + self._sections.sort( + reverse=self._reverse, + key=lambda x: x.name + ) + if self._indexes is None: + self._indexes = list( + map( + lambda p: self._old.index(p), + self._sections.sections + ) + ) + self._old = None + + +class MoveCommand(QUndoCommand): + def __init__(self, sections, up, i): + QUndoCommand.__init__(self) + + self._sections = sections + self._up = up == "up" + self._i = i + + def undo(self): + if self._up: + self._sections.move_up(self._i) + else: + self._sections.move_down(self._i) + + def redo(self): + if self._up: + self._sections.move_up(self._i) + else: + self._sections.move_down(self._i) + + +class PasteCommand(QUndoCommand): + def __init__(self, sections, row, section): + QUndoCommand.__init__(self) + + self._sections = sections + self._row = row + self._section = deepcopy(section) + self._section.reverse() + + def undo(self): + self._sections.delete(self._section) + + def redo(self): + for section in self._section: + self._sections.insert(self._row, section) + + +class DuplicateCommand(QUndoCommand): + def __init__(self, sections, rows, section): + QUndoCommand.__init__(self) + + self._sections = sections + self._rows = rows + self._section = deepcopy(section) + self._section.reverse() + + def undo(self): + self._sections.delete(self._section) + + def redo(self): + for section in self._sections: + self._sections.insert(self._rows[0], section) diff --git a/src/View/Sections/Window.py b/src/View/Sections/Window.py new file mode 100644 index 0000000000000000000000000000000000000000..38337f17bd9dc6e649c91566ca5ac386826db68b --- /dev/null +++ b/src/View/Sections/Window.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- + +from tools import trace, timer + +from View.ASubWindow import ASubMainWindow +from View.ListedSubWindow import ListedSubWindow + +from PyQt5.QtGui import ( + QKeySequence, +) + +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, QVBoxLayout, QHeaderView, QTabWidget, +) + +from View.Sections.UndoCommand import ( + PasteCommand, DuplicateCommand, +) + +from View.Sections.Table import ( + TableModel, ComboBoxDelegate +) + +from View.Plot.MplCanvas import MplCanvas +from View.Geometry.PlotXY import PlotXY +from View.Sections.translate import * + +_translate = QCoreApplication.translate + +class SectionsWindow(ASubMainWindow, ListedSubWindow): + def __init__(self, title="Sections", study=None, parent=None): + title = title + " - " + study.name + + super(SectionsWindow, self).__init__( + name=title, ui="Sections", parent=parent + ) + + self._study = study + self._sections = self._study.river.sections + + self.setup_sc() + self.setup_table() + self.setup_graph() + self.setup_connections() + + self.ui.setWindowTitle(title) + + def setup_sc(self): + self._undo_stack = QUndoStack() + + self.undo_sc = QShortcut(QKeySequence.Undo, self) + self.redo_sc = QShortcut(QKeySequence.Redo, self) + self.copy_sc = QShortcut(QKeySequence.Copy, self) + self.paste_sc = QShortcut(QKeySequence.Paste, self) + + def setup_table(self): + self._table = {} + + table = self.find(QTableView, f"tableView") + self._table = TableModel( + data = self._study.river, + undo = self._undo_stack, + ) + table.setModel(self._table) + + self._delegate_edge = ComboBoxDelegate( + data = self._study.river, + mode = "edge", + parent=self + ) + self._delegate_stricklers = ComboBoxDelegate( + data = self._study.river, + mode = "stricklers", + parent=self + ) + + table.setItemDelegateForColumn( + 1, self._delegate_edge + ) + table.setItemDelegateForColumn( + 4, self._delegate_stricklers + ) + table.setItemDelegateForColumn( + 5, self._delegate_stricklers + ) + + table.setSelectionBehavior(QAbstractItemView.SelectRows) + table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + table.setAlternatingRowColors(True) + + def setup_graph(self): + self.canvas = MplCanvas(width=5, height=4, dpi=100) + self.canvas.setObjectName("canvas") + self.plot_layout = self.find(QVBoxLayout, "verticalLayout") + self.plot_layout.addWidget(self.canvas) + + self.plot = PlotXY( + canvas = self.canvas, + data = None, + toolbar = None, + ) + + def setup_connections(self): + self.find(QAction, "action_add").triggered.connect(self.add) + self.find(QAction, "action_del").triggered.connect(self.delete) + self.find(QAction, "action_sort").triggered.connect(self.sort) + + self.undo_sc.activated.connect(self.undo) + self.redo_sc.activated.connect(self.redo) + self.copy_sc.activated.connect(self.copy) + self.paste_sc.activated.connect(self.paste) + + table = self.find(QTableView, f"tableView") + table.selectionModel()\ + .selectionChanged\ + .connect(self._set_current_reach) + + self._table.dataChanged\ + .connect(self._set_current_reach) + + def index_selected_rows(self): + table = self.find(QTableView, f"tableView") + return list( + # Delete duplicate + set( + map( + lambda i: i.row(), + table.selectedIndexes() + ) + ) + ) + + def _set_current_reach(self): + rows = self.index_selected_rows() + + data = None + highlight = None + + if len(rows) > 0: + edge = self._study\ + .river\ + .sections\ + .get(rows[0])\ + .edge + if edge: + data = edge.reach + sec = self._sections.get(rows[0]) + highlight = (sec.begin_kp, sec.end_kp) + + self.plot = PlotXY( + canvas = self.canvas, + data = data, + toolbar = None, + ) + self.plot.draw(highlight=highlight) + + def add(self): + rows = self.index_selected_rows() + if len(self._sections) == 0 or len(rows) == 0: + self._table.add(0) + else: + self._table.add(rows[0]) + + def delete(self): + rows = self.index_selected_rows() + if len(rows) == 0: + return + + self._table.delete(rows) + + def sort(self): + self._table.sort(False) + + def move_up(self): + row = self.index_selected_row() + self._table.move_up(row) + + def move_down(self): + row = self.index_selected_row() + self._table.move_down(row) + + def copy(self): + print("TODO") + + def paste(self): + print("TODO") + + def undo(self): + self._table.undo() + + def redo(self): + self._table.redo() diff --git a/src/View/Sections/translate.py b/src/View/Sections/translate.py new file mode 100644 index 0000000000000000000000000000000000000000..318c455bc9986b3e990f9c4b531cda182da133ac --- /dev/null +++ b/src/View/Sections/translate.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import QCoreApplication + +_translate = QCoreApplication.translate + +table_headers = { + "name": _translate("Sections", "Name"), + "edge": _translate("Sections", "Reach"), + "begin_kp": _translate("Sections", "Begin kp (m)"), + "end_kp": _translate("Sections", "End kp (m)"), + "begin_strickler": _translate("Sections", "Begin strickler"), + "end_strickler": _translate("Sections", "End strickler"), +} diff --git a/src/View/Stricklers/Window.py b/src/View/Stricklers/Window.py index bae6ccad9f150883fb6475376300eb4c0109d179..be02f4e7649abff99a7ec470f74004e2b68cdbca 100644 --- a/src/View/Stricklers/Window.py +++ b/src/View/Stricklers/Window.py @@ -61,7 +61,7 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow): for t in ["app", "study"]: table = self.find(QTableView, f"tableView_{t}") if t == "study": - data = self._study.river.striklers + data = self._study.river.stricklers else: data = self._config.stricklers diff --git a/src/View/ui/Sections.ui b/src/View/ui/Sections.ui new file mode 100644 index 0000000000000000000000000000000000000000..f714f3753ac1dcda5a20031f8b43e5b6352b41c4 --- /dev/null +++ b/src/View/ui/Sections.ui @@ -0,0 +1,89 @@ +<?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>943</width> + <height>434</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <property name="locale"> + <locale language="English" country="Europe"/> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QTableView" name="tableView"/> + <widget class="QWidget" name="verticalLayoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout"/> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>943</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> + <addaction name="action_add"/> + <addaction name="action_del"/> + <addaction name="action_sort"/> + </widget> + <action name="action_add"> + <property name="icon"> + <iconset> + <normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset> + </property> + <property name="text"> + <string>Add</string> + </property> + </action> + <action name="action_del"> + <property name="icon"> + <iconset> + <normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset> + </property> + <property name="text"> + <string>delete</string> + </property> + </action> + <action name="action_sort"> + <property name="icon"> + <iconset> + <normaloff>ressources/gtk-sort-ascending.png</normaloff>ressources/gtk-sort-ascending.png</iconset> + </property> + <property name="text"> + <string>Sort</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui>