Section: Add code base.

mesh
Pierre-Antoine Rouby 2023-05-24 16:47:41 +02:00
parent 3b2a41e0e9
commit d6c1633b28
10 changed files with 968 additions and 2 deletions

View File

@ -10,6 +10,7 @@ from Model.Geometry.Reach import Reach
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
from Model.LateralContribution.LateralContributionList import LateralContributionList from Model.LateralContribution.LateralContributionList import LateralContributionList
from Model.Stricklers.StricklersList import StricklersList from Model.Stricklers.StricklersList import StricklersList
from Model.Section.SectionList import SectionList
class RiverNode(Node): class RiverNode(Node):
def __init__(self, id:str, name:str, def __init__(self, id:str, name:str,
@ -62,6 +63,7 @@ class River(Graph):
self._boundary_condition = BoundaryConditionList(status=self._status) self._boundary_condition = BoundaryConditionList(status=self._status)
self._lateral_contribution = LateralContributionList(status=self._status) self._lateral_contribution = LateralContributionList(status=self._status)
self._stricklers = StricklersList(status=self._status) self._stricklers = StricklersList(status=self._status)
self._sections = SectionList(status=self._status)
@property @property
def boundary_condition(self): def boundary_condition(self):
@ -72,9 +74,13 @@ class River(Graph):
return self._lateral_contribution return self._lateral_contribution
@property @property
def striklers(self): def stricklers(self):
return self._stricklers return self._stricklers
@property
def sections(self):
return self._sections
def has_current_reach(self): def has_current_reach(self):
return self._current_reach is not None return self._current_reach is not None

View File

@ -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()

View File

@ -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()

View File

@ -25,6 +25,7 @@ from View.Geometry.Window import GeometryWindow
from View.BoundaryCondition.Window import BoundaryConditionWindow from View.BoundaryCondition.Window import BoundaryConditionWindow
from View.LateralContribution.Window import LateralContributionWindow from View.LateralContribution.Window import LateralContributionWindow
from View.Stricklers.Window import StricklersWindow from View.Stricklers.Window import StricklersWindow
from View.Sections.Window import SectionsWindow
from Model.Study import Study from Model.Study import Study
@ -127,6 +128,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_toolBar_lateral_contrib": self.open_lateral_contrib, "action_toolBar_lateral_contrib": self.open_lateral_contrib,
"action_toolBar_spills": lambda: self.open_dummy("Deversement"), "action_toolBar_spills": lambda: self.open_dummy("Deversement"),
"action_toolBar_stricklers": self.open_stricklers, "action_toolBar_stricklers": self.open_stricklers,
"action_toolBar_sections": self.open_sections,
"action_toolBar_building": lambda: self.open_dummy("Ouvrages"), "action_toolBar_building": lambda: self.open_dummy("Ouvrages"),
} }
@ -341,6 +343,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
) )
self.strick.show() self.strick.show()
def open_sections(self):
self.sections = SectionsWindow(
study = self.model,
parent=self
)
self.sections.show()
# TODO: Delete me ! # TODO: Delete me !
############### ###############
# DUMMY STUFF # # DUMMY STUFF #

254
src/View/Sections/Table.py Normal file
View File

@ -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()

View File

@ -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)

201
src/View/Sections/Window.py Normal file
View File

@ -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()

View File

@ -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"),
}

View File

@ -61,7 +61,7 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow):
for t in ["app", "study"]: for t in ["app", "study"]:
table = self.find(QTableView, f"tableView_{t}") table = self.find(QTableView, f"tableView_{t}")
if t == "study": if t == "study":
data = self._study.river.striklers data = self._study.river.stricklers
else: else:
data = self._config.stricklers data = self._config.stricklers

89
src/View/ui/Sections.ui Normal file
View File

@ -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>