diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py
index b67ba0a66dd0023fdbab7bf38d8241ee1c83baa3..9c113582cfadd3887413ee4b9ff78cbd13d0c8ea 100644
--- a/src/Model/Geometry/Reach.py
+++ b/src/Model/Geometry/Reach.py
@@ -8,7 +8,7 @@ from copy import deepcopy
 from operator import itemgetter
 from functools import reduce
 
-from tools import flatten, timer
+from tools import flatten, timer, trace
 
 from Model.Geometry.Profile import Profile
 from Model.Geometry.ProfileXYZ import ProfileXYZ
@@ -99,6 +99,19 @@ class Reach:
         self._profiles.insert(index, profile)
         self._update_profile_numbers()
 
+    def insert_profile(self, index: int, profile: Profile):
+        """Insert new profile in list
+
+        Args:
+            index: The position of the new profile.
+
+        Returns:
+            Nothing.
+        """
+        self._profiles.insert(index, profile)
+        self._update_profile_numbers()
+
+
     def delete(self, list_index: list):
         """Delete some elements in profile list
 
@@ -124,13 +137,6 @@ class Reach:
             else:
                 raise TypeError(f"{list_index} is instance of unexpected type '{type(list_index)}'")
 
-    def sort(self, is_reversed: bool = False):
-        self._profiles = sorted(
-            self._profiles,
-            key=lambda profile: profile.kp,
-            reverse=is_reversed
-        )
-
     def get_x(self):
         return [profile.x() for profile in self.profiles]
 
@@ -270,22 +276,28 @@ class Reach:
 
     # Sort
 
-    def sort_ascending(self):
-        """Sort profiles by increasing KP
-
-        Returns:
-            Nothing.
-        """
-        self._sort(is_reversed=False)
-
-    def sort_descending(self):
-        """Sort profiles by decreasing KP
+    @timer
+    def sort(self, is_reversed: bool = False):
+        self._profiles = sorted(
+            self._profiles,
+            key=lambda profile: profile.kp,
+            reverse=is_reversed
+        )
 
