HexEdit/HexEditUndoStack.py

changeset 4650
b1ca3bcde70b
child 5389
9b1c800daff3
diff -r bbc8b2de9173 -r b1ca3bcde70b HexEdit/HexEditUndoStack.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HexEdit/HexEditUndoStack.py	Sat Jan 09 19:04:34 2016 +0100
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the Undo stack for the hex edit widget.
+"""
+
+from __future__ import unicode_literals
+
+try:
+    from enum import Enum
+except ImportError:
+    from ThirdParty.enum import Enum
+
+from PyQt5.QtWidgets import QUndoStack, QUndoCommand
+
+
+class HexEditCommand(Enum):
+    """
+    Class implementing the edit comands.
+    """
+    Insert = 0
+    RemoveAt = 1
+    Overwrite = 2
+
+
+class HexEditUndoCommand(QUndoCommand):
+    """
+    Class implementing the Undo command.
+    """
+    def __init__(self, chunks, cmd, pos, newByte, parent=None):
+        """
+        Constructor
+        
+        @param chunks reference to the data container
+        @type HexEditChunks
+        @param cmd edit command
+        @type HexEditCommand
+        @param pos edit position
+        @type int
+        @param newByte new byte value
+        @type int (range 0 to 255)
+        @param parent reference to the parent command
+        @type QUndoCommand
+        """
+        super(HexEditUndoCommand, self).__init__(parent)
+        
+        self.__chunks = chunks
+        self._pos = pos
+        self._newByte = newByte
+        self._cmd = cmd
+        
+        self.__wasChanged = False
+        self.__oldByte = 0
+    
+    def undo(self):
+        """
+        Public method to undo the command.
+        """
+        if self._cmd == HexEditCommand.Insert:
+            self.__chunks.removeAt(self._pos)
+        elif self._cmd == HexEditCommand.Overwrite:
+            self.__chunks.overwrite(self._pos, self.__oldByte)
+            self.__chunks.setDataChanged(self._pos, self.__wasChanged)
+        elif self._cmd == HexEditCommand.RemoveAt:
+            self.__chunks.insert(self._pos, self.__oldByte)
+            self.__chunks.setDataChanged(self._pos, self.__wasChanged)
+    
+    def redo(self):
+        """
+        Public method to redo the command.
+        """
+        if self._cmd == HexEditCommand.Insert:
+            self.__chunks.insert(self._pos, self._newByte)
+        elif self._cmd == HexEditCommand.Overwrite:
+            self.__oldByte = self.__chunks[self._pos]
+            self.__wasChanged = self.__chunks.dataChanged(self._pos)
+            self.__chunks.overwrite(self._pos, self._newByte)
+        elif self._cmd == HexEditCommand.RemoveAt:
+            self.__oldByte = self.__chunks[self._pos]
+            self.__wasChanged = self.__chunks.dataChanged(self._pos)
+            self.__chunks.removeAt(self._pos)
+    
+    def mergeWith(self, command):
+        """
+        Public method to merge this command with another one.
+        
+        @param command reference to the command to merge with
+        @type QUndoCommand
+        @return flag indicating a successful merge
+        @rtype bool
+        """
+        result = False
+        
+        if self._cmd != HexEditCommand.RemoveAt:
+            if command._cmd == HexEditCommand.Overwrite:
+                if command._pos == self._pos:
+                    self._newByte = command._newByte
+                    result = True
+        
+        return result
+    
+    def id(self):
+        """
+        Public method to get the ID of this undo command class.
+        
+        @return ID of the undo command class
+        @rtype int
+        """
+        return 4242
+
+
+class HexEditUndoStack(QUndoStack):
+    """
+    Class implementing an Undo stack for the hex edit widget.
+    """
+    def __init__(self, chunks, parent=None):
+        """
+        Constructor
+        
+        @param chunks reference to the data container
+        @type HexEditChunks
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(HexEditUndoStack, self).__init__(parent)
+        
+        self.__chunks = chunks
+        self.__parent = parent
+    
+    def insert(self, pos, data):
+        """
+        Public method to insert a byte.
+        
+        @param pos position to insert at
+        @type int
+        @param data byte to be inserted
+        @type int (range 0 to 255)
+        """
+        if pos >= 0 and pos <= self.__chunks.size():
+            uc = HexEditUndoCommand(
+                self.__chunks, HexEditCommand.Insert, pos, data)
+            self.push(uc)
+    
+    def insertByteArray(self, pos, byteArray):
+        """
+        Public method to insert bytes.
+        
+        @param pos position to insert at
+        @type int
+        @param byteArray data to be inserted
+        @type byteArray or QByteArray
+        """
+        ba = bytearray(byteArray)
+        
+        if pos >= 0 and pos <= self.__chunks.size():
+            txt = self.tr("Inserting %n byte(s)", "", len(ba))
+            self.beginMacro(txt)
+            for idx in range(len(ba)):
+                uc = HexEditUndoCommand(
+                    self.__chunks, HexEditCommand.Insert, pos + idx, ba[idx])
+                self.push(uc)
+            self.endMacro()
+    
+    def removeAt(self, pos, length=1):
+        """
+        Public method to remove bytes.
+        
+        @param pos position to remove bytes from
+        @type int
+        @param length amount of bytes to remove
+        @type int
+        """
+        if pos >= 0 and pos <= self.__chunks.size():
+            if length == 1:
+                uc = HexEditUndoCommand(
+                    self.__chunks, HexEditCommand.RemoveAt, pos, 0)
+                self.push(uc)
+            else:
+                txt = self.tr("Deleting %n byte(s)", "", length)
+                self.beginMacro(txt)
+                for cnt in range(length):
+                    uc = HexEditUndoCommand(
+                        self.__chunks, HexEditCommand.RemoveAt, pos, 0)
+                    self.push(uc)
+                self.endMacro()
+    
+    def overwrite(self, pos, data):
+        """
+        Public method to replace a byte.
+        
+        @param pos position to replace the byte at
+        @type int
+        @param data byte to replace with
+        @type int (range 0 to 255)
+        """
+        if pos >= 0 and pos <= self.__chunks.size():
+            uc = HexEditUndoCommand(
+                self.__chunks, HexEditCommand.Overwrite, pos, data)
+            self.push(uc)
+    
+    def overwriteByteArray(self, pos, length, byteArray):
+        """
+        Public method to replace bytes.
+        
+        @param pos position to replace the bytes at
+        @type int
+        @param length amount of bytes to replace
+        @type int
+        @param byteArray bytes to replace with
+        @type bytearray or QByteArray
+        """
+        ba = bytearray(byteArray)
+        
+        if pos >= 0 and pos <= self.__chunks.size():
+            txt = self.tr("Inserting %n byte(s)", "", len(ba))
+            self.beginMacro(txt)
+            self.removeAt(pos, length)
+            self.insertByteArray(pos, ba)
+            self.endMacro()

eric ide

mercurial