eric7/HexEdit/HexEditMainWindow.py

branch
eric7
changeset 8312
800c432b34c8
parent 8265
0090cfa83159
child 8314
e3642a6a1e71
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/HexEdit/HexEditMainWindow.py	Sat May 15 18:45:04 2021 +0200
@@ -0,0 +1,1504 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2016 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the hex editor main window.
+"""
+
+import os
+import contextlib
+
+from PyQt5.QtCore import (
+    pyqtSignal, pyqtSlot, QFile, QFileInfo, QSize, QCoreApplication, QLocale
+)
+from PyQt5.QtGui import QKeySequence
+from PyQt5.QtWidgets import (
+    QWhatsThis, QLabel, QWidget, QVBoxLayout, QDialog, QAction, QFrame, QMenu
+)
+
+from E5Gui.E5Action import E5Action
+from E5Gui.E5MainWindow import E5MainWindow
+from E5Gui import E5FileDialog, E5MessageBox
+from E5Gui.E5ClickableLabel import E5ClickableLabel
+
+from Globals import strGroup, recentNameHexFiles
+
+from .HexEditWidget import HexEditWidget
+from .HexEditSearchReplaceWidget import HexEditSearchReplaceWidget
+from .HexEditGotoWidget import HexEditGotoWidget
+
+import UI.PixmapCache
+import UI.Config
+
+import Preferences
+import Utilities
+
+
+class HexEditMainWindow(E5MainWindow):
+    """
+    Class implementing the web browser main window.
+    
+    @signal editorClosed() emitted after the window was requested to close down
+    """
+    editorClosed = pyqtSignal()
+    
+    windows = []
+    
+    maxMenuFilePathLen = 75
+    
+    def __init__(self, fileName="", parent=None, fromEric=False, project=None):
+        """
+        Constructor
+        
+        @param fileName name of a file to load on startup (string)
+        @param parent parent widget of this window (QWidget)
+        @param fromEric flag indicating whether it was called from within
+            eric (boolean)
+        @param project reference to the project object (Project)
+        """
+        super().__init__(parent)
+        self.setObjectName("eric6_hex_editor")
+        
+        self.__srHistory = {
+            "search": [],
+            # list of recent searches (tuple of format type index and
+            # search term)
+            "replace": [],
+            # list of recent replaces (tuple of format type index and
+            # replace term
+        }
+        
+        self.__fromEric = fromEric
+        self.setWindowIcon(UI.PixmapCache.getIcon("hexEditor"))
+        
+        if not self.__fromEric:
+            self.setStyle(Preferences.getUI("Style"),
+                          Preferences.getUI("StyleSheet"))
+        
+        self.__editor = HexEditWidget()
+        self.__searchWidget = HexEditSearchReplaceWidget(
+            self.__editor, self, False)
+        self.__replaceWidget = HexEditSearchReplaceWidget(
+            self.__editor, self, True)
+        self.__gotoWidget = HexEditGotoWidget(self.__editor)
+        cw = QWidget()
+        layout = QVBoxLayout(cw)
+        layout.setContentsMargins(1, 1, 1, 1)
+        layout.setSpacing(1)
+        layout.addWidget(self.__editor)
+        layout.addWidget(self.__searchWidget)
+        layout.addWidget(self.__gotoWidget)
+        cw.setLayout(layout)
+        layout.addWidget(self.__replaceWidget)
+        self.__searchWidget.hide()
+        self.__replaceWidget.hide()
+        self.__gotoWidget.hide()
+        self.setCentralWidget(cw)
+        
+        g = Preferences.getGeometry("HexEditorGeometry")
+        if g.isEmpty():
+            s = QSize(600, 500)
+            self.resize(s)
+        else:
+            self.restoreGeometry(g)
+        
+        self.__initActions()
+        self.__initMenus()
+        self.__initToolbars()
+        self.__createStatusBar()
+        
+        self.__class__.windows.append(self)
+        
+        state = Preferences.getHexEditor("HexEditorState")
+        self.restoreState(state)
+        
+        self.__editor.currentAddressChanged.connect(self.__showAddress)
+        self.__editor.selectionAvailable.connect(self.__showSelectionInfo)
+        self.__editor.currentSizeChanged.connect(self.__showSize)
+        self.__editor.dataChanged.connect(self.__modificationChanged)
+        self.__editor.overwriteModeChanged.connect(self.__showEditMode)
+        self.__editor.readOnlyChanged.connect(self.__showReadOnlyMode)
+        self.__editor.readOnlyChanged.connect(self.__checkActions)
+        
+        self.preferencesChanged()
+        self.__editor.setOverwriteMode(
+            Preferences.getHexEditor("OpenInOverwriteMode"))
+        
+        self.__project = project
+        self.__lastOpenPath = ""
+        self.__lastSavePath = ""
+        
+        self.__recent = []
+        self.__loadRecent()
+        
+        self.__setCurrentFile("")
+        if fileName:
+            self.__loadHexFile(fileName)
+        
+        self.__checkActions()
+    
+    def __initActions(self):
+        """
+        Private method to define the user interface actions.
+        """
+        # list of all actions
+        self.__actions = []
+        
+        self.__initFileActions()
+        self.__initEditActions()
+        self.__initHelpActions()
+        if not self.__fromEric:
+            self.__initConfigActions()
+        
+    def __initFileActions(self):
+        """
+        Private method to define the file related user interface actions.
+        """
+        self.newWindowAct = E5Action(
+            self.tr('New Window'),
+            UI.PixmapCache.getIcon("newWindow"),
+            self.tr('New &Window'),
+            0, 0, self, 'hexEditor_file_new_window')
+        self.newWindowAct.setStatusTip(self.tr(
+            'Open a binary file for editing in a new hex editor window'))
+        self.newWindowAct.setWhatsThis(self.tr(
+            """<b>New Window</b>"""
+            """<p>This opens a binary file for editing in a new hex editor"""
+            """ window.</p>"""
+        ))
+        self.newWindowAct.triggered.connect(self.__openHexFileNewWindow)
+        self.__actions.append(self.newWindowAct)
+        
+        # correct texts will be set later
+        self.openAct = E5Action(
+            self.tr('Open'),
+            UI.PixmapCache.getIcon("open"),
+            self.tr('&Open...'),
+            QKeySequence(self.tr("Ctrl+O", "File|Open")),
+            0, self, 'hexEditor_file_open')
+        self.openAct.triggered.connect(self.__openHexFile)
+        self.__actions.append(self.openAct)
+        
+        # correct texts will be set later
+        self.openReadOnlyAct = E5Action(
+            "", "",
+            0, 0, self, 'hexEditor_file_open_read_only')
+        self.openReadOnlyAct.triggered.connect(self.__openHexFileReadOnly)
+        self.__actions.append(self.openReadOnlyAct)
+        
+        self.saveAct = E5Action(
+            self.tr('Save'),
+            UI.PixmapCache.getIcon("fileSave"),
+            self.tr('&Save'),
+            QKeySequence(self.tr("Ctrl+S", "File|Save")),
+            0, self, 'hexEditor_file_save')
+        self.saveAct.setStatusTip(self.tr('Save the current binary file'))
+        self.saveAct.setWhatsThis(self.tr(
+            """<b>Save File</b>"""
+            """<p>Save the contents of the hex editor window.</p>"""
+        ))
+        self.saveAct.triggered.connect(self.__saveHexFile)
+        self.__actions.append(self.saveAct)
+        
+        self.saveAsAct = E5Action(
+            self.tr('Save As'),
+            UI.PixmapCache.getIcon("fileSaveAs"),
+            self.tr('Save &As...'),
+            QKeySequence(self.tr("Shift+Ctrl+S", "File|Save As")),
+            0, self, 'hexEditor_file_save_as')
+        self.saveAsAct.setStatusTip(
+            self.tr('Save the current binary data to a new file'))
+        self.saveAsAct.setWhatsThis(self.tr(
+            """<b>Save As...</b>"""
+            """<p>Saves the current binary data to a new file.</p>"""
+        ))
+        self.saveAsAct.triggered.connect(self.__saveHexFileAs)
+        self.__actions.append(self.saveAsAct)
+        
+        self.saveReadableAct = E5Action(
+            self.tr('Save As Readable'),
+            self.tr('Save As &Readable...'),
+            0, 0, self, 'hexEditor_file_save_readable')
+        self.saveReadableAct.setStatusTip(
+            self.tr('Save the current binary data to a new file in a readable'
+                    ' format'))
+        self.saveReadableAct.setWhatsThis(self.tr(
+            """<b>Save As Readable...</b>"""
+            """<p>Saves the current binary data to a new file in a readable"""
+            """ format.</p>"""
+        ))
+        self.saveReadableAct.triggered.connect(self.__saveHexFileReadable)
+        self.__actions.append(self.saveReadableAct)
+        
+        self.closeAct = E5Action(
+            self.tr('Close'),
+            UI.PixmapCache.getIcon("close"),
+            self.tr('&Close'),
+            QKeySequence(self.tr("Ctrl+W", "File|Close")),
+            0, self, 'hexEditor_file_close')
+        self.closeAct.setStatusTip(self.tr(
+            'Close the current hex editor window'))
+        self.closeAct.setWhatsThis(self.tr(
+            """<b>Close</b>"""
+            """<p>Closes the current hex editor window.</p>"""
+        ))
+        self.closeAct.triggered.connect(self.close)
+        self.__actions.append(self.closeAct)
+        
+        self.closeAllAct = E5Action(
+            self.tr('Close All'),
+            self.tr('Close &All'),
+            0, 0, self, 'hexEditor_file_close_all')
+        self.closeAllAct.setStatusTip(self.tr(
+            'Close all hex editor windows'))
+        self.closeAllAct.setWhatsThis(self.tr(
+            """<b>Close All</b>"""
+            """<p>Closes all hex editor windows.</p>"""
+        ))
+        self.closeAllAct.triggered.connect(self.__closeAll)
+        self.__actions.append(self.closeAllAct)
+        
+        self.closeOthersAct = E5Action(
+            self.tr('Close Others'),
+            self.tr('Close Others'),
+            0, 0, self, 'hexEditor_file_close_others')
+        self.closeOthersAct.setStatusTip(self.tr(
+            'Close all other hex editor windows'))
+        self.closeOthersAct.setWhatsThis(self.tr(
+            """<b>Close Others</b>"""
+            """<p>Closes all other hex editor windows.</p>"""
+        ))
+        self.closeOthersAct.triggered.connect(self.__closeOthers)
+        self.__actions.append(self.closeOthersAct)
+        
+        self.exitAct = E5Action(
+            self.tr('Quit'),
+            UI.PixmapCache.getIcon("exit"),
+            self.tr('&Quit'),
+            QKeySequence(self.tr("Ctrl+Q", "File|Quit")),
+            0, self, 'hexEditor_file_quit')
+        self.exitAct.setStatusTip(self.tr('Quit the hex editor'))
+        self.exitAct.setWhatsThis(self.tr(
+            """<b>Quit</b>"""
+            """<p>Quit the hex editor.</p>"""
+        ))
+        if not self.__fromEric:
+            self.exitAct.triggered.connect(self.__closeAll)
+        self.__actions.append(self.exitAct)
+    
+    def __initEditActions(self):
+        """
+        Private method to create the Edit actions.
+        """
+        self.undoAct = E5Action(
+            self.tr('Undo'),
+            UI.PixmapCache.getIcon("editUndo"),
+            self.tr('&Undo'),
+            QKeySequence(self.tr("Ctrl+Z", "Edit|Undo")),
+            QKeySequence(self.tr("Alt+Backspace", "Edit|Undo")),
+            self, 'hexEditor_edit_undo')
+        self.undoAct.setStatusTip(self.tr('Undo the last change'))
+        self.undoAct.setWhatsThis(self.tr(
+            """<b>Undo</b>"""
+            """<p>Undo the last change done.</p>"""
+        ))
+        self.undoAct.triggered.connect(self.__editor.undo)
+        self.__actions.append(self.undoAct)
+        
+        self.redoAct = E5Action(
+            self.tr('Redo'),
+            UI.PixmapCache.getIcon("editRedo"),
+            self.tr('&Redo'),
+            QKeySequence(self.tr("Ctrl+Shift+Z", "Edit|Redo")),
+            0, self, 'hexEditor_edit_redo')
+        self.redoAct.setStatusTip(self.tr('Redo the last change'))
+        self.redoAct.setWhatsThis(self.tr(
+            """<b>Redo</b>"""
+            """<p>Redo the last change done.</p>"""
+        ))
+        self.redoAct.triggered.connect(self.__editor.redo)
+        self.__actions.append(self.redoAct)
+        
+        self.revertAct = E5Action(
+            self.tr('Revert to last saved state'),
+            self.tr('Re&vert to last saved state'),
+            QKeySequence(self.tr("Ctrl+Y", "Edit|Revert")),
+            0,
+            self, 'hexEditor_edit_revert')
+        self.revertAct.setStatusTip(self.tr('Revert to last saved state'))
+        self.revertAct.setWhatsThis(self.tr(
+            """<b>Revert to last saved state</b>"""
+            """<p>Undo all changes up to the last saved state of the"""
+            """ editor.</p>"""
+        ))
+        self.revertAct.triggered.connect(self.__editor.revertToUnmodified)
+        self.__actions.append(self.revertAct)
+        
+        self.cutAct = E5Action(
+            self.tr('Cut'),
+            UI.PixmapCache.getIcon("editCut"),
+            self.tr('Cu&t'),
+            QKeySequence(self.tr("Ctrl+X", "Edit|Cut")),
+            QKeySequence(self.tr("Shift+Del", "Edit|Cut")),
+            self, 'hexEditor_edit_cut')
+        self.cutAct.setStatusTip(self.tr('Cut the selection'))
+        self.cutAct.setWhatsThis(self.tr(
+            """<b>Cut</b>"""
+            """<p>Cut the selected binary area to the clipboard.</p>"""
+        ))
+        self.cutAct.triggered.connect(self.__editor.cut)
+        self.__actions.append(self.cutAct)
+        
+        self.copyAct = E5Action(
+            self.tr('Copy'),
+            UI.PixmapCache.getIcon("editCopy"),
+            self.tr('&Copy'),
+            QKeySequence(self.tr("Ctrl+C", "Edit|Copy")),
+            QKeySequence(self.tr("Ctrl+Ins", "Edit|Copy")),
+            self, 'hexEditor_edit_copy')
+        self.copyAct.setStatusTip(self.tr('Copy the selection'))
+        self.copyAct.setWhatsThis(self.tr(
+            """<b>Copy</b>"""
+            """<p>Copy the selected binary area to the clipboard.</p>"""
+        ))
+        self.copyAct.triggered.connect(self.__editor.copy)
+        self.__actions.append(self.copyAct)
+        
+        self.pasteAct = E5Action(
+            self.tr('Paste'),
+            UI.PixmapCache.getIcon("editPaste"),
+            self.tr('&Paste'),
+            QKeySequence(self.tr("Ctrl+V", "Edit|Paste")),
+            QKeySequence(self.tr("Shift+Ins", "Edit|Paste")),
+            self, 'hexEditor_edit_paste')
+        self.pasteAct.setStatusTip(self.tr('Paste the clipboard contents'))
+        self.pasteAct.setWhatsThis(self.tr(
+            """<b>Paste</b>"""
+            """<p>Paste the clipboard contents.</p>"""
+        ))
+        self.pasteAct.triggered.connect(self.__editor.paste)
+        self.__actions.append(self.pasteAct)
+        
+        self.selectAllAct = E5Action(
+            self.tr('Select All'),
+            UI.PixmapCache.getIcon("editSelectAll"),
+            self.tr('&Select All'),
+            QKeySequence(self.tr("Ctrl+A", "Edit|Select All")),
+            0,
+            self, 'hexEditor_edit_select_all')
+        self.selectAllAct.setStatusTip(self.tr(
+            'Select the complete binary data'))
+        self.selectAllAct.setWhatsThis(self.tr(
+            """<b>Select All</b>"""
+            """<p>Selects the complete binary data.</p>"""
+        ))
+        self.selectAllAct.triggered.connect(self.__editor.selectAll)
+        self.__actions.append(self.selectAllAct)
+        
+        self.deselectAllAct = E5Action(
+            self.tr('Deselect all'),
+            self.tr('&Deselect all'),
+            QKeySequence(self.tr("Alt+Ctrl+A", "Edit|Deselect all")),
+            0,
+            self, 'hexEditor_edit_deselect_all')
+        self.deselectAllAct.setStatusTip(self.tr('Deselect all binary data'))
+        self.deselectAllAct.setWhatsThis(self.tr(
+            """<b>Deselect All</b>"""
+            """<p>Deselect all all binary data.</p>"""
+        ))
+        self.deselectAllAct.triggered.connect(self.__editor.deselectAll)
+        self.__actions.append(self.deselectAllAct)
+        
+        self.saveSelectionReadableAct = E5Action(
+            self.tr('Save Selection Readable'),
+            self.tr('Save Selection Readable...'),
+            0, 0, self, 'hexEditor_edit_selection_save_readable')
+        self.saveSelectionReadableAct.setStatusTip(
+            self.tr('Save the binary data of the current selection to a file'
+                    ' in a readable format'))
+        self.saveSelectionReadableAct.setWhatsThis(self.tr(
+            """<b>Save Selection Readable...</b>"""
+            """<p>Saves the binary data of the current selection to a file"""
+            """ in a readable format.</p>"""
+        ))
+        self.saveSelectionReadableAct.triggered.connect(
+            self.__saveSelectionReadable)
+        self.__actions.append(self.saveSelectionReadableAct)
+        
+        self.readonlyAct = E5Action(
+            self.tr('Set Read Only'),
+            self.tr('Set Read Only'),
+            0, 0, self, 'hexEditor_edit_readonly', True)
+        self.readonlyAct.setStatusTip(self.tr(
+            'Change the edit mode to read only'))
+        self.readonlyAct.setWhatsThis(self.tr(
+            """<b>Set Read Only</b>"""
+            """<p>This changes the edit mode to read only (i.e. to view"""
+            """ mode).</p>"""
+        ))
+        self.readonlyAct.setChecked(False)
+        self.readonlyAct.toggled[bool].connect(self.__editor.setReadOnly)
+        self.__editor.readOnlyChanged.connect(self.readonlyAct.setChecked)
+        self.__actions.append(self.readonlyAct)
+        
+        self.searchAct = E5Action(
+            self.tr('Search'),
+            UI.PixmapCache.getIcon("find"),
+            self.tr('&Search...'),
+            QKeySequence(self.tr("Ctrl+F", "Search|Search")),
+            0,
+            self, 'hexEditor_edit_search')
+        self.searchAct.setStatusTip(self.tr('Search for data'))
+        self.searchAct.setWhatsThis(self.tr(
+            """<b>Search</b>"""
+            """<p>Search for some data. A dialog is shown to enter the"""
+            """ data to search for in various formats.</p>"""
+        ))
+        self.searchAct.triggered.connect(self.__search)
+        self.__actions.append(self.searchAct)
+        
+        self.searchNextAct = E5Action(
+            self.tr('Search next'),
+            UI.PixmapCache.getIcon("findNext"),
+            self.tr('Search &next'),
+            QKeySequence(self.tr("F3", "Search|Search next")),
+            0,
+            self, 'hexEditor_edit_search_next')
+        self.searchNextAct.setStatusTip(self.tr(
+            'Search next occurrence'))
+        self.searchNextAct.setWhatsThis(self.tr(
+            """<b>Search next</b>"""
+            """<p>Search the next occurrence of some data. The previously"""
+            """ entered search data are reused.</p>"""
+        ))
+        self.searchNextAct.triggered.connect(self.__searchWidget.findPrevNext)
+        self.__actions.append(self.searchNextAct)
+        
+        self.searchPrevAct = E5Action(
+            self.tr('Search previous'),
+            UI.PixmapCache.getIcon("findPrev"),
+            self.tr('Search &previous'),
+            QKeySequence(self.tr("Shift+F3", "Search|Search previous")),
+            0,
+            self, 'hexEditor_edit_search_previous')
+        self.searchPrevAct.setStatusTip(self.tr(
+            'Search previous occurrence'))
+        self.searchPrevAct.setWhatsThis(self.tr(
+            """<b>Search previous</b>"""
+            """<p>Search the previous occurrence of some data. The"""
+            """ previously entered search data are reused.</p>"""
+        ))
+        self.searchPrevAct.triggered.connect(
+            lambda: self.__searchWidget.findPrevNext(True))
+        self.__actions.append(self.searchPrevAct)
+        
+        self.replaceAct = E5Action(
+            self.tr('Replace'),
+            self.tr('&Replace...'),
+            QKeySequence(self.tr("Ctrl+R", "Search|Replace")),
+            0,
+            self, 'hexEditor_edit_search_replace')
+        self.replaceAct.setStatusTip(self.tr('Replace data'))
+        self.replaceAct.setWhatsThis(self.tr(
+            """<b>Replace</b>"""
+            """<p>Search for some data and replace it."""
+            """ A dialog is shown to enter the data to search for and the"""
+            """ replacement data in various formats.</p>"""
+        ))
+        self.replaceAct.triggered.connect(self.__replace)
+        self.__actions.append(self.replaceAct)
+        
+        self.gotoAct = E5Action(
+            self.tr('Goto Offset'),
+            UI.PixmapCache.getIcon("goto"),
+            self.tr('&Goto Offset...'),
+            QKeySequence(QCoreApplication.translate(
+                'ViewManager', "Ctrl+G", "Search|Goto Offset")),
+            0,
+            self, 'hexEditor_edit_goto')
+        self.gotoAct.setStatusTip(self.tr('Goto Offset'))
+        self.gotoAct.setWhatsThis(self.tr(
+            """<b>Goto Offset</b>"""
+            """<p>Go to a specific address. A dialog is shown to enter"""
+            """ the movement data.</p>"""
+        ))
+        self.gotoAct.triggered.connect(self.__goto)
+        self.__actions.append(self.gotoAct)
+        
+        self.redoAct.setEnabled(False)
+        self.__editor.canRedoChanged.connect(self.redoAct.setEnabled)
+        
+        self.undoAct.setEnabled(False)
+        self.__editor.canUndoChanged.connect(self.undoAct.setEnabled)
+        
+        self.revertAct.setEnabled(False)
+        self.__editor.dataChanged.connect(self.revertAct.setEnabled)
+        
+        self.cutAct.setEnabled(False)
+        self.copyAct.setEnabled(False)
+        self.saveSelectionReadableAct.setEnabled(False)
+        self.__editor.selectionAvailable.connect(self.__checkActions)
+        self.__editor.selectionAvailable.connect(self.copyAct.setEnabled)
+        self.__editor.selectionAvailable.connect(
+            self.saveSelectionReadableAct.setEnabled)
+    
+    def __initHelpActions(self):
+        """
+        Private method to create the Help actions.
+        """
+        self.aboutAct = E5Action(
+            self.tr('About'),
+            self.tr('&About'),
+            0, 0, self, 'hexEditor_help_about')
+        self.aboutAct.setStatusTip(self.tr(
+            'Display information about this software'))
+        self.aboutAct.setWhatsThis(self.tr(
+            """<b>About</b>"""
+            """<p>Display some information about this software.</p>"""))
+        self.aboutAct.triggered.connect(self.__about)
+        self.__actions.append(self.aboutAct)
+        
+        self.aboutQtAct = E5Action(
+            self.tr('About Qt'),
+            self.tr('About &Qt'),
+            0, 0, self, 'hexEditor_help_about_qt')
+        self.aboutQtAct.setStatusTip(
+            self.tr('Display information about the Qt toolkit'))
+        self.aboutQtAct.setWhatsThis(self.tr(
+            """<b>About Qt</b>"""
+            """<p>Display some information about the Qt toolkit.</p>"""
+        ))
+        self.aboutQtAct.triggered.connect(self.__aboutQt)
+        self.__actions.append(self.aboutQtAct)
+        
+        self.whatsThisAct = E5Action(
+            self.tr('What\'s This?'),
+            UI.PixmapCache.getIcon("whatsThis"),
+            self.tr('&What\'s This?'),
+            QKeySequence(self.tr("Shift+F1", "Help|What's This?'")),
+            0, self, 'hexEditor_help_whats_this')
+        self.whatsThisAct.setStatusTip(self.tr('Context sensitive help'))
+        self.whatsThisAct.setWhatsThis(self.tr(
+            """<b>Display context sensitive help</b>"""
+            """<p>In What's This? mode, the mouse cursor shows an arrow"""
+            """ with a question mark, and you can click on the interface"""
+            """ elements to get a short description of what they do and"""
+            """ how to use them. In dialogs, this feature can be accessed"""
+            """ using the context help button in the titlebar.</p>"""
+        ))
+        self.whatsThisAct.triggered.connect(self.__whatsThis)
+        self.__actions.append(self.whatsThisAct)
+    
+    def __initConfigActions(self):
+        """
+        Private method to create the Settings actions.
+        """
+        self.prefAct = E5Action(
+            self.tr('Preferences'),
+            UI.PixmapCache.getIcon("configure"),
+            self.tr('&Preferences...'),
+            0, 0, self, 'hexEditor_settings_preferences')
+        self.prefAct.setStatusTip(self.tr(
+            'Set the prefered configuration'))
+        self.prefAct.setWhatsThis(self.tr(
+            """<b>Preferences</b>"""
+            """<p>Set the configuration items of the application"""
+            """ with your prefered values.</p>"""
+        ))
+        self.prefAct.triggered.connect(self.__showPreferences)
+        self.prefAct.setMenuRole(QAction.MenuRole.PreferencesRole)
+        self.__actions.append(self.prefAct)
+    
+    def __setReadOnlyActionTexts(self):
+        """
+        Private method to switch the 'Open Read Only' action between
+        'read only' and 'read write'.
+        """
+        if Preferences.getHexEditor("OpenReadOnly"):
+            self.openAct.setStatusTip(self.tr(
+                'Open a binary file for viewing'))
+            self.openAct.setWhatsThis(self.tr(
+                """<b>Open File</b>"""
+                """<p>This opens a binary file for viewing (i.e. in read"""
+                """ only mode). It pops up a file selection dialog.</p>"""
+            ))
+            
+            self.openReadOnlyAct.setText(self.tr('Open for Editing...'))
+            self.openReadOnlyAct.setIconText(self.tr('Open for Editing'))
+            self.openReadOnlyAct.setStatusTip(self.tr(
+                'Open a binary file for editing'))
+            self.openReadOnlyAct.setWhatsThis(self.tr(
+                """<b>Open for Editing</b>"""
+                """<p>This opens a binary file for editing."""
+                """ It pops up a file selection dialog.</p>"""
+            ))
+        else:
+            self.openAct.setStatusTip(self.tr(
+                'Open a binary file for editing'))
+            self.openAct.setWhatsThis(self.tr(
+                """<b>Open File</b>"""
+                """<p>This opens a binary file for editing."""
+                """ It pops up a file selection dialog.</p>"""
+            ))
+            
+            self.openReadOnlyAct.setText(self.tr('Open Read Only...'))
+            self.openReadOnlyAct.setIconText(self.tr('Open Read Only'))
+            self.openReadOnlyAct.setStatusTip(self.tr(
+                'Open a binary file for viewing'))
+            self.openReadOnlyAct.setWhatsThis(self.tr(
+                """<b>Open Read Only</b>"""
+                """<p>This opens a binary file for viewing (i.e. in read"""
+                """ only mode). It pops up a file selection dialog.</p>"""
+            ))
+    
+    def __initMenus(self):
+        """
+        Private method to create the menus.
+        """
+        mb = self.menuBar()
+        
+        menu = mb.addMenu(self.tr('&File'))
+        menu.setTearOffEnabled(True)
+        self.__recentMenu = QMenu(self.tr('Open &Recent Files'), menu)
+        menu.addAction(self.newWindowAct)
+        menu.addAction(self.openAct)
+        menu.addAction(self.openReadOnlyAct)
+        self.__menuRecentAct = menu.addMenu(self.__recentMenu)
+        menu.addSeparator()
+        menu.addAction(self.saveAct)
+        menu.addAction(self.saveAsAct)
+        menu.addAction(self.saveReadableAct)
+        menu.addSeparator()
+        menu.addAction(self.closeAct)
+        menu.addAction(self.closeOthersAct)
+        if self.__fromEric:
+            menu.addAction(self.closeAllAct)
+        else:
+            menu.addSeparator()
+            menu.addAction(self.exitAct)
+        menu.aboutToShow.connect(self.__showFileMenu)
+        self.__recentMenu.aboutToShow.connect(self.__showRecentMenu)
+        self.__recentMenu.triggered.connect(self.__openRecentHexFile)
+        
+        menu = mb.addMenu(self.tr("&Edit"))
+        menu.setTearOffEnabled(True)
+        menu.addAction(self.undoAct)
+        menu.addAction(self.redoAct)
+        menu.addAction(self.revertAct)
+        menu.addSeparator()
+        menu.addAction(self.cutAct)
+        menu.addAction(self.copyAct)
+        menu.addAction(self.pasteAct)
+        menu.addSeparator()
+        menu.addAction(self.selectAllAct)
+        menu.addAction(self.deselectAllAct)
+        menu.addAction(self.saveSelectionReadableAct)
+        menu.addSeparator()
+        menu.addAction(self.searchAct)
+        menu.addAction(self.searchNextAct)
+        menu.addAction(self.searchPrevAct)
+        menu.addAction(self.replaceAct)
+        menu.addSeparator()
+        menu.addAction(self.gotoAct)
+        menu.addSeparator()
+        menu.addAction(self.readonlyAct)
+        
+        if not self.__fromEric:
+            menu = mb.addMenu(self.tr("Se&ttings"))
+            menu.setTearOffEnabled(True)
+            menu.addAction(self.prefAct)
+        
+        mb.addSeparator()
+        
+        menu = mb.addMenu(self.tr("&Help"))
+        menu.addAction(self.aboutAct)
+        menu.addAction(self.aboutQtAct)
+        menu.addSeparator()
+        menu.addAction(self.whatsThisAct)
+    
+    def __initToolbars(self):
+        """
+        Private method to create the toolbars.
+        """
+        filetb = self.addToolBar(self.tr("File"))
+        filetb.setObjectName("FileToolBar")
+        filetb.setIconSize(UI.Config.ToolBarIconSize)
+        filetb.addAction(self.newWindowAct)
+        filetb.addAction(self.openAct)
+        filetb.addSeparator()
+        filetb.addAction(self.saveAct)
+        filetb.addAction(self.saveAsAct)
+        filetb.addSeparator()
+        filetb.addAction(self.closeAct)
+        if not self.__fromEric:
+            filetb.addAction(self.exitAct)
+        
+        edittb = self.addToolBar(self.tr("Edit"))
+        edittb.setObjectName("EditToolBar")
+        edittb.setIconSize(UI.Config.ToolBarIconSize)
+        edittb.addAction(self.undoAct)
+        edittb.addAction(self.redoAct)
+        edittb.addSeparator()
+        edittb.addAction(self.cutAct)
+        edittb.addAction(self.copyAct)
+        edittb.addAction(self.pasteAct)
+        
+        searchtb = self.addToolBar(self.tr("Find"))
+        searchtb.setObjectName("SearchToolBar")
+        searchtb.setIconSize(UI.Config.ToolBarIconSize)
+        searchtb.addAction(self.searchAct)
+        searchtb.addAction(self.searchNextAct)
+        searchtb.addAction(self.searchPrevAct)
+        
+        if not self.__fromEric:
+            settingstb = self.addToolBar(self.tr("Settings"))
+            settingstb.setObjectName("SettingsToolBar")
+            settingstb.setIconSize(UI.Config.ToolBarIconSize)
+            settingstb.addAction(self.prefAct)
+        
+        helptb = self.addToolBar(self.tr("Help"))
+        helptb.setObjectName("HelpToolBar")
+        helptb.setIconSize(UI.Config.ToolBarIconSize)
+        helptb.addAction(self.whatsThisAct)
+    
+    def __createStatusBar(self):
+        """
+        Private method to initialize the status bar.
+        """
+        self.__statusBar = self.statusBar()
+        self.__statusBar.setSizeGripEnabled(True)
+        
+        self.__sbAddress = QLabel(self.__statusBar)
+        self.__statusBar.addPermanentWidget(self.__sbAddress)
+        self.__sbAddress.setWhatsThis(self.tr(
+            """<p>This part of the status bar displays the cursor"""
+            """ address.</p>"""
+        ))
+        self.__sbAddress.setFrameStyle(
+            QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
+        
+        self.__sbSelection = QLabel(self.__statusBar)
+        self.__statusBar.addPermanentWidget(self.__sbSelection)
+        self.__sbSelection.setWhatsThis(self.tr(
+            """<p>This part of the status bar displays some selection"""
+            """ information.</p>"""
+        ))
+        self.__sbSelection.setFrameStyle(
+            QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
+        
+        self.__sbSize = QLabel(self.__statusBar)
+        self.__statusBar.addPermanentWidget(self.__sbSize)
+        self.__sbSize.setWhatsThis(self.tr(
+            """<p>This part of the status bar displays the size of the"""
+            """ binary data.</p>"""
+        ))
+        self.__sbSize.setFrameStyle(
+            QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
+        
+        self.__sbEditMode = E5ClickableLabel(self.__statusBar)
+        self.__statusBar.addPermanentWidget(self.__sbEditMode)
+        self.__sbEditMode.setWhatsThis(self.tr(
+            """<p>This part of the status bar displays the edit mode.</p>"""
+        ))
+        self.__sbEditMode.setFrameStyle(
+            QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
+        self.__sbEditMode.clicked.connect(self.__toggleEditMode)
+        
+        self.__sbReadOnly = E5ClickableLabel(self.__statusBar)
+        self.__statusBar.addPermanentWidget(self.__sbReadOnly)
+        self.__sbReadOnly.setWhatsThis(self.tr(
+            """<p>This part of the status bar displays the read"""
+            """ only mode.</p>"""
+        ))
+        self.__sbReadOnly.setFrameStyle(
+            QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
+        self.__sbReadOnly.clicked.connect(self.__toggleReadOnlyMode)
+
+        self.__showEditMode(self.__editor.overwriteMode())
+        self.__showReadOnlyMode(self.__editor.isReadOnly())
+    
+    @pyqtSlot(int)
+    def __showAddress(self, address):
+        """
+        Private slot to show the address of the cursor position.
+        
+        @param address address of the cursor
+        @type int
+        """
+        txt = "{0:0{1}x}".format(address, self.__editor.addressWidth())
+        txt = strGroup(txt, ":", 4)
+        self.__sbAddress.setText(self.tr("Address: {0}").format(txt))
+    
+    @pyqtSlot(bool)
+    def __showSelectionInfo(self, avail):
+        """
+        Private slot to show selection information.
+        
+        @param avail flag indicating the availability of a selection.
+        @type bool
+        """
+        if avail:
+            addrWidth = self.__editor.addressWidth()
+            start = "{0:0{1}x}".format(self.__editor.getSelectionBegin(),
+                                       addrWidth)
+            start = strGroup(start, ":", 4)
+            end = "{0:0{1}x}".format(self.__editor.getSelectionEnd(),
+                                     addrWidth)
+            end = strGroup(end, ":", 4)
+            slen = self.__editor.getSelectionLength()
+            self.__sbSelection.setText(
+                self.tr("Selection: {0} - {1} ({2} Bytes)",
+                        "0: start, 1: end, 2: selection length")
+                .format(start, end, QLocale().toString(slen))
+            )
+        else:
+            self.__sbSelection.setText(
+                self.tr("Selection: -", "no selection available"))
+    
+    @pyqtSlot(bool)
+    def __showReadOnlyMode(self, on):
+        """
+        Private slot to show the read only mode.
+        
+        @param on flag indicating the read only state
+        @type bool
+        """
+        self.__sbReadOnly.setText(self.tr("ro") if on else self.tr("rw"))
+    
+    @pyqtSlot()
+    def __toggleReadOnlyMode(self):
+        """
+        Private slot to toggle the read only mode upon a click on the status
+        bar label.
+        """
+        self.__editor.setReadOnly(not self.__editor.isReadOnly())
+    
+    @pyqtSlot(bool)
+    def __showEditMode(self, overwrite):
+        """
+        Private slot to show the edit mode.
+        
+        @param overwrite flag indicating overwrite mode
+        @type bool
+        """
+        self.__sbEditMode.setText(
+            self.tr("Overwrite") if overwrite else self.tr("Insert"))
+    
+    @pyqtSlot()
+    def __toggleEditMode(self):
+        """
+        Private slot to toggle the edit mode upon a click on the status bar
+        label.
+        """
+        self.__editor.setOverwriteMode(not self.__editor.overwriteMode())
+    
+    @pyqtSlot(int)
+    def __showSize(self, size):
+        """
+        Private slot to show the binary data size.
+        
+        @param size size of the binary data
+        @type int
+        """
+        self.__sbSize.setText(
+            self.tr("Size: {0}").format(QLocale().toString(size)))
+    
+    def closeEvent(self, evt):
+        """
+        Protected event handler for the close event.
+        
+        @param evt reference to the close event
+            <br />This event is simply accepted after the history has been
+            saved and all window references have been deleted.
+        @type QCloseEvent
+        """
+        if self.__maybeSave():
+            state = self.saveState()
+            Preferences.setHexEditor("HexEditorState", state)
+
+            Preferences.setGeometry("HexEditorGeometry", self.saveGeometry())
+            
+            with contextlib.suppress(ValueError):
+                if self.__fromEric or len(self.__class__.windows) > 1:
+                    del self.__class__.windows[
+                        self.__class__.windows.index(self)]
+            
+            if not self.__fromEric:
+                Preferences.syncPreferences()
+            
+            self.__saveRecent()
+            
+            evt.accept()
+            self.editorClosed.emit()
+        else:
+            evt.ignore()
+    
+    def __openHexFileNewWindow(self):
+        """
+        Private slot called to open a binary file in new hex editor window.
+        """
+        if (
+            not self.__lastOpenPath and
+            self.__project is not None and
+            self.__project.isOpen()
+        ):
+            self.__lastOpenPath = self.__project.getProjectPath()
+        
+        fileName = E5FileDialog.getOpenFileName(
+            self,
+            self.tr("Open binary file in new window"),
+            self.__lastOpenPath,
+            self.tr("All Files (*)"))
+        if fileName:
+            he = HexEditMainWindow(fileName=fileName,
+                                   parent=self.parent(),
+                                   fromEric=self.__fromEric,
+                                   project=self.__project)
+            he.setRecentPaths("", self.__lastSavePath)
+            he.show()
+    
+    def __maybeSave(self):
+        """
+        Private method to ask the user to save the file, if it was modified.
+        
+        @return flag indicating, if it is ok to continue
+        @rtype bool
+        """
+        if self.__editor.isModified():
+            ret = E5MessageBox.okToClearData(
+                self,
+                self.tr("eric Hex Editor"),
+                self.tr("""The loaded file has unsaved changes."""),
+                self.__saveHexFile)
+            if not ret:
+                return False
+        return True
+    
+    def __loadHexFile(self, fileName):
+        """
+        Private method to load a binary file.
+        
+        @param fileName name of the binary file to load
+        @type str
+        """
+        file = QFile(fileName)
+        if not file.exists():
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("The file '{0}' does not exist.")
+                .format(fileName))
+            return
+        
+        if not file.open(QFile.ReadOnly):
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("Cannot read file '{0}:\n{1}.")
+                .format(fileName, file.errorString()))
+            return
+        
+        data = file.readAll()
+        file.close()
+        
+        self.__lastOpenPath = os.path.dirname(fileName)
+        self.__editor.setData(data)
+        self.__setCurrentFile(fileName)
+        
+        self.__editor.setReadOnly(Preferences.getHexEditor("OpenReadOnly"))
+        
+        self.__gotoWidget.reset()
+    
+    def __openHexFile(self):
+        """
+        Private slot to open a binary file.
+        """
+        if self.__maybeSave():
+            if (
+                not self.__lastOpenPath and
+                self.__project is not None and
+                self.__project.isOpen()
+            ):
+                self.__lastOpenPath = self.__project.getProjectPath()
+            
+            fileName = E5FileDialog.getOpenFileName(
+                self,
+                self.tr("Open binary file"),
+                self.__lastOpenPath,
+                self.tr("All Files (*)"))
+            if fileName:
+                self.__loadHexFile(fileName)
+        self.__checkActions()
+    
+    def __openHexFileReadOnly(self):
+        """
+        Private slot to open a binary file in read only mode.
+        """
+        self.__openHexFile()
+        self.__editor.setReadOnly(not Preferences.getHexEditor("OpenReadOnly"))
+        self.__checkActions()
+    
+    def __saveHexFile(self):
+        """
+        Private method to save a binary file.
+        
+        @return flag indicating success
+        @rtype bool
+        """
+        ok = (
+            self.__saveHexDataFile(self.__fileName)
+            if self.__fileName else
+            self.__saveHexFileAs()
+        )
+        
+        if ok:
+            self.__editor.undoStack().setClean()
+        
+        return ok
+    
+    def __saveHexFileAs(self):
+        """
+        Private method to save the data to a new file.
+        
+        @return flag indicating success
+        @rtype bool
+        """
+        if (
+            not self.__lastSavePath and
+            self.__project is not None and
+            self.__project.isOpen()
+        ):
+            self.__lastSavePath = self.__project.getProjectPath()
+        if not self.__lastSavePath and self.__lastOpenPath:
+            self.__lastSavePath = self.__lastOpenPath
+        
+        fileName = E5FileDialog.getSaveFileName(
+            self,
+            self.tr("Save binary file"),
+            self.__lastSavePath,
+            self.tr("All Files (*)"),
+            E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
+        if not fileName:
+            return False
+        
+        if QFileInfo(fileName).exists():
+            res = E5MessageBox.yesNo(
+                self,
+                self.tr("Save binary file"),
+                self.tr("<p>The file <b>{0}</b> already exists."
+                        " Overwrite it?</p>").format(fileName),
+                icon=E5MessageBox.Warning)
+            if not res:
+                return False
+        
+        self.__lastSavePath = os.path.dirname(fileName)
+        
+        return self.__saveHexDataFile(fileName)
+    
+    def __saveHexDataFile(self, fileName):
+        """
+        Private method to save the binary data to a file.
+        
+        @param fileName name of the file to write to
+        @type str
+        @return flag indicating success
+        @rtype bool
+        """
+        file = QFile(fileName)
+        if not file.open(QFile.WriteOnly):
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("Cannot write file '{0}:\n{1}.")
+                .format(fileName, file.errorString()))
+        
+            self.__checkActions()
+            
+            return False
+        
+        res = file.write(self.__editor.data()) != -1
+        file.close()
+        
+        if not res:
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("Cannot write file '{0}:\n{1}.")
+                .format(fileName, file.errorString()))
+        
+            self.__checkActions()
+            
+            return False
+        
+        self.__editor.setModified(False, setCleanState=True)
+        
+        self.__setCurrentFile(fileName)
+        self.__statusBar.showMessage(self.tr("File saved"), 2000)
+        
+        self.__checkActions()
+        
+        return True
+    
+    def __saveHexFileReadable(self, selectionOnly=False):
+        """
+        Private method to save the binary data in readable format.
+        
+        @param selectionOnly flag indicating to save the selection only
+        @type bool
+        """
+        savePath = self.__lastSavePath
+        if (
+            not savePath and
+            self.__project is not None and
+            self.__project.isOpen()
+        ):
+            savePath = self.__project.getProjectPath()
+        if not savePath and self.__lastOpenPath:
+            savePath = self.__lastOpenPath
+        
+        fileName, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
+            self,
+            self.tr("Save to readable file"),
+            savePath,
+            self.tr("Text Files (*.txt);;All Files (*)"),
+            self.tr("Text Files (*.txt)"),
+            E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
+        if not fileName:
+            return
+        
+        ext = QFileInfo(fileName).suffix()
+        if not ext:
+            ex = selectedFilter.split("(*")[1].split(")")[0]
+            if ex:
+                fileName += ex
+        if QFileInfo(fileName).exists():
+            res = E5MessageBox.yesNo(
+                self,
+                self.tr("Save to readable file"),
+                self.tr("<p>The file <b>{0}</b> already exists."
+                        " Overwrite it?</p>").format(fileName),
+                icon=E5MessageBox.Warning)
+            if not res:
+                return
+        
+        file = QFile(fileName)
+        if not file.open(QFile.WriteOnly):
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("Cannot write file '{0}:\n{1}.")
+                .format(fileName, file.errorString()))
+            return
+        
+        readableData = (
+            self.__editor.selectionToReadableString()
+            if selectionOnly else
+            self.__editor.toReadableString()
+        )
+        res = file.write(readableData.encode("latin1")) != -1
+        file.close()
+        
+        if not res:
+            E5MessageBox.warning(
+                self, self.tr("eric Hex Editor"),
+                self.tr("Cannot write file '{0}:\n{1}.")
+                .format(fileName, file.errorString()))
+            return
+        
+        self.__statusBar.showMessage(self.tr("File saved"), 2000)
+    
+    def __saveSelectionReadable(self):
+        """
+        Private method to save the data of the current selection in readable
+        format.
+        """
+        self.__saveHexFileReadable(selectionOnly=True)
+    
+    def __closeAll(self):
+        """
+        Private slot to close all windows.
+        """
+        self.__closeOthers()
+        self.close()
+    
+    def __closeOthers(self):
+        """
+        Private slot to close all other windows.
+        """
+        for win in self.__class__.windows[:]:
+            if win != self:
+                win.close()
+
+    def __setCurrentFile(self, fileName):
+        """
+        Private method to register the file name of the current file.
+        
+        @param fileName name of the file to register
+        @type str
+        """
+        self.__fileName = fileName
+        # insert filename into list of recently opened files
+        self.__addToRecentList(fileName)
+        
+        shownName = (
+            self.tr("Untitled")
+            if not self.__fileName else
+            self.__strippedName(self.__fileName)
+        )
+        
+        self.setWindowTitle(self.tr("{0}[*] - {1}")
+                            .format(shownName, self.tr("Hex Editor")))
+        
+        self.setWindowModified(self.__editor.isModified())
+    
+    def __strippedName(self, fullFileName):
+        """
+        Private method to return the filename part of the given path.
+        
+        @param fullFileName full pathname of the given file
+        @type str
+        @return filename part
+        @rtype str
+        """
+        return QFileInfo(fullFileName).fileName()
+    
+    def setRecentPaths(self, openPath, savePath):
+        """
+        Public method to set the last open and save paths.
+        
+        @param openPath least recently used open path
+        @type str
+        @param savePath least recently used save path
+        @type str
+        """
+        if openPath:
+            self.__lastOpenPath = openPath
+        if savePath:
+            self.__lastSavePath = savePath
+    
+    @pyqtSlot()
+    def __checkActions(self):
+        """
+        Private slot to check some actions for their enable/disable status.
+        """
+        self.saveAct.setEnabled(self.__editor.isModified())
+        
+        self.cutAct.setEnabled(not self.__editor.isReadOnly() and
+                               self.__editor.hasSelection())
+        self.pasteAct.setEnabled(not self.__editor.isReadOnly())
+        self.replaceAct.setEnabled(not self.__editor.isReadOnly())
+    
+    @pyqtSlot(bool)
+    def __modificationChanged(self, m):
+        """
+        Private slot to handle the dataChanged signal.
+        
+        @param m modification status
+        @type bool
+        """
+        self.setWindowModified(m)
+        self.__checkActions()
+    
+    def __about(self):
+        """
+        Private slot to show a little About message.
+        """
+        E5MessageBox.about(
+            self, self.tr("About eric Hex Editor"),
+            self.tr("The eric Hex Editor is a simple editor component"
+                    " to edit binary files."))
+    
+    def __aboutQt(self):
+        """
+        Private slot to handle the About Qt dialog.
+        """
+        E5MessageBox.aboutQt(self, "eric Hex Editor")
+    
+    def __whatsThis(self):
+        """
+        Private slot called in to enter Whats This mode.
+        """
+        QWhatsThis.enterWhatsThisMode()
+        
+    def __search(self):
+        """
+        Private method to handle the search action.
+        """
+        self.__replaceWidget.hide()
+        self.__gotoWidget.hide()
+        txt = (
+            self.__editor.selectionToHexString()
+            if self.__editor.hasSelection() else
+            ""
+        )
+        self.__searchWidget.show(txt)
+        
+    def __replace(self):
+        """
+        Private method to handle the replace action.
+        """
+        self.__searchWidget.hide()
+        self.__gotoWidget.hide()
+        txt = (
+            self.__editor.selectionToHexString()
+            if self.__editor.hasSelection() else
+            ""
+        )
+        self.__replaceWidget.show(txt)
+    
+    def __goto(self):
+        """
+        Private method to handle the goto action.
+        """
+        self.__searchWidget.hide()
+        self.__replaceWidget.hide()
+        self.__gotoWidget.show()
+    
+    def preferencesChanged(self):
+        """
+        Public method to (re-)read the various settings.
+        """
+        self.__editor.setAddressWidth(
+            Preferences.getHexEditor("AddressAreaWidth"))
+        self.__editor.setAddressArea(
+            Preferences.getHexEditor("ShowAddressArea"))
+        self.__editor.setAsciiArea(
+            Preferences.getHexEditor("ShowAsciiArea"))
+        self.__editor.setHighlighting(
+            Preferences.getHexEditor("HighlightChanges"))
+        self.__editor.setHighlightColors(
+            Preferences.getHexEditor("HighlightingForeGround"),
+            Preferences.getHexEditor("HighlightingBackGround"))
+        self.__editor.setSelectionColors(
+            Preferences.getHexEditor("SelectionForeGround"),
+            Preferences.getHexEditor("SelectionBackGround"))
+        self.__editor.setAddressAreaColors(
+            Preferences.getHexEditor("AddressAreaForeGround"),
+            Preferences.getHexEditor("AddressAreaBackGround"))
+        self.__editor.setFont(
+            Preferences.getHexEditor("Font"))
+        
+        self.__setReadOnlyActionTexts()
+    
+    def __showPreferences(self):
+        """
+        Private slot to set the preferences.
+        """
+        from Preferences.ConfigurationDialog import (
+            ConfigurationDialog, ConfigurationMode
+        )
+        dlg = ConfigurationDialog(
+            None, 'Configuration', True, fromEric=True,
+            displayMode=ConfigurationMode.HEXEDITORMODE)
+        dlg.preferencesChanged.connect(
+            self.__preferencesChangedByLocalPreferencesDialog)
+        dlg.show()
+        dlg.showConfigurationPageByName("hexEditorPage")
+        dlg.exec()
+        QCoreApplication.processEvents()
+        if dlg.result() == QDialog.DialogCode.Accepted:
+            dlg.setPreferences()
+            Preferences.syncPreferences()
+            self.__preferencesChangedByLocalPreferencesDialog()
+    
+    def __preferencesChangedByLocalPreferencesDialog(self):
+        """
+        Private slot to handle preferences changes by our local dialog.
+        """
+        for hexEditor in HexEditMainWindow.windows:
+            hexEditor.preferencesChanged()
+    
+    def getSRHistory(self, key):
+        """
+        Public method to get the search or replace history list.
+        
+        @param key name of list to return
+        @type str (must be 'search' or 'replace')
+        @return the requested history list
+        @rtype list of tuples of (int, str)
+        """
+        if key in ['search', 'replace']:
+            return self.__srHistory[key]
+        
+        return []
+    
+    @pyqtSlot()
+    def __showFileMenu(self):
+        """
+        Private slot to modify the file menu before being shown.
+        """
+        self.__menuRecentAct.setEnabled(len(self.__recent) > 0)
+    
+    @pyqtSlot()
+    def __showRecentMenu(self):
+        """
+        Private slot to set up the recent files menu.
+        """
+        self.__loadRecent()
+        
+        self.__recentMenu.clear()
+        
+        for idx, rs in enumerate(self.__recent, start=1):
+            formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
+            act = self.__recentMenu.addAction(
+                formatStr.format(
+                    idx,
+                    Utilities.compactPath(
+                        rs, HexEditMainWindow.maxMenuFilePathLen)))
+            act.setData(rs)
+            act.setEnabled(QFileInfo(rs).exists())
+        
+        self.__recentMenu.addSeparator()
+        self.__recentMenu.addAction(self.tr('&Clear'), self.__clearRecent)
+    
+    @pyqtSlot(QAction)
+    def __openRecentHexFile(self, act):
+        """
+        Private method to open a file from the list of recently opened files.
+        
+        @param act reference to the action that triggered (QAction)
+        """
+        fileName = act.data()
+        if fileName and self.__maybeSave():
+            self.__loadHexFile(fileName)
+            self.__editor.setReadOnly(Preferences.getHexEditor("OpenReadOnly"))
+            self.__checkActions()
+    
+    @pyqtSlot()
+    def __clearRecent(self):
+        """
+        Private method to clear the list of recently opened files.
+        """
+        self.__recent = []
+    
+    def __loadRecent(self):
+        """
+        Private method to load the list of recently opened files.
+        """
+        self.__recent = []
+        Preferences.Prefs.rsettings.sync()
+        rs = Preferences.Prefs.rsettings.value(recentNameHexFiles)
+        if rs is not None:
+            for f in Preferences.toList(rs):
+                if QFileInfo(f).exists():
+                    self.__recent.append(f)
+        
+    def __saveRecent(self):
+        """
+        Private method to save the list of recently opened files.
+        """
+        Preferences.Prefs.rsettings.setValue(recentNameHexFiles, self.__recent)
+        Preferences.Prefs.rsettings.sync()
+    
+    def __addToRecentList(self, fileName):
+        """
+        Private method to add a file name to the list of recently opened files.
+        
+        @param fileName name of the file to be added
+        """
+        if fileName:
+            for recent in self.__recent[:]:
+                if Utilities.samepath(fileName, recent):
+                    self.__recent.remove(recent)
+            self.__recent.insert(0, fileName)
+            maxRecent = Preferences.getHexEditor("RecentNumber")
+            if len(self.__recent) > maxRecent:
+                self.__recent = self.__recent[:maxRecent]
+            self.__saveRecent()

eric ide

mercurial