-        Returns:
-            Nothing.
-        """
-        self._sort(is_reversed=True)
+    @timer
+    def sort_with_indexes(self, indexes: list):
+        if len(self._profiles) != len(indexes):
+            print("TODO: CRITICAL ERROR!")
 
+        self._profiles = list(
+            map(
+                lambda x: x[1],
+                sorted(
+                    enumerate(self.profiles),
+                    key=lambda x: indexes[x[0]]
+                )
+            )
+        )
 
     # Copy/Paste
 
diff --git a/src/View/Geometry/GeometryWindow.py b/src/View/Geometry/GeometryWindow.py
index ffdc1eb8e67aa6f3d1807b99cc7eaea3fc5cf571..b97840201bf349917c826ece448bb0e0c7c88a1f 100644
--- a/src/View/Geometry/GeometryWindow.py
+++ b/src/View/Geometry/GeometryWindow.py
@@ -28,6 +28,9 @@ from View.ASubWindow import WindowToolKit
 
 _translate = QCoreApplication.translate
 
+
+
+
 class GeometryWindow(QMainWindow, WindowToolKit):
     def __init__(self, model=None, parent=None):
         self.parent = parent
@@ -47,6 +50,7 @@ class GeometryWindow(QMainWindow, WindowToolKit):
         self.setup_window()
         self.setup_model()
         self.setup_plots()
+        # self.setup_undo()
         self.setup_connections()
         self.changed_slider_value()
 
@@ -67,6 +71,12 @@ class GeometryWindow(QMainWindow, WindowToolKit):
             self.plot_kpc()
             self.plot_ac()
 
+    # def setup_undo(self):
+        # self.undoAction = self.undoStack.createUndoAction(self, self.tr("&Undo"))
+        # self.undoAction.setShortcuts(QKeySequence.Undo)
+        # self.redoAction = self.undoStack.createRedoAction(self, self.tr("&Redo"))
+        # self.redoAction.setShortcuts(QKeySequence.Redo)
+
     def setup_connections(self):
         self.ui.btn_open.clicked.connect(self.open_file_dialog)
         self.ui.btn_sort_asc.clicked.connect(self.sort_ascending)
diff --git a/src/View/Geometry/ReachUndoCommand.py b/src/View/Geometry/ReachUndoCommand.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c1171c03ec5ad71f4510ea30038255cf160fe4e
--- /dev/null
+++ b/src/View/Geometry/ReachUndoCommand.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+from tools import trace, timer
+
+from PyQt5.QtWidgets import (
+    QMessageBox, QUndoCommand, QUndoStack,
+)
+
+from Model.Geometry import Reach
+
+
+class SetDataCommand(QUndoCommand):
+    def __init__(self, reach, index, old_value, new_value):
+        QUndoCommand.__init__(self)
+
+        self._reach = reach
+        self._index = index
+        self._old = old_value
+        self._new = new_value
+
+class SetNameCommand(SetDataCommand):
+    def undo(self):
+        self._reach.profile(self._index).name = self._old
+
+    def redo(self):
+        self._reach.profile(self._index).name = self._new
+
+class SetKPCommand(SetDataCommand):
+    def undo(self):
+        self._reach.profile(self._index).kp = self._old
+
+    def redo(self):
+        self._reach.profile(self._index).kp = self._new
+
+
+class AddCommand(QUndoCommand):
+    def __init__(self, reach, index):
+        QUndoCommand.__init__(self)
+
+        self._reach = reach
+        self._index = index
+
+    def undo(self):
+        self._reach.delete([self._index])
+
+    def redo(self):
+        self._reach.insert(self._index)
+
+class DelCommand(QUndoCommand):
+    def __init__(self, reach, index, profile):
+        QUndoCommand.__init__(self)
+
+        self._reach = reach
+        self._index = index
+        self._profile = profile
+
+    def undo(self):
+        self._reach.insert_profile(self._index, self._profile)
+
+    def redo(self):
+        self._reach.delete([self._index])
+
+class SortCommand(QUndoCommand):
+    @timer
+    def __init__(self, reach, old, new):
+        QUndoCommand.__init__(self)
+
+        self._reach = reach
+        self._indexes = list(
+            map(
+                lambda p: old.index(p),
+                new
+            )
+        )
+        self._rindexes = list(
+            map(
+                lambda p: new.index(p),
+                old
+            )
+        )
+
+    def undo(self):
+        self._reach.sort_with_indexes(self._indexes)
+
+    def redo(self):
+        self._reach.sort_with_indexes(self._rindexes)
diff --git a/src/View/Geometry/qtableview_reach.py b/src/View/Geometry/qtableview_reach.py
index fd8e164c20b0a73450e812936c1716a3cf4cc5b0..ea931d7444e1fb487c69c68472b2fbfd93f1f19a 100644
--- a/src/View/Geometry/qtableview_reach.py
+++ b/src/View/Geometry/qtableview_reach.py
@@ -13,21 +13,26 @@ from PyQt5 import (
 )
 from PyQt5.QtCore import (
     Qt, QAbstractTableModel, QModelIndex,
-    QVariant, pyqtSlot, QCoreApplication
+    QVariant, pyqtSlot, QCoreApplication,
 )
 from PyQt5.QtWidgets import (
-    QMessageBox
+    QMessageBox, QUndoCommand, QUndoStack,
 )
 
 from Model.Geometry import Reach
+from View.Geometry.ReachUndoCommand import *
+
 
 _translate = QCoreApplication.translate
 
+
 class PandasModelEditable(QAbstractTableModel):
     def __init__(self, reach, headers=None):
         QAbstractTableModel.__init__(self)
         data_list = []
 
+        self._undo_stack = QUndoStack()
+
         self._reach = reach
 
         if headers is None:
@@ -91,9 +96,23 @@ class PandasModelEditable(QAbstractTableModel):
 
         if role == Qt.EditRole and index.column() != 2:
             if index.column() == 0:
+                self._undo_stack.push(
+                    SetNameCommand(
+                        self._reach, index.row(),
+                        self._reach.profile(index.row()).name,
+                        value
+                    )
+                )
                 self._reach.profile(index.row()).name = value
 
             if index.column() == 1:
+                self._undo_stack.push(
+                    SetKPCommand(
+                        self._reach, index.row(),
+                        self._reach.profile(index.row()).kp,
+                        value
+                    )
+                )
                 self._reach.profile(index.row()).kp = value
 
             self.dataChanged.emit(index, index)
@@ -167,6 +186,14 @@ class PandasModelEditable(QAbstractTableModel):
         self.endMoveRows()
         self.layoutChanged.emit()
 
+    def undo(self):
+        self._undo_stack.undo()
+        self.layoutChanged.emit()
+
+    def redo(self):
+        self._undo_stack.redo()
+        self.layoutChanged.emit()
+
 
 class Delegate(QtWidgets.QStyledItemDelegate):
     def __init__(self, parent=None, setModelDataEvent=None):