diff --git a/src/View/Network/ContextMenu.py b/src/View/Network/ContextMenu.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e29fefe5d562177de7575166a5c18b9980cd493
--- /dev/null
+++ b/src/View/Network/ContextMenu.py
@@ -0,0 +1,84 @@
+# ContextMenu.py -- Pamhyr
+# Copyright (C) 2024  INRAE
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+# -*- coding: utf-8 -*-
+
+from PyQt5.QtWidgets import (
+    QMenu,
+)
+
+
+class AbstractMenu(object):
+    def __init__(self, event=None, pos=None, items=[],
+                 trad=None, parent=None):
+        super(AbstractMenu, self).__init__()
+
+        self._menu = QMenu(parent)
+        self._event = event
+        self._pos = pos
+        self._items = items
+
+        self._trad = trad
+        self._parent = parent
+
+    def map_to_global(self):
+        return self._parent.mapToGlobal(self._event.pos())
+
+    def _exec(self):
+        return self._menu.exec_(self.map_to_global())
+
+    def run(self):
+        return
+
+
+class DefaultMenu(AbstractMenu):
+    def run(self):
+        add_node = self._menu.addAction(self._trad["menu_add_node"])
+
+        action = self._exec()
+        if action == add_node:
+            self._parent.add_node(self._pos)
+
+
+class NodeMenu(AbstractMenu):
+    def run(self):
+        delete = self._menu.addAction(self._trad["menu_del_node"])
+
+        action = self._exec()
+        if action == delete:
+            self._parent.del_node(self._items[0])
+
+
+class EdgeMenu(AbstractMenu):
+    def run(self):
+        it = self._items[0]
+
+        reverse = self._menu.addAction(self._trad["menu_rev_edge"])
+        delete = self._menu.addAction(self._trad["menu_del_edge"])
+        if self._parent.graph.is_enable_edge(it.edge):
+            enable = self._menu.addAction(self._trad["menu_dis_edge"])
+            is_enable = True
+        else:
+            enable = self._menu.addAction(self._trad["menu_ena_edge"])
+            is_enable = False
+
+        action = self._exec()
+        if action == delete:
+            self._parent.del_edge(it)
+        elif action == enable:
+            self._parent.enable_edge(it, is_enable)
+        elif action == reverse:
+            self._parent.reverse_edge(it)
diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py
index 54da854b3cee31c4e174897613b305eba7e53956..b3e321cdad8b8cb4c23a71729c3fec4f2d1a838c 100644
--- a/src/View/Network/GraphWidget.py
+++ b/src/View/Network/GraphWidget.py
@@ -39,6 +39,9 @@ from Model.Network.Edge import Edge
 from Model.Network.Graph import Graph
 
 from View.Network.UndoCommand import *
+from View.Network.ContextMenu import (
+    DefaultMenu, NodeMenu, EdgeMenu,
+)
 
 logger = logging.getLogger()
 
@@ -292,7 +295,8 @@ class GraphWidget(QGraphicsView):
 
     def __init__(self, graph, parent=None,
                  min_size=(400, 400), max_size=None,
-                 size=None, only_display=False, undo=None):
+                 size=None, only_display=False, undo=None,
+                 trad=None):
         super(GraphWidget, self).__init__(parent=parent)
 
         self.timerId = 0
@@ -300,6 +304,7 @@ class GraphWidget(QGraphicsView):
         self._state = "move"
         self._only_display = only_display
         self._undo = undo
+        self._trad = trad
 
         self.graph = graph
 
@@ -813,45 +818,6 @@ class GraphWidget(QGraphicsView):
 
     # Contextual menu
 
-    def _menu_default(self, event, pos, items, menu):
-        add_node = menu.addAction(_translate("Network", "Add node"))
-
-        action = menu.exec_(self.mapToGlobal(event.pos()))
-
-        if action == add_node:
-            self.add_node(pos)
-
-    def _menu_node(self, event, pos, items, menu):
-        delete = menu.addAction(_translate("Network", "Delete the node"))
-        disable = menu.addAction(_translate("Network", "Disable the node"))
-
-        action = menu.exec_(self.mapToGlobal(event.pos()))
-
-        if action == delete:
-            self.del_node(items[0])
-
-    def _menu_edge(self, event, pos, items, menu):
-        delete = menu.addAction(_translate("Network", "Delete the reach"))
-
-        if self.graph.is_enable_edge(items[0].edge):
-            enable = menu.addAction(_translate("Network", "Disable the reach"))
-            is_enable = True
-        else:
-            enable = menu.addAction(_translate("Network", "Enable the reach"))
-            is_enable = False
-
-        reverse = menu.addAction(_translate(
-            "Network", "Reverse the reach orientation"))
-
-        action = menu.exec_(self.mapToGlobal(event.pos()))
-
-        if action == delete:
-            self.del_edge(items[0])
-        elif action == enable:
-            self.enable_edge(items[0], is_enable)
-        elif action == reverse:
-            self.reverse_edge(items[0])
-
     def contextMenuEvent(self, event):
         if self._only_display:
             return
@@ -859,10 +825,17 @@ class GraphWidget(QGraphicsView):
         pos = self.mapToScene(event.pos())
         items = self.items(event.pos())
 
-        menu = QMenu(self)
+        # Select current menu
         if len(items) == 0:
-            self._menu_default(event, pos, items, menu)
+            m_type = DefaultMenu
         elif type(items[0]) is NodeItem:
-            self._menu_node(event, pos, items, menu)
+            m_type = NodeMenu
         elif type(items[0]) is EdgeItem:
-            self._menu_edge(event, pos, items, menu)
+            m_type = EdgeMenu
+
+        # Create and exec menu
+        m = m_type(
+            event=event, pos=pos, items=items,
+            trad=self._trad, parent=self
+        )
+        m.run()
diff --git a/src/View/Network/Window.py b/src/View/Network/Window.py
index 17a95b2f8baa1fe016369ab1008477c3dfeceddd..18763bc6ce28dba855fef6b96d2f653f1314783e 100644
--- a/src/View/Network/Window.py
+++ b/src/View/Network/Window.py
@@ -117,7 +117,8 @@ class NetworkWindow(PamhyrWindow):
     def setup_graph(self):
         self._graph_widget = GraphWidget(
             self._graph, parent=self,
-            undo=self._undo_stack
+            undo=self._undo_stack,
+            trad=self._trad,
         )
         self._graph_layout = self.find(QHBoxLayout, "horizontalLayout_graph")
         self._graph_layout.addWidget(self._graph_widget)
diff --git a/src/View/Network/translate.py b/src/View/Network/translate.py
index 089dc9a13aabc3903155ea52141718a2947a4856..ff5440b81b3d6a9bfdff6d139d813acc674f3d43 100644
--- a/src/View/Network/translate.py
+++ b/src/View/Network/translate.py
@@ -31,6 +31,16 @@ class NetworkTranslate(MainTranslate):
             "Network", "River network"
         )
 
+        self._dict["menu_add_node"] = _translate("Network", "Add node")
+        self._dict["menu_del_node"] = _translate("Network", "Delete the node")
+
+        self._dict["menu_del_edge"] = _translate("Network", "Delete the reach")
+        self._dict["menu_ena_edge"] = _translate("Network", "Enable the reach")
+        self._dict["menu_dis_edge"] = _translate("Network", "Disable the reach")
+        self._dict["menu_rev_edge"] = _translate(
+            "Network", "Reverse the reach orientation"
+        )
+
         self._sub_dict["table_headers_node"] = {
             "name": self._dict['name'],
             "type": self._dict['type'],