src/eric7/HexEdit/HexEditMainWindow.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9165
17617e5d5473
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the hex editor main window.
8 """
9
10 import os
11 import contextlib
12 import pathlib
13
14 from PyQt6.QtCore import (
15 pyqtSignal, pyqtSlot, QSize, QCoreApplication, QLocale
16 )
17 from PyQt6.QtGui import QKeySequence, QAction
18 from PyQt6.QtWidgets import (
19 QWhatsThis, QLabel, QWidget, QVBoxLayout, QDialog, QFrame, QMenu
20 )
21
22 from EricGui.EricAction import EricAction
23 from EricWidgets.EricMainWindow import EricMainWindow
24 from EricWidgets import EricFileDialog, EricMessageBox
25 from EricWidgets.EricClickableLabel import EricClickableLabel
26
27 from Globals import strGroup, recentNameHexFiles
28
29 from .HexEditWidget import HexEditWidget
30 from .HexEditSearchReplaceWidget import HexEditSearchReplaceWidget
31 from .HexEditGotoWidget import HexEditGotoWidget
32
33 import UI.PixmapCache
34 import UI.Config
35
36 import Preferences
37 import Utilities
38
39
40 class HexEditMainWindow(EricMainWindow):
41 """
42 Class implementing the web browser main window.
43
44 @signal editorClosed() emitted after the window was requested to close down
45 """
46 editorClosed = pyqtSignal()
47
48 windows = []
49
50 maxMenuFilePathLen = 75
51
52 def __init__(self, fileName="", parent=None, fromEric=False, project=None):
53 """
54 Constructor
55
56 @param fileName name of a file to load on startup (string)
57 @param parent parent widget of this window (QWidget)
58 @param fromEric flag indicating whether it was called from within
59 eric (boolean)
60 @param project reference to the project object (Project)
61 """
62 super().__init__(parent)
63 self.setObjectName("eric7_hex_editor")
64
65 self.__srHistory = {
66 "search": [],
67 # list of recent searches (tuple of format type index and
68 # search term)
69 "replace": [],
70 # list of recent replaces (tuple of format type index and
71 # replace term
72 }
73
74 self.__fromEric = fromEric
75 self.setWindowIcon(UI.PixmapCache.getIcon("hexEditor"))
76
77 if not self.__fromEric:
78 self.setStyle(Preferences.getUI("Style"),
79 Preferences.getUI("StyleSheet"))
80
81 self.__editor = HexEditWidget()
82 self.__searchWidget = HexEditSearchReplaceWidget(
83 self.__editor, self, False)
84 self.__replaceWidget = HexEditSearchReplaceWidget(
85 self.__editor, self, True)
86 self.__gotoWidget = HexEditGotoWidget(self.__editor)
87 cw = QWidget()
88 layout = QVBoxLayout(cw)
89 layout.setContentsMargins(1, 1, 1, 1)
90 layout.setSpacing(1)
91 layout.addWidget(self.__editor)
92 layout.addWidget(self.__searchWidget)
93 layout.addWidget(self.__gotoWidget)
94 cw.setLayout(layout)
95 layout.addWidget(self.__replaceWidget)
96 self.__searchWidget.hide()
97 self.__replaceWidget.hide()
98 self.__gotoWidget.hide()
99 self.setCentralWidget(cw)
100
101 g = Preferences.getGeometry("HexEditorGeometry")
102 if g.isEmpty():
103 s = QSize(600, 500)
104 self.resize(s)
105 else:
106 self.restoreGeometry(g)
107
108 self.__initActions()
109 self.__initMenus()
110 self.__initToolbars()
111 self.__createStatusBar()
112
113 self.__class__.windows.append(self)
114
115 state = Preferences.getHexEditor("HexEditorState")
116 self.restoreState(state)
117
118 self.__editor.currentAddressChanged.connect(self.__showAddress)
119 self.__editor.selectionAvailable.connect(self.__showSelectionInfo)
120 self.__editor.currentSizeChanged.connect(self.__showSize)
121 self.__editor.dataChanged.connect(self.__modificationChanged)
122 self.__editor.overwriteModeChanged.connect(self.__showEditMode)
123 self.__editor.readOnlyChanged.connect(self.__showReadOnlyMode)
124 self.__editor.readOnlyChanged.connect(self.__checkActions)
125
126 self.preferencesChanged()
127 self.__editor.setOverwriteMode(
128 Preferences.getHexEditor("OpenInOverwriteMode"))
129
130 self.__project = project
131 self.__lastOpenPath = ""
132 self.__lastSavePath = ""
133
134 self.__recent = []
135 self.__loadRecent()
136
137 self.__setCurrentFile("")
138 if fileName:
139 self.__loadHexFile(fileName)
140
141 self.__checkActions()
142
143 def __initActions(self):
144 """
145 Private method to define the user interface actions.
146 """
147 # list of all actions
148 self.__actions = []
149
150 self.__initFileActions()
151 self.__initEditActions()
152 self.__initHelpActions()
153 if not self.__fromEric:
154 self.__initConfigActions()
155
156 def __initFileActions(self):
157 """
158 Private method to define the file related user interface actions.
159 """
160 self.newWindowAct = EricAction(
161 self.tr('New Window'),
162 UI.PixmapCache.getIcon("newWindow"),
163 self.tr('New &Window'),
164 0, 0, self, 'hexEditor_file_new_window')
165 self.newWindowAct.setStatusTip(self.tr(
166 'Open a binary file for editing in a new hex editor window'))
167 self.newWindowAct.setWhatsThis(self.tr(
168 """<b>New Window</b>"""
169 """<p>This opens a binary file for editing in a new hex editor"""
170 """ window.</p>"""
171 ))
172 self.newWindowAct.triggered.connect(self.__openHexFileNewWindow)
173 self.__actions.append(self.newWindowAct)
174
175 # correct texts will be set later
176 self.openAct = EricAction(
177 self.tr('Open'),
178 UI.PixmapCache.getIcon("open"),
179 self.tr('&Open...'),
180 QKeySequence(self.tr("Ctrl+O", "File|Open")),
181 0, self, 'hexEditor_file_open')
182 self.openAct.triggered.connect(self.__openHexFile)
183 self.__actions.append(self.openAct)
184
185 # correct texts will be set later
186 self.openReadOnlyAct = EricAction(
187 "", "",
188 0, 0, self, 'hexEditor_file_open_read_only')
189 self.openReadOnlyAct.triggered.connect(self.__openHexFileReadOnly)
190 self.__actions.append(self.openReadOnlyAct)
191
192 self.saveAct = EricAction(
193 self.tr('Save'),
194 UI.PixmapCache.getIcon("fileSave"),
195 self.tr('&Save'),
196 QKeySequence(self.tr("Ctrl+S", "File|Save")),
197 0, self, 'hexEditor_file_save')
198 self.saveAct.setStatusTip(self.tr('Save the current binary file'))
199 self.saveAct.setWhatsThis(self.tr(
200 """<b>Save File</b>"""
201 """<p>Save the contents of the hex editor window.</p>"""
202 ))
203 self.saveAct.triggered.connect(self.__saveHexFile)
204 self.__actions.append(self.saveAct)
205
206 self.saveAsAct = EricAction(
207 self.tr('Save As'),
208 UI.PixmapCache.getIcon("fileSaveAs"),
209 self.tr('Save &As...'),
210 QKeySequence(self.tr("Shift+Ctrl+S", "File|Save As")),
211 0, self, 'hexEditor_file_save_as')
212 self.saveAsAct.setStatusTip(
213 self.tr('Save the current binary data to a new file'))
214 self.saveAsAct.setWhatsThis(self.tr(
215 """<b>Save As...</b>"""
216 """<p>Saves the current binary data to a new file.</p>"""
217 ))
218 self.saveAsAct.triggered.connect(self.__saveHexFileAs)
219 self.__actions.append(self.saveAsAct)
220
221 self.saveReadableAct = EricAction(
222 self.tr('Save As Readable'),
223 self.tr('Save As &Readable...'),
224 0, 0, self, 'hexEditor_file_save_readable')
225 self.saveReadableAct.setStatusTip(
226 self.tr('Save the current binary data to a new file in a readable'
227 ' format'))
228 self.saveReadableAct.setWhatsThis(self.tr(
229 """<b>Save As Readable...</b>"""
230 """<p>Saves the current binary data to a new file in a readable"""
231 """ format.</p>"""
232 ))
233 self.saveReadableAct.triggered.connect(self.__saveHexFileReadable)
234 self.__actions.append(self.saveReadableAct)
235
236 self.closeAct = EricAction(
237 self.tr('Close'),
238 UI.PixmapCache.getIcon("close"),
239 self.tr('&Close'),
240 QKeySequence(self.tr("Ctrl+W", "File|Close")),
241 0, self, 'hexEditor_file_close')
242 self.closeAct.setStatusTip(self.tr(
243 'Close the current hex editor window'))
244 self.closeAct.setWhatsThis(self.tr(
245 """<b>Close</b>"""
246 """<p>Closes the current hex editor window.</p>"""
247 ))
248 self.closeAct.triggered.connect(self.close)
249 self.__actions.append(self.closeAct)
250
251 self.closeAllAct = EricAction(
252 self.tr('Close All'),
253 self.tr('Close &All'),
254 0, 0, self, 'hexEditor_file_close_all')
255 self.closeAllAct.setStatusTip(self.tr(
256 'Close all hex editor windows'))
257 self.closeAllAct.setWhatsThis(self.tr(
258 """<b>Close All</b>"""
259 """<p>Closes all hex editor windows.</p>"""
260 ))
261 self.closeAllAct.triggered.connect(self.__closeAll)
262 self.__actions.append(self.closeAllAct)
263
264 self.closeOthersAct = EricAction(
265 self.tr('Close Others'),
266 self.tr('Close Others'),
267 0, 0, self, 'hexEditor_file_close_others')
268 self.closeOthersAct.setStatusTip(self.tr(
269 'Close all other hex editor windows'))
270 self.closeOthersAct.setWhatsThis(self.tr(
271 """<b>Close Others</b>"""
272 """<p>Closes all other hex editor windows.</p>"""
273 ))
274 self.closeOthersAct.triggered.connect(self.__closeOthers)
275 self.__actions.append(self.closeOthersAct)
276
277 self.exitAct = EricAction(
278 self.tr('Quit'),
279 UI.PixmapCache.getIcon("exit"),
280 self.tr('&Quit'),
281 QKeySequence(self.tr("Ctrl+Q", "File|Quit")),
282 0, self, 'hexEditor_file_quit')
283 self.exitAct.setStatusTip(self.tr('Quit the hex editor'))
284 self.exitAct.setWhatsThis(self.tr(
285 """<b>Quit</b>"""
286 """<p>Quit the hex editor.</p>"""
287 ))
288 if not self.__fromEric:
289 self.exitAct.triggered.connect(self.__closeAll)
290 self.__actions.append(self.exitAct)
291
292 def __initEditActions(self):
293 """
294 Private method to create the Edit actions.
295 """
296 self.undoAct = EricAction(
297 self.tr('Undo'),
298 UI.PixmapCache.getIcon("editUndo"),
299 self.tr('&Undo'),
300 QKeySequence(self.tr("Ctrl+Z", "Edit|Undo")),
301 QKeySequence(self.tr("Alt+Backspace", "Edit|Undo")),
302 self, 'hexEditor_edit_undo')
303 self.undoAct.setStatusTip(self.tr('Undo the last change'))
304 self.undoAct.setWhatsThis(self.tr(
305 """<b>Undo</b>"""
306 """<p>Undo the last change done.</p>"""
307 ))
308 self.undoAct.triggered.connect(self.__editor.undo)
309 self.__actions.append(self.undoAct)
310
311 self.redoAct = EricAction(
312 self.tr('Redo'),
313 UI.PixmapCache.getIcon("editRedo"),
314 self.tr('&Redo'),
315 QKeySequence(self.tr("Ctrl+Shift+Z", "Edit|Redo")),
316 0, self, 'hexEditor_edit_redo')
317 self.redoAct.setStatusTip(self.tr('Redo the last change'))
318 self.redoAct.setWhatsThis(self.tr(
319 """<b>Redo</b>"""
320 """<p>Redo the last change done.</p>"""
321 ))
322 self.redoAct.triggered.connect(self.__editor.redo)
323 self.__actions.append(self.redoAct)
324
325 self.revertAct = EricAction(
326 self.tr('Revert to last saved state'),
327 self.tr('Re&vert to last saved state'),
328 QKeySequence(self.tr("Ctrl+Y", "Edit|Revert")),
329 0,
330 self, 'hexEditor_edit_revert')
331 self.revertAct.setStatusTip(self.tr('Revert to last saved state'))
332 self.revertAct.setWhatsThis(self.tr(
333 """<b>Revert to last saved state</b>"""
334 """<p>Undo all changes up to the last saved state of the"""
335 """ editor.</p>"""
336 ))
337 self.revertAct.triggered.connect(self.__editor.revertToUnmodified)
338 self.__actions.append(self.revertAct)
339
340 self.cutAct = EricAction(
341 self.tr('Cut'),
342 UI.PixmapCache.getIcon("editCut"),
343 self.tr('Cu&t'),
344 QKeySequence(self.tr("Ctrl+X", "Edit|Cut")),
345 QKeySequence(self.tr("Shift+Del", "Edit|Cut")),
346 self, 'hexEditor_edit_cut')
347 self.cutAct.setStatusTip(self.tr('Cut the selection'))
348 self.cutAct.setWhatsThis(self.tr(
349 """<b>Cut</b>"""
350 """<p>Cut the selected binary area to the clipboard.</p>"""
351 ))
352 self.cutAct.triggered.connect(self.__editor.cut)
353 self.__actions.append(self.cutAct)
354
355 self.copyAct = EricAction(
356 self.tr('Copy'),
357 UI.PixmapCache.getIcon("editCopy"),
358 self.tr('&Copy'),
359 QKeySequence(self.tr("Ctrl+C", "Edit|Copy")),
360 QKeySequence(self.tr("Ctrl+Ins", "Edit|Copy")),
361 self, 'hexEditor_edit_copy')
362 self.copyAct.setStatusTip(self.tr('Copy the selection'))
363 self.copyAct.setWhatsThis(self.tr(
364 """<b>Copy</b>"""
365 """<p>Copy the selected binary area to the clipboard.</p>"""
366 ))
367 self.copyAct.triggered.connect(self.__editor.copy)
368 self.__actions.append(self.copyAct)
369
370 self.pasteAct = EricAction(
371 self.tr('Paste'),
372 UI.PixmapCache.getIcon("editPaste"),
373 self.tr('&Paste'),
374 QKeySequence(self.tr("Ctrl+V", "Edit|Paste")),
375 QKeySequence(self.tr("Shift+Ins", "Edit|Paste")),
376 self, 'hexEditor_edit_paste')
377 self.pasteAct.setStatusTip(self.tr('Paste the clipboard contents'))
378 self.pasteAct.setWhatsThis(self.tr(
379 """<b>Paste</b>"""
380 """<p>Paste the clipboard contents.</p>"""
381 ))
382 self.pasteAct.triggered.connect(self.__editor.paste)
383 self.__actions.append(self.pasteAct)
384
385 self.selectAllAct = EricAction(
386 self.tr('Select All'),
387 UI.PixmapCache.getIcon("editSelectAll"),
388 self.tr('&Select All'),
389 QKeySequence(self.tr("Ctrl+A", "Edit|Select All")),
390 0,
391 self, 'hexEditor_edit_select_all')
392 self.selectAllAct.setStatusTip(self.tr(
393 'Select the complete binary data'))
394 self.selectAllAct.setWhatsThis(self.tr(
395 """<b>Select All</b>"""
396 """<p>Selects the complete binary data.</p>"""
397 ))
398 self.selectAllAct.triggered.connect(self.__editor.selectAll)
399 self.__actions.append(self.selectAllAct)
400
401 self.deselectAllAct = EricAction(
402 self.tr('Deselect all'),
403 self.tr('&Deselect all'),
404 QKeySequence(self.tr("Alt+Ctrl+A", "Edit|Deselect all")),
405 0,
406 self, 'hexEditor_edit_deselect_all')
407 self.deselectAllAct.setStatusTip(self.tr('Deselect all binary data'))
408 self.deselectAllAct.setWhatsThis(self.tr(
409 """<b>Deselect All</b>"""
410 """<p>Deselect all all binary data.</p>"""
411 ))
412 self.deselectAllAct.triggered.connect(self.__editor.deselectAll)
413 self.__actions.append(self.deselectAllAct)
414
415 self.saveSelectionReadableAct = EricAction(
416 self.tr('Save Selection Readable'),
417 self.tr('Save Selection Readable...'),
418 0, 0, self, 'hexEditor_edit_selection_save_readable')
419 self.saveSelectionReadableAct.setStatusTip(
420 self.tr('Save the binary data of the current selection to a file'
421 ' in a readable format'))
422 self.saveSelectionReadableAct.setWhatsThis(self.tr(
423 """<b>Save Selection Readable...</b>"""
424 """<p>Saves the binary data of the current selection to a file"""
425 """ in a readable format.</p>"""
426 ))
427 self.saveSelectionReadableAct.triggered.connect(
428 self.__saveSelectionReadable)
429 self.__actions.append(self.saveSelectionReadableAct)
430
431 self.readonlyAct = EricAction(
432 self.tr('Set Read Only'),
433 self.tr('Set Read Only'),
434 0, 0, self, 'hexEditor_edit_readonly', True)
435 self.readonlyAct.setStatusTip(self.tr(
436 'Change the edit mode to read only'))
437 self.readonlyAct.setWhatsThis(self.tr(
438 """<b>Set Read Only</b>"""
439 """<p>This changes the edit mode to read only (i.e. to view"""
440 """ mode).</p>"""
441 ))
442 self.readonlyAct.setChecked(False)
443 self.readonlyAct.toggled[bool].connect(self.__editor.setReadOnly)
444 self.__editor.readOnlyChanged.connect(self.readonlyAct.setChecked)
445 self.__actions.append(self.readonlyAct)
446
447 self.searchAct = EricAction(
448 self.tr('Search'),
449 UI.PixmapCache.getIcon("find"),
450 self.tr('&Search...'),
451 QKeySequence(self.tr("Ctrl+F", "Search|Search")),
452 0,
453 self, 'hexEditor_edit_search')
454 self.searchAct.setStatusTip(self.tr('Search for data'))
455 self.searchAct.setWhatsThis(self.tr(
456 """<b>Search</b>"""
457 """<p>Search for some data. A dialog is shown to enter the"""
458 """ data to search for in various formats.</p>"""
459 ))
460 self.searchAct.triggered.connect(self.__search)
461 self.__actions.append(self.searchAct)
462
463 self.searchNextAct = EricAction(
464 self.tr('Search next'),
465 UI.PixmapCache.getIcon("findNext"),
466 self.tr('Search &next'),
467 QKeySequence(self.tr("F3", "Search|Search next")),
468 0,
469 self, 'hexEditor_edit_search_next')
470 self.searchNextAct.setStatusTip(self.tr(
471 'Search next occurrence'))
472 self.searchNextAct.setWhatsThis(self.tr(
473 """<b>Search next</b>"""
474 """<p>Search the next occurrence of some data. The previously"""
475 """ entered search data are reused.</p>"""
476 ))
477 self.searchNextAct.triggered.connect(self.__searchWidget.findPrevNext)
478 self.__actions.append(self.searchNextAct)
479
480 self.searchPrevAct = EricAction(
481 self.tr('Search previous'),
482 UI.PixmapCache.getIcon("findPrev"),
483 self.tr('Search &previous'),
484 QKeySequence(self.tr("Shift+F3", "Search|Search previous")),
485 0,
486 self, 'hexEditor_edit_search_previous')
487 self.searchPrevAct.setStatusTip(self.tr(
488 'Search previous occurrence'))
489 self.searchPrevAct.setWhatsThis(self.tr(
490 """<b>Search previous</b>"""
491 """<p>Search the previous occurrence of some data. The"""
492 """ previously entered search data are reused.</p>"""
493 ))
494 self.searchPrevAct.triggered.connect(
495 lambda: self.__searchWidget.findPrevNext(True))
496 self.__actions.append(self.searchPrevAct)
497
498 self.replaceAct = EricAction(
499 self.tr('Replace'),
500 self.tr('&Replace...'),
501 QKeySequence(self.tr("Ctrl+R", "Search|Replace")),
502 0,
503 self, 'hexEditor_edit_search_replace')
504 self.replaceAct.setStatusTip(self.tr('Replace data'))
505 self.replaceAct.setWhatsThis(self.tr(
506 """<b>Replace</b>"""
507 """<p>Search for some data and replace it."""
508 """ A dialog is shown to enter the data to search for and the"""
509 """ replacement data in various formats.</p>"""
510 ))
511 self.replaceAct.triggered.connect(self.__replace)
512 self.__actions.append(self.replaceAct)
513
514 self.gotoAct = EricAction(
515 self.tr('Goto Offset'),
516 UI.PixmapCache.getIcon("goto"),
517 self.tr('&Goto Offset...'),
518 QKeySequence(QCoreApplication.translate(
519 'ViewManager', "Ctrl+G", "Search|Goto Offset")),
520 0,
521 self, 'hexEditor_edit_goto')
522 self.gotoAct.setStatusTip(self.tr('Goto Offset'))
523 self.gotoAct.setWhatsThis(self.tr(
524 """<b>Goto Offset</b>"""
525 """<p>Go to a specific address. A dialog is shown to enter"""
526 """ the movement data.</p>"""
527 ))
528 self.gotoAct.triggered.connect(self.__goto)
529 self.__actions.append(self.gotoAct)
530
531 self.redoAct.setEnabled(False)
532 self.__editor.canRedoChanged.connect(self.redoAct.setEnabled)
533
534 self.undoAct.setEnabled(False)
535 self.__editor.canUndoChanged.connect(self.undoAct.setEnabled)
536
537 self.revertAct.setEnabled(False)
538 self.__editor.dataChanged.connect(self.revertAct.setEnabled)
539
540 self.cutAct.setEnabled(False)
541 self.copyAct.setEnabled(False)
542 self.saveSelectionReadableAct.setEnabled(False)
543 self.__editor.selectionAvailable.connect(self.__checkActions)
544 self.__editor.selectionAvailable.connect(self.copyAct.setEnabled)
545 self.__editor.selectionAvailable.connect(
546 self.saveSelectionReadableAct.setEnabled)
547
548 def __initHelpActions(self):
549 """
550 Private method to create the Help actions.
551 """
552 self.aboutAct = EricAction(
553 self.tr('About'),
554 self.tr('&About'),
555 0, 0, self, 'hexEditor_help_about')
556 self.aboutAct.setStatusTip(self.tr(
557 'Display information about this software'))
558 self.aboutAct.setWhatsThis(self.tr(
559 """<b>About</b>"""
560 """<p>Display some information about this software.</p>"""))
561 self.aboutAct.triggered.connect(self.__about)
562 self.__actions.append(self.aboutAct)
563
564 self.aboutQtAct = EricAction(
565 self.tr('About Qt'),
566 self.tr('About &Qt'),
567 0, 0, self, 'hexEditor_help_about_qt')
568 self.aboutQtAct.setStatusTip(
569 self.tr('Display information about the Qt toolkit'))
570 self.aboutQtAct.setWhatsThis(self.tr(
571 """<b>About Qt</b>"""
572 """<p>Display some information about the Qt toolkit.</p>"""
573 ))
574 self.aboutQtAct.triggered.connect(self.__aboutQt)
575 self.__actions.append(self.aboutQtAct)
576
577 self.whatsThisAct = EricAction(
578 self.tr('What\'s This?'),
579 UI.PixmapCache.getIcon("whatsThis"),
580 self.tr('&What\'s This?'),
581 QKeySequence(self.tr("Shift+F1", "Help|What's This?'")),
582 0, self, 'hexEditor_help_whats_this')
583 self.whatsThisAct.setStatusTip(self.tr('Context sensitive help'))
584 self.whatsThisAct.setWhatsThis(self.tr(
585 """<b>Display context sensitive help</b>"""
586 """<p>In What's This? mode, the mouse cursor shows an arrow"""
587 """ with a question mark, and you can click on the interface"""
588 """ elements to get a short description of what they do and"""
589 """ how to use them. In dialogs, this feature can be accessed"""
590 """ using the context help button in the titlebar.</p>"""
591 ))
592 self.whatsThisAct.triggered.connect(self.__whatsThis)
593 self.__actions.append(self.whatsThisAct)
594
595 def __initConfigActions(self):
596 """
597 Private method to create the Settings actions.
598 """
599 self.prefAct = EricAction(
600 self.tr('Preferences'),
601 UI.PixmapCache.getIcon("configure"),
602 self.tr('&Preferences...'),
603 0, 0, self, 'hexEditor_settings_preferences')
604 self.prefAct.setStatusTip(self.tr(
605 'Set the prefered configuration'))
606 self.prefAct.setWhatsThis(self.tr(
607 """<b>Preferences</b>"""
608 """<p>Set the configuration items of the application"""
609 """ with your prefered values.</p>"""
610 ))
611 self.prefAct.triggered.connect(self.__showPreferences)
612 self.prefAct.setMenuRole(QAction.MenuRole.PreferencesRole)
613 self.__actions.append(self.prefAct)
614
615 def __setReadOnlyActionTexts(self):
616 """
617 Private method to switch the 'Open Read Only' action between
618 'read only' and 'read write'.
619 """
620 if Preferences.getHexEditor("OpenReadOnly"):
621 self.openAct.setStatusTip(self.tr(
622 'Open a binary file for viewing'))
623 self.openAct.setWhatsThis(self.tr(
624 """<b>Open File</b>"""
625 """<p>This opens a binary file for viewing (i.e. in read"""
626 """ only mode). It pops up a file selection dialog.</p>"""
627 ))
628
629 self.openReadOnlyAct.setText(self.tr('Open for Editing...'))
630 self.openReadOnlyAct.setIconText(self.tr('Open for Editing'))
631 self.openReadOnlyAct.setStatusTip(self.tr(
632 'Open a binary file for editing'))
633 self.openReadOnlyAct.setWhatsThis(self.tr(
634 """<b>Open for Editing</b>"""
635 """<p>This opens a binary file for editing."""
636 """ It pops up a file selection dialog.</p>"""
637 ))
638 else:
639 self.openAct.setStatusTip(self.tr(
640 'Open a binary file for editing'))
641 self.openAct.setWhatsThis(self.tr(
642 """<b>Open File</b>"""
643 """<p>This opens a binary file for editing."""
644 """ It pops up a file selection dialog.</p>"""
645 ))
646
647 self.openReadOnlyAct.setText(self.tr('Open Read Only...'))
648 self.openReadOnlyAct.setIconText(self.tr('Open Read Only'))
649 self.openReadOnlyAct.setStatusTip(self.tr(
650 'Open a binary file for viewing'))
651 self.openReadOnlyAct.setWhatsThis(self.tr(
652 """<b>Open Read Only</b>"""
653 """<p>This opens a binary file for viewing (i.e. in read"""
654 """ only mode). It pops up a file selection dialog.</p>"""
655 ))
656
657 def __initMenus(self):
658 """
659 Private method to create the menus.
660 """
661 mb = self.menuBar()
662
663 menu = mb.addMenu(self.tr('&File'))
664 menu.setTearOffEnabled(True)
665 self.__recentMenu = QMenu(self.tr('Open &Recent Files'), menu)
666 menu.addAction(self.newWindowAct)
667 menu.addAction(self.openAct)
668 menu.addAction(self.openReadOnlyAct)
669 self.__menuRecentAct = menu.addMenu(self.__recentMenu)
670 menu.addSeparator()
671 menu.addAction(self.saveAct)
672 menu.addAction(self.saveAsAct)
673 menu.addAction(self.saveReadableAct)
674 menu.addSeparator()
675 menu.addAction(self.closeAct)
676 menu.addAction(self.closeOthersAct)
677 if self.__fromEric:
678 menu.addAction(self.closeAllAct)
679 else:
680 menu.addSeparator()
681 menu.addAction(self.exitAct)
682 menu.aboutToShow.connect(self.__showFileMenu)
683 self.__recentMenu.aboutToShow.connect(self.__showRecentMenu)
684 self.__recentMenu.triggered.connect(self.__openRecentHexFile)
685
686 menu = mb.addMenu(self.tr("&Edit"))
687 menu.setTearOffEnabled(True)
688 menu.addAction(self.undoAct)
689 menu.addAction(self.redoAct)
690 menu.addAction(self.revertAct)
691 menu.addSeparator()
692 menu.addAction(self.cutAct)
693 menu.addAction(self.copyAct)
694 menu.addAction(self.pasteAct)
695 menu.addSeparator()
696 menu.addAction(self.selectAllAct)
697 menu.addAction(self.deselectAllAct)
698 menu.addAction(self.saveSelectionReadableAct)
699 menu.addSeparator()
700 menu.addAction(self.searchAct)
701 menu.addAction(self.searchNextAct)
702 menu.addAction(self.searchPrevAct)
703 menu.addAction(self.replaceAct)
704 menu.addSeparator()
705 menu.addAction(self.gotoAct)
706 menu.addSeparator()
707 menu.addAction(self.readonlyAct)
708
709 if not self.__fromEric:
710 menu = mb.addMenu(self.tr("Se&ttings"))
711 menu.setTearOffEnabled(True)
712 menu.addAction(self.prefAct)
713
714 mb.addSeparator()
715
716 menu = mb.addMenu(self.tr("&Help"))
717 menu.addAction(self.aboutAct)
718 menu.addAction(self.aboutQtAct)
719 menu.addSeparator()
720 menu.addAction(self.whatsThisAct)
721
722 def __initToolbars(self):
723 """
724 Private method to create the toolbars.
725 """
726 filetb = self.addToolBar(self.tr("File"))
727 filetb.setObjectName("FileToolBar")
728 filetb.setIconSize(UI.Config.ToolBarIconSize)
729 filetb.addAction(self.newWindowAct)
730 filetb.addAction(self.openAct)
731 filetb.addSeparator()
732 filetb.addAction(self.saveAct)
733 filetb.addAction(self.saveAsAct)
734 filetb.addSeparator()
735 filetb.addAction(self.closeAct)
736 if not self.__fromEric:
737 filetb.addAction(self.exitAct)
738
739 edittb = self.addToolBar(self.tr("Edit"))
740 edittb.setObjectName("EditToolBar")
741 edittb.setIconSize(UI.Config.ToolBarIconSize)
742 edittb.addAction(self.undoAct)
743 edittb.addAction(self.redoAct)
744 edittb.addSeparator()
745 edittb.addAction(self.cutAct)
746 edittb.addAction(self.copyAct)
747 edittb.addAction(self.pasteAct)
748
749 searchtb = self.addToolBar(self.tr("Find"))
750 searchtb.setObjectName("SearchToolBar")
751 searchtb.setIconSize(UI.Config.ToolBarIconSize)
752 searchtb.addAction(self.searchAct)
753 searchtb.addAction(self.searchNextAct)
754 searchtb.addAction(self.searchPrevAct)
755
756 if not self.__fromEric:
757 settingstb = self.addToolBar(self.tr("Settings"))
758 settingstb.setObjectName("SettingsToolBar")
759 settingstb.setIconSize(UI.Config.ToolBarIconSize)
760 settingstb.addAction(self.prefAct)
761
762 helptb = self.addToolBar(self.tr("Help"))
763 helptb.setObjectName("HelpToolBar")
764 helptb.setIconSize(UI.Config.ToolBarIconSize)
765 helptb.addAction(self.whatsThisAct)
766
767 def __createStatusBar(self):
768 """
769 Private method to initialize the status bar.
770 """
771 self.__statusBar = self.statusBar()
772 self.__statusBar.setSizeGripEnabled(True)
773
774 self.__sbAddress = QLabel(self.__statusBar)
775 self.__statusBar.addPermanentWidget(self.__sbAddress)
776 self.__sbAddress.setWhatsThis(self.tr(
777 """<p>This part of the status bar displays the cursor"""
778 """ address.</p>"""
779 ))
780 self.__sbAddress.setFrameStyle(
781 QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
782
783 self.__sbSelection = QLabel(self.__statusBar)
784 self.__statusBar.addPermanentWidget(self.__sbSelection)
785 self.__sbSelection.setWhatsThis(self.tr(
786 """<p>This part of the status bar displays some selection"""
787 """ information.</p>"""
788 ))
789 self.__sbSelection.setFrameStyle(
790 QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
791
792 self.__sbSize = QLabel(self.__statusBar)
793 self.__statusBar.addPermanentWidget(self.__sbSize)
794 self.__sbSize.setWhatsThis(self.tr(
795 """<p>This part of the status bar displays the size of the"""
796 """ binary data.</p>"""
797 ))
798 self.__sbSize.setFrameStyle(
799 QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
800
801 self.__sbEditMode = EricClickableLabel(self.__statusBar)
802 self.__statusBar.addPermanentWidget(self.__sbEditMode)
803 self.__sbEditMode.setWhatsThis(self.tr(
804 """<p>This part of the status bar displays the edit mode.</p>"""
805 ))
806 self.__sbEditMode.setFrameStyle(
807 QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
808 self.__sbEditMode.clicked.connect(self.__toggleEditMode)
809
810 self.__sbReadOnly = EricClickableLabel(self.__statusBar)
811 self.__statusBar.addPermanentWidget(self.__sbReadOnly)
812 self.__sbReadOnly.setWhatsThis(self.tr(
813 """<p>This part of the status bar displays the read"""
814 """ only mode.</p>"""
815 ))
816 self.__sbReadOnly.setFrameStyle(
817 QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
818 self.__sbReadOnly.clicked.connect(self.__toggleReadOnlyMode)
819
820 self.__showEditMode(self.__editor.overwriteMode())
821 self.__showReadOnlyMode(self.__editor.isReadOnly())
822
823 @pyqtSlot(int)
824 def __showAddress(self, address):
825 """
826 Private slot to show the address of the cursor position.
827
828 @param address address of the cursor
829 @type int
830 """
831 txt = "{0:0{1}x}".format(address, self.__editor.addressWidth())
832 txt = strGroup(txt, ":", 4)
833 self.__sbAddress.setText(self.tr("Address: {0}").format(txt))
834
835 @pyqtSlot(bool)
836 def __showSelectionInfo(self, avail):
837 """
838 Private slot to show selection information.
839
840 @param avail flag indicating the availability of a selection.
841 @type bool
842 """
843 if avail:
844 addrWidth = self.__editor.addressWidth()
845 start = "{0:0{1}x}".format(self.__editor.getSelectionBegin(),
846 addrWidth)
847 start = strGroup(start, ":", 4)
848 end = "{0:0{1}x}".format(self.__editor.getSelectionEnd(),
849 addrWidth)
850 end = strGroup(end, ":", 4)
851 slen = self.__editor.getSelectionLength()
852 self.__sbSelection.setText(
853 self.tr("Selection: {0} - {1} ({2} Bytes)",
854 "0: start, 1: end, 2: selection length")
855 .format(start, end, QLocale().toString(slen))
856 )
857 else:
858 self.__sbSelection.setText(
859 self.tr("Selection: -", "no selection available"))
860
861 @pyqtSlot(bool)
862 def __showReadOnlyMode(self, on):
863 """
864 Private slot to show the read only mode.
865
866 @param on flag indicating the read only state
867 @type bool
868 """
869 self.__sbReadOnly.setText(self.tr("ro") if on else self.tr("rw"))
870
871 @pyqtSlot()
872 def __toggleReadOnlyMode(self):
873 """
874 Private slot to toggle the read only mode upon a click on the status
875 bar label.
876 """
877 self.__editor.setReadOnly(not self.__editor.isReadOnly())
878
879 @pyqtSlot(bool)
880 def __showEditMode(self, overwrite):
881 """
882 Private slot to show the edit mode.
883
884 @param overwrite flag indicating overwrite mode
885 @type bool
886 """
887 self.__sbEditMode.setText(
888 self.tr("Overwrite") if overwrite else self.tr("Insert"))
889
890 @pyqtSlot()
891 def __toggleEditMode(self):
892 """
893 Private slot to toggle the edit mode upon a click on the status bar
894 label.
895 """
896 self.__editor.setOverwriteMode(not self.__editor.overwriteMode())
897
898 @pyqtSlot(int)
899 def __showSize(self, size):
900 """
901 Private slot to show the binary data size.
902
903 @param size size of the binary data
904 @type int
905 """
906 self.__sbSize.setText(
907 self.tr("Size: {0}").format(QLocale().toString(size)))
908
909 def closeEvent(self, evt):
910 """
911 Protected event handler for the close event.
912
913 @param evt reference to the close event
914 <br />This event is simply accepted after the history has been
915 saved and all window references have been deleted.
916 @type QCloseEvent
917 """
918 if self.__maybeSave():
919 state = self.saveState()
920 Preferences.setHexEditor("HexEditorState", state)
921
922 Preferences.setGeometry("HexEditorGeometry", self.saveGeometry())
923
924 with contextlib.suppress(ValueError):
925 if self.__fromEric or len(self.__class__.windows) > 1:
926 del self.__class__.windows[
927 self.__class__.windows.index(self)]
928
929 if not self.__fromEric:
930 Preferences.syncPreferences()
931
932 self.__saveRecent()
933
934 evt.accept()
935 self.editorClosed.emit()
936 else:
937 evt.ignore()
938
939 def __openHexFileNewWindow(self):
940 """
941 Private slot called to open a binary file in new hex editor window.
942 """
943 if (
944 not self.__lastOpenPath and
945 self.__project is not None and
946 self.__project.isOpen()
947 ):
948 self.__lastOpenPath = self.__project.getProjectPath()
949
950 fileName = EricFileDialog.getOpenFileName(
951 self,
952 self.tr("Open binary file in new window"),
953 self.__lastOpenPath,
954 self.tr("All Files (*)"))
955 if fileName:
956 he = HexEditMainWindow(fileName=fileName,
957 parent=self.parent(),
958 fromEric=self.__fromEric,
959 project=self.__project)
960 he.setRecentPaths("", self.__lastSavePath)
961 he.show()
962
963 def __maybeSave(self):
964 """
965 Private method to ask the user to save the file, if it was modified.
966
967 @return flag indicating, if it is ok to continue
968 @rtype bool
969 """
970 if self.__editor.isModified():
971 ret = EricMessageBox.okToClearData(
972 self,
973 self.tr("eric Hex Editor"),
974 self.tr("""The loaded file has unsaved changes."""),
975 self.__saveHexFile)
976 if not ret:
977 return False
978 return True
979
980 def __loadHexFile(self, fileName):
981 """
982 Private method to load a binary file.
983
984 @param fileName name of the binary file to load
985 @type str
986 """
987 if not os.path.exists(fileName):
988 EricMessageBox.warning(
989 self, self.tr("eric Hex Editor"),
990 self.tr("The file '{0}' does not exist.")
991 .format(fileName))
992 return
993
994 try:
995 with open(fileName, "rb") as f:
996 data = f.read()
997 except OSError as err:
998 EricMessageBox.warning(
999 self, self.tr("eric Hex Editor"),
1000 self.tr("<p>Cannot read file <b>{0}</b>.</p>"
1001 "<p>Reason: {1}</p>")
1002 .format(fileName, str(err)))
1003 return
1004
1005 self.__lastOpenPath = os.path.dirname(fileName)
1006 self.__editor.setData(data)
1007 self.__setCurrentFile(fileName)
1008
1009 self.__editor.setReadOnly(Preferences.getHexEditor("OpenReadOnly"))
1010
1011 self.__gotoWidget.reset()
1012
1013 def __openHexFile(self):
1014 """
1015 Private slot to open a binary file.
1016 """
1017 if self.__maybeSave():
1018 if (
1019 not self.__lastOpenPath and
1020 self.__project is not None and
1021 self.__project.isOpen()
1022 ):
1023 self.__lastOpenPath = self.__project.getProjectPath()
1024
1025 fileName = EricFileDialog.getOpenFileName(
1026 self,
1027 self.tr("Open binary file"),
1028 self.__lastOpenPath,
1029 self.tr("All Files (*)"))
1030 if fileName:
1031 self.__loadHexFile(fileName)
1032 self.__checkActions()
1033
1034 def __openHexFileReadOnly(self):
1035 """
1036 Private slot to open a binary file in read only mode.
1037 """
1038 self.__openHexFile()
1039 self.__editor.setReadOnly(not Preferences.getHexEditor("OpenReadOnly"))
1040 self.__checkActions()
1041
1042 def __saveHexFile(self):
1043 """
1044 Private method to save a binary file.
1045
1046 @return flag indicating success
1047 @rtype bool
1048 """
1049 ok = (
1050 self.__saveHexDataFile(self.__fileName)
1051 if self.__fileName else
1052 self.__saveHexFileAs()
1053 )
1054
1055 if ok:
1056 self.__editor.undoStack().setClean()
1057
1058 return ok
1059
1060 def __saveHexFileAs(self):
1061 """
1062 Private method to save the data to a new file.
1063
1064 @return flag indicating success
1065 @rtype bool
1066 """
1067 if (
1068 not self.__lastSavePath and
1069 self.__project is not None and
1070 self.__project.isOpen()
1071 ):
1072 self.__lastSavePath = self.__project.getProjectPath()
1073 if not self.__lastSavePath and self.__lastOpenPath:
1074 self.__lastSavePath = self.__lastOpenPath
1075
1076 fileName = EricFileDialog.getSaveFileName(
1077 self,
1078 self.tr("Save binary file"),
1079 self.__lastSavePath,
1080 self.tr("All Files (*)"),
1081 EricFileDialog.DontConfirmOverwrite)
1082 if not fileName:
1083 return False
1084
1085 if pathlib.Path(fileName).exists():
1086 res = EricMessageBox.yesNo(
1087 self,
1088 self.tr("Save binary file"),
1089 self.tr("<p>The file <b>{0}</b> already exists."
1090 " Overwrite it?</p>").format(fileName),
1091 icon=EricMessageBox.Warning)
1092 if not res:
1093 return False
1094
1095 self.__lastSavePath = os.path.dirname(fileName)
1096
1097 return self.__saveHexDataFile(fileName)
1098
1099 def __saveHexDataFile(self, fileName):
1100 """
1101 Private method to save the binary data to a file.
1102
1103 @param fileName name of the file to write to
1104 @type str
1105 @return flag indicating success
1106 @rtype bool
1107 """
1108 try:
1109 with open(fileName, "wb") as f:
1110 f.write(self.__editor.data())
1111 except OSError as err:
1112 EricMessageBox.warning(
1113 self, self.tr("eric Hex Editor"),
1114 self.tr("<p>Cannot write file <b>{0}</b>.</p>"
1115 "<p>Reason: {1}</p>")
1116 .format(fileName, str(err)))
1117 self.__checkActions()
1118 return False
1119
1120 self.__editor.setModified(False, setCleanState=True)
1121
1122 self.__setCurrentFile(fileName)
1123 self.__statusBar.showMessage(self.tr("File saved"), 2000)
1124
1125 self.__checkActions()
1126
1127 return True
1128
1129 def __saveHexFileReadable(self, selectionOnly=False):
1130 """
1131 Private method to save the binary data in readable format.
1132
1133 @param selectionOnly flag indicating to save the selection only
1134 @type bool
1135 """
1136 savePath = self.__lastSavePath
1137 if (
1138 not savePath and
1139 self.__project is not None and
1140 self.__project.isOpen()
1141 ):
1142 savePath = self.__project.getProjectPath()
1143 if not savePath and self.__lastOpenPath:
1144 savePath = self.__lastOpenPath
1145
1146 fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
1147 self,
1148 self.tr("Save to readable file"),
1149 savePath,
1150 self.tr("Text Files (*.txt);;All Files (*)"),
1151 self.tr("Text Files (*.txt)"),
1152 EricFileDialog.DontConfirmOverwrite)
1153 if not fileName:
1154 return
1155
1156 fpath = pathlib.Path(fileName)
1157 if not fpath.suffix:
1158 ex = selectedFilter.split("(*")[1].split(")")[0]
1159 if ex:
1160 fpath = fpath.with_suffix(ex)
1161 if fpath.exists():
1162 res = EricMessageBox.yesNo(
1163 self,
1164 self.tr("Save to readable file"),
1165 self.tr("<p>The file <b>{0}</b> already exists."
1166 " Overwrite it?</p>").format(fpath),
1167 icon=EricMessageBox.Warning)
1168 if not res:
1169 return
1170
1171 readableData = (
1172 self.__editor.selectionToReadableString()
1173 if selectionOnly else
1174 self.__editor.toReadableString()
1175 )
1176 try:
1177 with fpath.open("w", encoding="latin1") as f:
1178 f.write(readableData)
1179 except OSError as err:
1180 EricMessageBox.warning(
1181 self, self.tr("eric Hex Editor"),
1182 self.tr("<p>Cannot write file <b>{0}</b>.</p>"
1183 "<p>Reason: {1}</p>")
1184 .format(fpath, str(err)))
1185 return
1186
1187 self.__statusBar.showMessage(self.tr("File saved"), 2000)
1188
1189 def __saveSelectionReadable(self):
1190 """
1191 Private method to save the data of the current selection in readable
1192 format.
1193 """
1194 self.__saveHexFileReadable(selectionOnly=True)
1195
1196 def __closeAll(self):
1197 """
1198 Private slot to close all windows.
1199 """
1200 self.__closeOthers()
1201 self.close()
1202
1203 def __closeOthers(self):
1204 """
1205 Private slot to close all other windows.
1206 """
1207 for win in self.__class__.windows[:]:
1208 if win != self:
1209 win.close()
1210
1211 def __setCurrentFile(self, fileName):
1212 """
1213 Private method to register the file name of the current file.
1214
1215 @param fileName name of the file to register
1216 @type str
1217 """
1218 self.__fileName = fileName
1219 # insert filename into list of recently opened files
1220 self.__addToRecentList(fileName)
1221
1222 shownName = (
1223 self.tr("Untitled")
1224 if not self.__fileName else
1225 self.__strippedName(self.__fileName)
1226 )
1227
1228 self.setWindowTitle(self.tr("{0}[*] - {1}")
1229 .format(shownName, self.tr("Hex Editor")))
1230
1231 self.setWindowModified(self.__editor.isModified())
1232
1233 def __strippedName(self, fullFileName):
1234 """
1235 Private method to return the filename part of the given path.
1236
1237 @param fullFileName full pathname of the given file
1238 @type str
1239 @return filename part
1240 @rtype str
1241 """
1242 return pathlib.Path(fullFileName).name
1243
1244 def setRecentPaths(self, openPath, savePath):
1245 """
1246 Public method to set the last open and save paths.
1247
1248 @param openPath least recently used open path
1249 @type str
1250 @param savePath least recently used save path
1251 @type str
1252 """
1253 if openPath:
1254 self.__lastOpenPath = openPath
1255 if savePath:
1256 self.__lastSavePath = savePath
1257
1258 @pyqtSlot()
1259 def __checkActions(self):
1260 """
1261 Private slot to check some actions for their enable/disable status.
1262 """
1263 self.saveAct.setEnabled(self.__editor.isModified())
1264
1265 self.cutAct.setEnabled(not self.__editor.isReadOnly() and
1266 self.__editor.hasSelection())
1267 self.pasteAct.setEnabled(not self.__editor.isReadOnly())
1268 self.replaceAct.setEnabled(not self.__editor.isReadOnly())
1269
1270 @pyqtSlot(bool)
1271 def __modificationChanged(self, m):
1272 """
1273 Private slot to handle the dataChanged signal.
1274
1275 @param m modification status
1276 @type bool
1277 """
1278 self.setWindowModified(m)
1279 self.__checkActions()
1280
1281 def __about(self):
1282 """
1283 Private slot to show a little About message.
1284 """
1285 EricMessageBox.about(
1286 self, self.tr("About eric Hex Editor"),
1287 self.tr("The eric Hex Editor is a simple editor component"
1288 " to edit binary files."))
1289
1290 def __aboutQt(self):
1291 """
1292 Private slot to handle the About Qt dialog.
1293 """
1294 EricMessageBox.aboutQt(self, "eric Hex Editor")
1295
1296 def __whatsThis(self):
1297 """
1298 Private slot called in to enter Whats This mode.
1299 """
1300 QWhatsThis.enterWhatsThisMode()
1301
1302 def __search(self):
1303 """
1304 Private method to handle the search action.
1305 """
1306 self.__replaceWidget.hide()
1307 self.__gotoWidget.hide()
1308 txt = (
1309 self.__editor.selectionToHexString()
1310 if self.__editor.hasSelection() else
1311 ""
1312 )
1313 self.__searchWidget.show(txt)
1314
1315 def __replace(self):
1316 """
1317 Private method to handle the replace action.
1318 """
1319 self.__searchWidget.hide()
1320 self.__gotoWidget.hide()
1321 txt = (
1322 self.__editor.selectionToHexString()
1323 if self.__editor.hasSelection() else
1324 ""
1325 )
1326 self.__replaceWidget.show(txt)
1327
1328 def __goto(self):
1329 """
1330 Private method to handle the goto action.
1331 """
1332 self.__searchWidget.hide()
1333 self.__replaceWidget.hide()
1334 self.__gotoWidget.show()
1335
1336 def preferencesChanged(self):
1337 """
1338 Public method to (re-)read the various settings.
1339 """
1340 self.__editor.setAddressWidth(
1341 Preferences.getHexEditor("AddressAreaWidth"))
1342 self.__editor.setAddressArea(
1343 Preferences.getHexEditor("ShowAddressArea"))
1344 self.__editor.setAsciiArea(
1345 Preferences.getHexEditor("ShowAsciiArea"))
1346 self.__editor.setHighlighting(
1347 Preferences.getHexEditor("HighlightChanges"))
1348 self.__editor.setFont(
1349 Preferences.getHexEditor("Font"))
1350
1351 self.__setReadOnlyActionTexts()
1352
1353 def __showPreferences(self):
1354 """
1355 Private slot to set the preferences.
1356 """
1357 from Preferences.ConfigurationDialog import (
1358 ConfigurationDialog, ConfigurationMode
1359 )
1360 dlg = ConfigurationDialog(
1361 None, 'Configuration', True, fromEric=True,
1362 displayMode=ConfigurationMode.HEXEDITORMODE)
1363 dlg.preferencesChanged.connect(
1364 self.__preferencesChangedByLocalPreferencesDialog)
1365 dlg.show()
1366 dlg.showConfigurationPageByName("hexEditorPage")
1367 dlg.exec()
1368 QCoreApplication.processEvents()
1369 if dlg.result() == QDialog.DialogCode.Accepted:
1370 dlg.setPreferences()
1371 Preferences.syncPreferences()
1372 self.__preferencesChangedByLocalPreferencesDialog()
1373
1374 def __preferencesChangedByLocalPreferencesDialog(self):
1375 """
1376 Private slot to handle preferences changes by our local dialog.
1377 """
1378 for hexEditor in HexEditMainWindow.windows:
1379 hexEditor.preferencesChanged()
1380
1381 def getSRHistory(self, key):
1382 """
1383 Public method to get the search or replace history list.
1384
1385 @param key name of list to return
1386 @type str (must be 'search' or 'replace')
1387 @return the requested history list
1388 @rtype list of tuples of (int, str)
1389 """
1390 if key in ['search', 'replace']:
1391 return self.__srHistory[key]
1392
1393 return []
1394
1395 @pyqtSlot()
1396 def __showFileMenu(self):
1397 """
1398 Private slot to modify the file menu before being shown.
1399 """
1400 self.__menuRecentAct.setEnabled(len(self.__recent) > 0)
1401
1402 @pyqtSlot()
1403 def __showRecentMenu(self):
1404 """
1405 Private slot to set up the recent files menu.
1406 """
1407 self.__loadRecent()
1408
1409 self.__recentMenu.clear()
1410
1411 for idx, rs in enumerate(self.__recent, start=1):
1412 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
1413 act = self.__recentMenu.addAction(
1414 formatStr.format(
1415 idx,
1416 Utilities.compactPath(
1417 rs, HexEditMainWindow.maxMenuFilePathLen)))
1418 act.setData(rs)
1419 act.setEnabled(pathlib.Path(rs).exists())
1420
1421 self.__recentMenu.addSeparator()
1422 self.__recentMenu.addAction(self.tr('&Clear'), self.__clearRecent)
1423
1424 @pyqtSlot(QAction)
1425 def __openRecentHexFile(self, act):
1426 """
1427 Private method to open a file from the list of recently opened files.
1428
1429 @param act reference to the action that triggered (QAction)
1430 """
1431 fileName = act.data()
1432 if fileName and self.__maybeSave():
1433 self.__loadHexFile(fileName)
1434 self.__editor.setReadOnly(Preferences.getHexEditor("OpenReadOnly"))
1435 self.__checkActions()
1436
1437 @pyqtSlot()
1438 def __clearRecent(self):
1439 """
1440 Private method to clear the list of recently opened files.
1441 """
1442 self.__recent = []
1443
1444 def __loadRecent(self):
1445 """
1446 Private method to load the list of recently opened files.
1447 """
1448 self.__recent = []
1449 Preferences.Prefs.rsettings.sync()
1450 rs = Preferences.Prefs.rsettings.value(recentNameHexFiles)
1451 if rs is not None:
1452 for f in Preferences.toList(rs):
1453 if pathlib.Path(f).exists():
1454 self.__recent.append(f)
1455
1456 def __saveRecent(self):
1457 """
1458 Private method to save the list of recently opened files.
1459 """
1460 Preferences.Prefs.rsettings.setValue(recentNameHexFiles, self.__recent)
1461 Preferences.Prefs.rsettings.sync()
1462
1463 def __addToRecentList(self, fileName):
1464 """
1465 Private method to add a file name to the list of recently opened files.
1466
1467 @param fileName name of the file to be added
1468 """
1469 if fileName:
1470 for recent in self.__recent[:]:
1471 if Utilities.samepath(fileName, recent):
1472 self.__recent.remove(recent)
1473 self.__recent.insert(0, fileName)
1474 maxRecent = Preferences.getHexEditor("RecentNumber")
1475 if len(self.__recent) > maxRecent:
1476 self.__recent = self.__recent[:maxRecent]
1477 self.__saveRecent()

eric ide

mercurial