eric6/HexEdit/HexEditMainWindow.py

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

eric ide

mercurial