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