diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py
index d81379322e1c990f4a0d33686a6519de7bab59a8..606b2e2959c6e6ba4baadf99602bcaccf19964ea 100644
--- a/src/Model/Geometry/Profile.py
+++ b/src/Model/Geometry/Profile.py
@@ -56,6 +56,9 @@ class Profile(object):
 
         self._profile_type = _type
 
+    def __len__(self):
+        return len(self._points)
+
     @property
     def number_points(self):
         return len(self._points)
diff --git a/src/View/Geometry/Profile/Plot.py b/src/View/Geometry/Profile/Plot.py
index 076c27031cad042079823ec6ac7e5407d4a6e6e8..12bb9aee1642622ef34788301c2c257a451a7058 100644
--- a/src/View/Geometry/Profile/Plot.py
+++ b/src/View/Geometry/Profile/Plot.py
@@ -19,8 +19,8 @@
 import logging
 
 from tools import timer, trace
-from View.Plot.APlot import APlot
-from View.Plot.mpl_canvas_onpick_event import OnpickEvent
+from View.Tools.PamhyrPlot import PamhyrPlot
+from View.Tools.Plot.OnPickEvent import OnpickEvent
 
 from PyQt5.QtCore import (
     QCoreApplication
@@ -30,12 +30,15 @@ _translate = QCoreApplication.translate
 
 logger = logging.getLogger()
 
-class Plot(APlot):
-    def __init__(self, canvas=None, data=None, toolbar=None, table=None):
+class Plot(PamhyrPlot):
+    def __init__(self, canvas=None, trad=None, data=None, toolbar=None,
+                 table=None, parent=None):
         super(Plot, self).__init__(
-            canvas=canvas,
-            data=data,
-            toolbar=toolbar
+            canvas = canvas,
+            trad = trad,
+            data = data,
+            toolbar = toolbar,
+            parent = parent
         )
 
         self._table = table
diff --git a/src/View/Geometry/Profile/Table.py b/src/View/Geometry/Profile/Table.py
index 2de665aad935b2825dddde4388a9047f1ad790f0..d1a670ac1f468bf70c5c1cd198b083707389756c 100644
--- a/src/View/Geometry/Profile/Table.py
+++ b/src/View/Geometry/Profile/Table.py
@@ -29,10 +29,11 @@ from PyQt5.QtWidgets import (
     QMessageBox, QStyledItemDelegate, QLineEdit
 )
 from PyQt5.QtCore import (
-    QModelIndex, Qt, QAbstractTableModel,
-    QVariant, QCoreApplication
+    QModelIndex, Qt, QVariant, QCoreApplication
 )
 
+from View.Tools.PamhyrTable import PamhyrTableModel
+
 from Model.Geometry.PointXYZ import PointXYZ
 from Model.Geometry.ProfileXYZ import ProfileXYZ
 
@@ -43,43 +44,22 @@ logger = logging.getLogger()
 _translate = QCoreApplication.translate
 
 
-class TableEditableModel(QAbstractTableModel):
-    def __init__(self, profile: ProfileXYZ, header=None, undo=None):
-        QAbstractTableModel.__init__(self)
-
-        self._undo_stack = undo
-        self._profile = profile
-
-        if header is None:
-            self._header = [
-                "X (m)", "Y (m)", "Z (m)",
-                _translate("MainWindowProfile", "Nom"),
-                _translate("MainWindowProfile", "Abs en travers (m)")
-            ]
-        else:
-            self._header = header
-
-    def rowCount(self, parent=QModelIndex()):
-        return self._profile.number_points
-
-    def columnCount(self, parent=QModelIndex()):
-        return len(self._header)
-
+class GeometryProfileTableModel(PamhyrTableModel):
     def data(self, index, role=Qt.DisplayRole):
         if index.isValid():
             if role == Qt.DisplayRole:
                 value = ""
 
                 if index.column() == 0:
-                    value = self._profile.point(index.row()).x
+                    value = self._data.point(index.row()).x
                 elif index.column() == 1:
-                    value = self._profile.point(index.row()).y
+                    value = self._data.point(index.row()).y
                 elif index.column() == 2:
-                    value = self._profile.point(index.row()).z
+                    value = self._data.point(index.row()).z
                 elif index.column() == 3:
-                    value = self._profile.point(index.row()).name
+                    value = self._data.point(index.row()).name
                 elif index.column() == 4:
-                    station = self._profile.get_station()
+                    station = self._data.get_station()
                     if station is None:
                         return "-"
                     else:
@@ -95,25 +75,25 @@ class TableEditableModel(QAbstractTableModel):
                 return Qt.AlignHCenter | Qt.AlignVCenter
 
             if index.column() == 2:
-                value = self._profile.point(index.row()).z
+                value = self._data.point(index.row()).z
                 if role == Qt.ForegroundRole:
-                    if value == self._profile.z_min():
+                    if value == self._data.z_min():
                         return QColor("red")
-                    elif value == self._profile.z_max():
+                    elif value == self._data.z_max():
                         return QColor("blue")
 
                 if role == Qt.ToolTipRole:
-                    if value == self._profile.z_min():
+                    if value == self._data.z_min():
                         return _translate("MainWindowProfile",
                                           "La cote du fond",
                                           "Z minimale")
-                    elif value == self._profile.z_max():
+                    elif value == self._data.z_max():
                         return _translate("MainWindowProfile",
                                           "La cote maximale",
                                           "Z maximale")
 
             if index.column() == 3:
-                value = self._profile.point(index.row()).name
+                value = self._data.point(index.row()).name
 
                 if value.strip().upper() in ["RG", "RD"]:
                     if role == Qt.FontRole:
@@ -132,21 +112,6 @@ class TableEditableModel(QAbstractTableModel):
 
         return QVariant()
 
-    def headerData(self, section, orientation, role=Qt.DisplayRole):
-        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
-            return self._header[section]
-        elif orientation == Qt.Vertical and role == Qt.DisplayRole:
-            return str(section + 1)
-
-        if role == Qt.ToolTipRole and section == 4:
-            return _translate(
-                "MainWindowProfile",
-                "Abscisse en travers calculée en projétant les points"
-                " \nsur le plan défini par les deux points nommés extrêmes "
-            )
-
-        return QVariant()
-
     def setData(self, index, value, role=Qt.EditRole):
         row = index.row()
         column = index.column()
@@ -154,34 +119,34 @@ class TableEditableModel(QAbstractTableModel):
         if role == Qt.EditRole:
             try:
                 if column == 0:
-                    self._undo_stack.push(
+                    self._undo.push(
                         SetXCommand(
-                            self._profile, row,
-                            self._profile.point(row).x,
+                            self._data, row,
+                            self._data.point(row).x,
                             value
                         )
                     )
                 elif column == 1:
-                    self._undo_stack.push(
+                    self._undo.push(
                         SetYCommand(
-                            self._profile, row,
-                            self._profile.point(row).y,
+                            self._data, row,
+                            self._data.point(row).y,
                             value
                         )
                     )
                 elif column == 2:
-                    self._undo_stack.push(
+                    self._undo.push(
                         SetZCommand(
-                            self._profile, row,
-                            self._profile.point(row).z,
+                            self._data, row,
+                            self._data.point(row).z,
                             value
                         )
                     )
                 elif column == 3:
-                    self._undo_stack.push(
+                    self._undo.push(
                         SetNameCommand(
-                            self._profile, row,
-                            self._profile.point(row).name,
+                            self._data, row,
+                            self._data.point(row).name,
                             value
                         )
                     )
@@ -213,9 +178,9 @@ class TableEditableModel(QAbstractTableModel):
     def insert_row(self, row, parent=QModelIndex()):
         self.beginInsertRows(parent, row, row - 1)
 
-        self._undo_stack.push(
+        self._undo.push(
             AddCommand(
-                self._profile, row
+                self._data, row
             )
         )
 
@@ -225,9 +190,9 @@ class TableEditableModel(QAbstractTableModel):
     def remove_rows(self, rows, parent=QModelIndex()):
         self.beginRemoveRows(parent, rows[0], rows[-1])
 
-        self._undo_stack.push(
+        self._undo.push(
             DelCommand(
-                self._profile, rows
+                self._data, rows
             )
         )
 
@@ -239,15 +204,15 @@ class TableEditableModel(QAbstractTableModel):
 
         reverse = (order != Qt.AscendingOrder)
 
-        self._undo_stack.push(
+        self._undo.push(
             SortCommand(
-                self._profile, column, reverse
+                self._data, column, reverse
             )
         )
 
         self.layoutChanged.emit()
 
-    def move_row_up(self, row, parent=QModelIndex()):
+    def move_up(self, row, parent=QModelIndex()):
         if row <= 0:
             return
 
@@ -255,26 +220,26 @@ class TableEditableModel(QAbstractTableModel):
 
         self.beginMoveRows(parent, row - 1, row - 1, parent, target)
 
-        self._undo_stack.push(
+        self._undo.push(
             MoveCommand(
-                self._profile, "up", row
+                self._data, "up", row
             )
         )
 
         self.endMoveRows()
         self.layoutChanged.emit()
 
-    def move_row_down(self, row_to_move, parent=QModelIndex()):
-        if row > self._profile.number_points:
+    def move_down(self, row_to_move, parent=QModelIndex()):
+        if row > self._data.number_points:
             return
 
         target = row
 
         self.beginMoveRows(parent, row + 1, row + 1, parent, target)
 
-        self._undo_stack.push(
+        self._undo.push(
             MoveCommand(
-                self._profile, "down", row
+                self._data, "down", row
             )
         )
 
@@ -282,7 +247,7 @@ class TableEditableModel(QAbstractTableModel):
         self.layoutChanged.emit()
 
     def paste(self, row, header, data):
-        if row > self._profile.number_points:
+        if row > self._data.number_points:
             return
 
         if len(data) == 0:
@@ -290,12 +255,12 @@ class TableEditableModel(QAbstractTableModel):
 
         self.layoutAboutToBeChanged.emit()
 
-        self._undo_stack.push(
+        self._undo.push(
             PasteCommand(
-                self._profile, row,
+                self._data, row,
                 list(
                     map(
-                        lambda d: self._profile.point_from_data(header, d),
+                        lambda d: self._data.point_from_data(header, d),
                         data
                     )
                 )
@@ -306,32 +271,9 @@ class TableEditableModel(QAbstractTableModel):
         self.layoutChanged.emit()
 
     def undo(self):
-        self._undo_stack.undo()
+        self._undo.undo()
         self.layoutChanged.emit()
 
     def redo(self):
-        self._undo_stack.redo()
+        self._undo.redo()
         self.layoutChanged.emit()
-
-
-class Delegate(QStyledItemDelegate):
-    def __init__(self, parent=None, setModelDataEvent=None):
-        super(Delegate, self).__init__(parent)
-        self.setModelDataEvent = setModelDataEvent
-
-    def createEditor(self, parent, option, index):
-        index.model().data(index, Qt.DisplayRole)
-        return QLineEdit(parent)
-
-    def setEditorData(self, editor, index):
-        value = index.model().data(index, Qt.DisplayRole)
-        editor.setText(str(value))
-
-    def setModelData(self, editor, model, index):
-        model.setData(index, editor.text())
-
-        if not self.setModelDataEvent is None:
-            self.setModelDataEvent()
-
-    def updateEditorGeometry(self, editor, option, index):
-        editor.setGeometry(option.rect)
diff --git a/src/View/Geometry/Profile/Translate.py b/src/View/Geometry/Profile/Translate.py
new file mode 100644
index 0000000000000000000000000000000000000000..148426aa453ccd9191b0ed85bbb654b04d0ff998
--- /dev/null
+++ b/src/View/Geometry/Profile/Translate.py
@@ -0,0 +1,36 @@
+# Translate.py -- Pamhyr
+# Copyright (C) 2023  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.Tools.PamhyrTranslate import PamhyrTranslate
+from View.Geometry.Translate import GeometryTranslate
+
+_translate = QCoreApplication.translate
+
+class GeometryProfileTranslate(GeometryTranslate):
+    def __init__(self):
+        super(GeometryProfileTranslate, self).__init__()
+
+        self._sub_dict["table_headers"] = {
+            "x": _translate("Geometry", "X (m)"),
+            "y": _translate("Geometry", "Y (m)"),
+            "z": _translate("Geometry", "Z (m)"),
+            "name": _translate("Geometry", "Name"),
+            "abs": _translate("Geometry", "Traversal abs (m)"),
+        }
diff --git a/src/View/Geometry/Profile/Window.py b/src/View/Geometry/Profile/Window.py
index eca6e7af14d99969d7df05e744b240ac922fbade..90fe1f44b054efea646e54ad4ebe4a0116a67405 100644
--- a/src/View/Geometry/Profile/Window.py
+++ b/src/View/Geometry/Profile/Window.py
@@ -31,206 +31,184 @@ from PyQt5.QtCore import (
 )
 from PyQt5.QtWidgets import (
     QApplication, QMainWindow, QFileDialog, QCheckBox,
-    QUndoStack, QShortcut,
+    QUndoStack, QShortcut, QTableView, QAbstractItemView,
+    QHeaderView, QVBoxLayout, QAction,
 )
 
 from Model.Geometry.Reach import Reach
 from Model.Geometry.ProfileXYZ import ProfileXYZ
 
-from View.Tools.ASubWindow import ASubMainWindow
+from View.Tools.PamhyrWindow import PamhyrWindow
+from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
+from View.Tools.Plot.PamhyrCanvas import MplCanvas
 
-from View.Geometry.Profile.mainwindow_ui_profile import Ui_MainWindow
 from View.Geometry.Profile.Plot import Plot
-from View.Geometry.Profile.Table import *
+from View.Geometry.Profile.Table import GeometryProfileTableModel
+from View.Geometry.Profile.Translate import GeometryProfileTranslate
 
 _translate = QCoreApplication.translate
 
 
-class ProfileWindow(ASubMainWindow):
-    def __init__(self, profile=None, title="Profile", parent=None):
-        self._title = title
-        self.parent = parent
-        super(ProfileWindow, self).__init__(
-            name=self._title,
-            parent=self.parent
-        )
-
-        self.ui = Ui_MainWindow()
-        self.ui.setupUi(self)
+class ProfileWindow(PamhyrWindow):
+    _pamhyr_ui = "GeometryCrossSection"
+    _pamhyr_name = "Geometry cross-section"
 
+    def __init__(self, profile=None, study=None, config=None, parent=None):
         self._profile = profile
-        self._model = None
-
-        self.setup_window()
-        self.setup_sc()
-        self.setup_model()
-        self.setup_connections()
-        self.plot()
-
-        self._model.dataChanged.connect(self.update_plot)
-        self.fileName = None
-
-        # self.ui.tableView.installEventFilter(self)
-        # self._model.dataChanged.connect(self.tableview_is_modified)
-
-        # self.ui.btn_go_back.setEnabled(False)
-        # self.ui.btn_check.setEnabled(False)
-        # self._model.dataChanged.connect(self.set_enable_cancel_btn)
-        # self._model.dataChanged.connect(self.set_enable_validate_changes_btn)
-        # self.ui.btn_reset.setEnabled(False)
-        # self._model.dataChanged.connect(self.set_enable_go_back_initial_state_btn)
-
-    def setup_window(self):
-        header = _translate("MainWindowProfile", "Profile")
-
-        name = self._profile.name
-        if (name is None) or (name == ""):
-            name = _translate("MainWindowProfile", "(no name)")
 
-        self._title = (
-            header + " - " +
-            f"{self._profile.reach.name}" + " - " +
-            f"{name} ({self._profile.kp})"
+        name = f"{self._pamhyr_name} - {self._profile.name} {self._profile.kp}"
+        super(ProfileWindow, self).__init__(
+            title = name,
+            study = study,
+            config = config,
+            trad = GeometryProfileTranslate(),
+            parent = parent
         )
 
-        self.setWindowTitle(self._title)
-
-    def setup_sc(self):
-        self._undo_stack = QUndoStack()
+        self.setup_table()
+        self.setup_plot()
+        self.setup_connections()
 
-        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):
+        table_headers = self._trad.get_dict("table_headers")
 
-    def setup_model(self):
-        self._model = TableEditableModel(
-            profile = self._profile,
+        table = self.find(QTableView, "tableView")
+        self._tablemodel = GeometryProfileTableModel(
+            table_view = table,
+            table_headers = table_headers,
+            editable_headers = ["name", "x", "y", "z"],
+            data = self._profile,
             undo = self._undo_stack
         )
-
-        self.ui.tableView.setModel(self._model)
-        self.ui.tableView.setItemDelegate(Delegate())
-
-    def setup_connections(self):
-        self.ui.btn_sort_asc_x.triggered.connect(self.sort_X_ascending)
-        self.ui.btn_sort_desc_x.triggered.connect(self.sort_X_descending)
-        self.ui.btn_sort_asc_y.triggered.connect(self.sort_Y_ascending)
-        self.ui.btn_sort_desc_y.triggered.connect(self.sort_Y_descending)
-        self.ui.btn_move_up.triggered.connect(self.move_row_up)
-        self.ui.btn_move_down.triggered.connect(self.move_row_down)
-        self.ui.btn_export.triggered.connect(self.handleSave)
-        self.ui.btn_add.triggered.connect(self.insert_row)
-        self.ui.btn_delete.triggered.connect(self.delete_row)
-        # self.ui.btn_copy.clicked.connect(self.copyTable)
-        # self.ui.btn_paste.clicked.connect(self.pasteTable)
-        # self.ui.btn_check.clicked.connect(self.validate_changes)
-        # self.ui.btn_go_back.clicked.connect(self.cancel_validate_changes)
-        # self.ui.btn_reset.clicked.connect(self.go_back_to_initial_state)
-
-        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)
-
-    def plot(self):
-        self.ui.tableView.model().blockSignals(True)
+        table.setModel(self._tablemodel)
+        table.setSelectionBehavior(QAbstractItemView.SelectRows)
+        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
+        table.setAlternatingRowColors(True)
+
+    def setup_plot(self):
+        self._tablemodel.blockSignals(True)
+
+        self._canvas = MplCanvas(width=3, height=4, dpi=100)
+        self._canvas.setObjectName("canvas")
+        self._toolbar = PamhyrPlotToolbar(
+            self._canvas, self,
+            items = ["home", "zoom", "save", "iso", "back/forward", "move"]
+        )
+        self._plot_layout = self.find(QVBoxLayout, "verticalLayout")
+        self._plot_layout.addWidget(self._toolbar)
+        self._plot_layout.addWidget(self._canvas)
 
         self._plot = Plot(
-            canvas = self.ui.canvas,
+            canvas = self._canvas,
             data = self._profile,
-            toolbar = None,
-            table = self.ui.tableView,
+            toolbar = self._toolbar,
+            table = self.find(QTableView, "tableView")
         )
         self._plot.draw()
 
-        self.ui.tableView.model().blockSignals(False)
+        self._tablemodel.blockSignals(False)
+
+    def setup_connections(self):
+        actions = {
+            "action_sort_asc": self.sort_X_ascending,
+            "action_sort_des": self.sort_X_descending,
+            "action_up": self.move_up,
+            "action_down": self.move_down,
+            "action_add": self.add,
+            "action_delete": self.delete,
+        }
+
+        for action in actions:
+            self.find(QAction, action)\
+                .triggered.connect(actions[action])
+
+        self._tablemodel.dataChanged.connect(self.update_plot)
 
     def update_plot(self):
-        self.ui.tableView.model().blockSignals(True)
+        self._tablemodel.blockSignals(True)
 
         # TODO: Do not rebuild all graph
         self._plot.update()
 
-        self.ui.tableView.model().blockSignals(False)
+        self._tablemodel.blockSignals(False)
 
     def index_selected_row(self):
-        rows = self.ui.tableView\
+        rows = self._tablemodel\
                       .selectionModel()\
                       .selectedRows()
         if len(rows) == 0:
             return 0
 
-        return self.ui.tableView\
+        return self._tablemodel\
                       .selectionModel()\
                       .selectedRows()[0]\
                       .row()
 
-    def insert_row(self):
-        if len(self.ui.tableView.selectedIndexes()) == 0:
-            self._model.insert_row(self._model.rowCount())
+    def add(self):
+        if len(self._tablemodel.selectedIndexes()) == 0:
+            self._tablemodel.insert_row(self._tablemodel.rowCount())
         else:
             row = self.index_selected_row()
-            self._model.insert_row(row + 1)
+            self._tablemodel.insert_row(row + 1)
         self.update_plot()
 
-    def delete_row(self):
+    def delete(self):
         rows = sorted(
             list(
                 set(
-                    [index.row() for index in self.ui.tableView.selectedIndexes()]
+                    [index.row() for index in self._tablemodel.selectedIndexes()]
                 )
             )
         )
 
         if len(rows) > 0:
-            self._model.remove_rows(rows)
+            self._tablemodel.remove_rows(rows)
             self.update_plot()
 
     def sort_X_ascending(self):
-        self._model.sort('x', order=Qt.AscendingOrder)
+        self._tablemodel.sort('x', order=Qt.AscendingOrder)
         self.update_plot()
 
     def sort_X_descending(self):
-        self._model.sort('x', order=Qt.DescendingOrder)
+        self._tablemodel.sort('x', order=Qt.DescendingOrder)
         self.update_plot()
 
     def sort_Y_ascending(self):
-        self._model.sort('y', order=Qt.AscendingOrder)
+        self._tablemodel.sort('y', order=Qt.AscendingOrder)
         self.update_plot()
 
     def sort_Y_descending(self):
-        self._model.sort('y', order=Qt.DescendingOrder)
+        self._tablemodel.sort('y', order=Qt.DescendingOrder)
         self.update_plot()
 
-    def move_row_down(self):
+    def move_down(self):
         rows = list(
             set(
-                [index.row() for index in self.ui.tableView.selectedIndexes()]
+                [index.row() for index in self._tablemodel.selectedIndexes()]
             )
         )
 
         for row in rows:
-            if row < self._model.rowCount() - 1:
-                self._model.move_row_down(row)
+            if row < self._tablemodel.rowCount() - 1:
+                self._tablemodel.move_down(row)
 
         self.update_plot()
 
-    def move_row_up(self):
+    def move_up(self):
         rows = list(
             set(
-                [index.row() for index in self.ui.tableView.selectedIndexes()]
+                [index.row() for index in self._tablemodel.selectedIndexes()]
             )
         )
 
         for row in rows:
             if 0 < row:
-                self._model.move_row_up(row)
+                self._tablemodel.move_up(row)
 
         self.update_plot()
 
     def copy(self):
-        rows = self.ui.tableView\
+        rows = self._tablemodel\
                       .selectionModel()\
                       .selectedRows()
         table = []
@@ -258,136 +236,13 @@ class ProfileWindow(ASubMainWindow):
             row.append(self._profile)
 
         row = self.index_selected_row()
-        self._model.paste(row, header, data)
+        self._tablemodel.paste(row, header, data)
         self.update_plot()
 
     def undo(self):
-        self._model.undo()
+        self._tablemodel.undo()
         self.update_plot()
 
     def redo(self):
-        self._model.redo()
+        self._tablemodel.redo()
         self.update_plot()
-
-    def handleSave(self):
-        if self.fileName is None or self.fileName == '':
-            self.fileName, self.filters = QFileDialog.getSaveFileName(
-                self, filter="CSV files (*.csv)"
-            )
-
-        if self.fileName != '':
-            with open(self.fileName, 'w') as stream:
-                csvout = csv.writer(stream, delimiter='\t', quotechar=' ',
-                                    escapechar=None,
-                                    quoting=csv.QUOTE_NONNUMERIC,
-                                    lineterminator='\n')
-
-                for row in range(self._model.rowCount(QModelIndex())):
-                    rowdata = []
-                    for column in range(self._model.columnCount(QModelIndex())):
-                        item = self._model.index(
-                            row, column, QModelIndex()
-                        ).data(Qt.DisplayRole)
-
-                        if item is not None:
-                            rowdata.append(item)
-
-                        if item == 'nan':
-                            rowdata.remove(item)
-
-                    csvout.writerow(rowdata)
-
-    def handleOpen(self):
-        self.fileName, self.filterName = QFileDialog.getOpenFileName(self)
-
-        if self.fileName != '':
-            with open(self.fileName, 'r') as f:
-                reader = csv.reader(f, delimiter='\t')
-                header = next(reader)
-
-                buf = []
-                for row in reader:
-                    row[0] = QCheckBox("-")
-                    buf.append(row)
-
-                self._model = None
-                self._model = TableEditableModel(buf)
-                self.ui.tableView.setModel(self._model)
-                self.fileName = ''
-
-    def set_enable_validate_changes_btn(self):
-        self.ui.btn_check.setEnabled(True)
-
-    def set_enable_cancel_btn(self):
-        self.ui.btn_go_back.setEnabled(True)
-
-    def set_enable_go_back_initial_state_btn(self):
-        self.ui.btn_reset.setEnabled(True)
-
-    def delete_empty_rows(self):
-        if self._model.data_contains_nan():
-            buttonReply = QtWidgets.QMessageBox.question(
-                self,
-                _translate("MainWindowProfile",
-                           "Suppression les lignes incomplètes"),
-                _translate("MainWindowProfile",
-                           "Supprimer les lignes des cellules"
-                           " non renseignées ?"),
-                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
-            )
-
-            if buttonReply == QtWidgets.QMessageBox.Yes:
-                self._model.delete_empty_rows()
-
-            if buttonReply == QtWidgets.QMessageBox.No:
-                pass
-
-    def remove_duplicates_point_names(self):
-        counter_list = []
-        list_deleted_names = []
-
-        for ind, name_point in enumerate(self._model.name):
-            if name_point not in counter_list:
-                counter_list.append(name_point)
-            elif len(name_point.strip()) > 0 and name_point in counter_list:
-                if name_point not in list_deleted_names:
-                    list_deleted_names.append(name_point)
-
-        if list_deleted_names:
-            self.msg_box_check_duplication_names(list_deleted_names)
-
-    def msg_box_check_duplication_names(self, list_deleted_names):
-        if len(list_deleted_names) == 1:
-            text = _translate("MainWindowProfile",
-                              "Le nom ''{}'' est dupliqué."
-                              " \n\nYes : Ne garder que la première occurrence. \nNo :"
-                              " Annuler la suppression.".format(list_deleted_names[0]))
-        else:
-            text = _translate("MainWindowProfile",
-                              "Les noms suivants :  \n{} sont dupliqués"
-                              "  \n\nYes : Ne garder que la première occurrence de "
-                              "chaque nom. \nNo :"
-                              " Annuler la suppression.".format(list_deleted_names))
-
-        buttonReply = QtWidgets.QMessageBox.question(
-            self, _translate("MainWindowProfile",
-                             "Suppression des noms répétés"),
-            text,
-            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
-        )
-
-        if buttonReply == QtWidgets.QMessageBox.Yes:
-            self._model.remove_duplicates_names()
-
-    def ask_quit(self):
-        choice = QtWidgets.QMessageBox.question(
-            self,
-            _translate("MainWindowProfile", "Quittez ?"),
-            _translate("MainWindowProfile",
-                       "Etes-vous sûr de vouloir quitter ?"),
-            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
-        )
-        return choice == QtWidgets.QMessageBox.Yes
-
-    def initial_state_model(self, profile_initial_state):
-        return profile_initial_state
diff --git a/src/View/Geometry/Table.py b/src/View/Geometry/Table.py
index 0ff5e0c871a6edda6104beb9c4681181b168d482..89fafafa7f47430912bcedfaaf40a732dc877277 100644
--- a/src/View/Geometry/Table.py
+++ b/src/View/Geometry/Table.py
@@ -46,7 +46,7 @@ logger = logging.getLogger()
 _translate = QCoreApplication.translate
 
 
-class TableEditableModel(PamhyrTableModel):
+class GeometryReachTableModel(PamhyrTableModel):
     def data(self, index, role=Qt.DisplayRole):
         if not index.isValid():
             return QVariant()
@@ -223,62 +223,3 @@ class TableEditableModel(PamhyrTableModel):
 
         self.layoutAboutToBeChanged.emit()
         self.layoutChanged.emit()
-
-# TODO: Delete useless delegate
-class Delegate(QStyledItemDelegate):
-    def __init__(self, parent=None, setModelDataEvent=None):
-        super(Delegate, self).__init__(parent)
-        self.setModelDataEvent = setModelDataEvent
-
-    def createEditor(self, parent, option, index):
-        index.model().data(index, Qt.DisplayRole)
-        return QLineEdit(parent)
-
-    def setEditorData(self, editor, index):
-        value = index.model().data(index, Qt.DisplayRole)
-        editor.setText(str(value))
-
-    def setModelData(self, editor, model, index):
-        model.setData(index, editor.text())
-
-        if not self.setModelDataEvent is None:
-            self.setModelDataEvent()
-
-    def updateEditorGeometry(self, editor, option, index):
-        editor.setGeometry(option.rect)
-
-class Delegate1(QStyledItemDelegate):
-    def __init__(self, owner, choices):
-        super().__init__(owner)
-        self.items = choices
-
-    def paint(self, painter, option, index):
-        if isinstance(self.parent(), QAbstractItemView):
-            self.parent().openPersistentEditor(index)
-        super(Delegate1, self).paint(painter, option, index)
-
-    def createEditor(self, parent, option, index):
-        editor = QComboBox(parent)
-        # editor.currentIndexChanged.connect(self.commit_editor)
-        editor.addItems(self.items)
-        return editor
-
-    def setEditorData(self, editor, index):
-        editor.blockSignals(True)
-        text = index.model().data(index, Qt.DisplayRole)
-        try:
-            i = self.items.index(text)
-        except ValueError:
-            i = 0
-        editor.setCurrentIndex(i)
-        editor.blockSignals(False)
-
-    def setModelData(self, editor, model, index):
-        model.setData(index, editor.currentText(), Qt.DisplayRole)
-
-    def updateEditorGeometry(self, editor, option, index):
-        editor.setGeometry(option.rect)
-
-    @pyqtSlot()
-    def currentIndexChanged(self):
-        self.commitData.emit(self.sender())
diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py
index 1b334bb724f024ec5fef0e3f979cdc08a15b2ca1..2fccde41ab74c8754038ca2c51cb162b9dc132aa 100644
--- a/src/View/Geometry/Window.py
+++ b/src/View/Geometry/Window.py
@@ -39,17 +39,16 @@ from PyQt5.QtWidgets import (
     QLabel,
 )
 
-from View.Geometry.PlotXY import PlotXY
-from View.Geometry.PlotKPZ import PlotKPZ
-from View.Geometry.PlotAC import PlotAC
-
 from View.Tools.PamhyrWindow import PamhyrWindow
 from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
 from View.Tools.Plot.PamhyrCanvas import MplCanvas
 
-from View.Geometry.Table import *
+from View.Geometry.Table import GeometryReachTableModel
+from View.Geometry.PlotXY import PlotXY
+from View.Geometry.PlotAC import PlotAC
+from View.Geometry.PlotKPZ import PlotKPZ
 from View.Geometry.Translate import GeometryTranslate
-# from View.Geometry.Profile.Window import ProfileWindow
+from View.Geometry.Profile.Window import ProfileWindow
 
 _translate = QCoreApplication.translate
 
@@ -87,7 +86,7 @@ class GeometryWindow(PamhyrWindow):
         table_headers = self._trad.get_dict("table_headers")
 
         table = self.find(QTableView, "tableView")
-        self._tablemodel = TableEditableModel(
+        self._tablemodel = GeometryReachTableModel(
             table_view = table,
             table_headers = table_headers,
             editable_headers = ["name", "kp"],
diff --git a/src/View/ui/GeometryCrossSection.ui b/src/View/ui/GeometryCrossSection.ui
index b0c12393d47714d27691d2701903f2d6b82374d0..67e06ced43a183d980eed8d1f03f523d9678c63b 100644
--- a/src/View/ui/GeometryCrossSection.ui
+++ b/src/View/ui/GeometryCrossSection.ui
@@ -51,8 +51,8 @@
    </attribute>
    <addaction name="action_add"/>
    <addaction name="action_delete"/>
-   <addaction name="action_sort"/>
-   <addaction name="action_resort"/>
+   <addaction name="action_sort_asc"/>
+   <addaction name="action_sort_des"/>
    <addaction name="action_up"/>
    <addaction name="action_down"/>
   </widget>
@@ -104,25 +104,25 @@
     <string>Mode down selected point(s)</string>
    </property>
   </action>
-  <action name="action_sort">
+  <action name="action_sort_asc">
    <property name="icon">
     <iconset>
      <normaloff>ressources/gtk-sort-ascending.png</normaloff>ressources/gtk-sort-ascending.png</iconset>
    </property>
    <property name="text">
-    <string>sort</string>
+    <string>sort_asc</string>
    </property>
    <property name="toolTip">
     <string>Sort points by nearest neighbor</string>
    </property>
   </action>
-  <action name="action_resort">
+  <action name="action_sort_des">
    <property name="icon">
     <iconset>
      <normaloff>ressources/gtk-sort-descending.png</normaloff>ressources/gtk-sort-descending.png</iconset>
    </property>
    <property name="text">
-    <string>resort</string>
+    <string>sort_des</string>
    </property>
    <property name="toolTip">
     <string>Sort reversed points by nearest neighbor</string>