PluginToolGenerateHash.py

branch
eric7
changeset 54
b43a0eccfc61
parent 51
b5a1a986b800
child 56
65b407bb4e24
equal deleted inserted replaced
53:a64adc8090ef 54:b43a0eccfc61
9 9
10 import contextlib 10 import contextlib
11 import os 11 import os
12 import hashlib 12 import hashlib
13 13
14 from PyQt5.QtCore import QObject, QTranslator 14 from PyQt6.QtCore import pyqtSlot, QObject, QTranslator
15 from PyQt5.QtWidgets import QMenu 15 from PyQt6.QtGui import QAction
16 16 from PyQt6.QtWidgets import QMenu
17 from E5Gui.E5Application import e5App 17
18 from E5Gui import E5FileDialog, E5MessageBox 18 from EricWidgets.EricApplication import ericApp
19 from EricWidgets import EricFileDialog, EricMessageBox
19 20
20 # Start-Of-Header 21 # Start-Of-Header
21 name = "Generate Hash Tool Plug-in" 22 name = "Generate Hash Tool Plug-in"
22 author = "Detlev Offenbach <detlev@die-offenbachs.de>" 23 author = "Detlev Offenbach <detlev@die-offenbachs.de>"
23 autoactivate = True 24 autoactivate = True
24 deactivateable = True 25 deactivateable = True
25 version = "3.2.0" 26 version = "1.0.0"
26 className = "ToolGenerateHashPlugin" 27 className = "ToolGenerateHashPlugin"
27 packageName = "ToolGenerateHash" 28 packageName = "ToolGenerateHash"
28 shortDescription = "Generate a hash for a selectable file or directory" 29 shortDescription = "Generate a hash for a selectable file or directory"
29 longDescription = ( 30 longDescription = (
30 """Plug-in to generate a hash for a selectable file or directory. The""" 31 """Plug-in to generate a hash for a selectable file or directory. The"""
40 41
41 class ToolGenerateHashPlugin(QObject): 42 class ToolGenerateHashPlugin(QObject):
42 """ 43 """
43 Class implementing the 'Generate Hash' tool plug-in. 44 Class implementing the 'Generate Hash' tool plug-in.
44 """ 45 """
45 Hashes = { 46 Hashes = [
46 "MD5": hashlib.md5, 47 h for h in ("md5", "sha1", "sha224", "sha256", "sha384", "sha512",
47 "SHA1": hashlib.sha1, 48 "sha3_224", "sha3_256", "sha3_384", "sha3_512")
48 "SHA224": hashlib.sha224, 49 if h in hashlib.algorithms_guaranteed
49 "SHA256": hashlib.sha256, 50 ]
50 "SHA384": hashlib.sha384,
51 "SHA512": hashlib.sha512,
52 }
53 51
54 def __init__(self, ui): 52 def __init__(self, ui):
55 """ 53 """
56 Constructor 54 Constructor
57 55
70 68
71 def activate(self): 69 def activate(self):
72 """ 70 """
73 Public method to activate this plugin. 71 Public method to activate this plugin.
74 72
75 @return tuple of None and activation status (boolean) 73 @return tuple of None and activation status
74 @rtype bool
76 """ 75 """
77 global error 76 global error
78 error = "" # clear previous error 77 error = "" # clear previous error
79 78
80 self.__ui.showMenu.connect(self.__populateMenu) 79 self.__ui.showMenu.connect(self.__populateMenu)
87 act = menu.addMenu(self.__fileMenu) 86 act = menu.addMenu(self.__fileMenu)
88 self.__mainActions.append(act) 87 self.__mainActions.append(act)
89 act = menu.addMenu(self.__dirMenu) 88 act = menu.addMenu(self.__dirMenu)
90 self.__mainActions.append(act) 89 self.__mainActions.append(act)
91 90
92 e5App().getObject("ViewManager").editorOpenedEd.connect( 91 ericApp().getObject("ViewManager").editorOpenedEd.connect(
93 self.__editorOpened) 92 self.__editorOpened)
94 e5App().getObject("ViewManager").editorClosedEd.connect( 93 ericApp().getObject("ViewManager").editorClosedEd.connect(
95 self.__editorClosed) 94 self.__editorClosed)
96 95
97 for editor in e5App().getObject("ViewManager").getOpenEditors(): 96 for editor in ericApp().getObject("ViewManager").getOpenEditors():
98 self.__editorOpened(editor) 97 self.__editorOpened(editor)
99 98
100 return None, True 99 return None, True
101 100
102 def deactivate(self): 101 def deactivate(self):
109 if menu is not None: 108 if menu is not None:
110 for act in self.__mainActions: 109 for act in self.__mainActions:
111 menu.removeAction(act) 110 menu.removeAction(act)
112 self.__mainActions = [] 111 self.__mainActions = []
113 112
114 e5App().getObject("ViewManager").editorOpenedEd.disconnect( 113 ericApp().getObject("ViewManager").editorOpenedEd.disconnect(
115 self.__editorOpened) 114 self.__editorOpened)
116 e5App().getObject("ViewManager").editorClosedEd.disconnect( 115 ericApp().getObject("ViewManager").editorClosedEd.disconnect(
117 self.__editorClosed) 116 self.__editorClosed)
118 117
119 for editor, acts in self.__editors.items(): 118 for editor, acts in self.__editors.items():
120 editor.showMenu.disconnect(self.__editorShowMenu) 119 editor.showMenu.disconnect(self.__editorShowMenu)
121 menu = editor.getMenu("Tools") 120 menu = editor.getMenu("Tools")
136 translation = "generatehash_{0}".format(loc) 135 translation = "generatehash_{0}".format(loc)
137 translator = QTranslator(None) 136 translator = QTranslator(None)
138 loaded = translator.load(translation, locale_dir) 137 loaded = translator.load(translation, locale_dir)
139 if loaded: 138 if loaded:
140 self.__translator = translator 139 self.__translator = translator
141 e5App().installTranslator(self.__translator) 140 ericApp().installTranslator(self.__translator)
142 else: 141 else:
143 print("Warning: translation file '{0}' could not be" 142 print("Warning: translation file '{0}' could not be"
144 " loaded.".format(translation)) 143 " loaded.".format(translation))
145 print("Using default.") 144 print("Using default.")
146 145
147 def __initMenus(self): 146 def __initMenus(self):
148 """ 147 """
149 Private method to initialize the hash generation menus. 148 Private method to initialize the hash generation menus.
150 """ 149 """
151 self.__fileMenu = QMenu(self.tr("Generate File Hash")) 150 self.__fileMenu = QMenu(self.tr("Generate File Hash"))
152 self.__fileMenu.addAction("MD5", self.__hashFile).setData("MD5") 151 for hash in self.Hashes:
153 self.__fileMenu.addAction("SHA1", self.__hashFile).setData("SHA1") 152 self.__fileMenu.addAction(
154 self.__fileMenu.addAction("SHA224", self.__hashFile).setData("SHA224") 153 hash.upper().replace("_", ":")).setData(hash)
155 self.__fileMenu.addAction("SHA256", self.__hashFile).setData("SHA256")
156 self.__fileMenu.addAction("SHA384", self.__hashFile).setData("SHA384")
157 self.__fileMenu.addAction("SHA512", self.__hashFile).setData("SHA512")
158 self.__fileMenu.setEnabled(False) 154 self.__fileMenu.setEnabled(False)
155 self.__fileMenu.triggered.connect(self.__hashFile)
159 156
160 self.__dirMenu = QMenu(self.tr("Generate Directory Hash")) 157 self.__dirMenu = QMenu(self.tr("Generate Directory Hash"))
161 self.__dirMenu.addAction( 158 for hash in self.Hashes:
162 "MD5", self.__hashDirectory).setData("MD5") 159 self.__dirMenu.addAction(
163 self.__dirMenu.addAction( 160 hash.upper().replace("_", ":")).setData(hash)
164 "SHA1", self.__hashDirectory).setData("SHA1")
165 self.__dirMenu.addAction(
166 "SHA224", self.__hashDirectory).setData("SHA224")
167 self.__dirMenu.addAction(
168 "SHA256", self.__hashDirectory).setData("SHA256")
169 self.__dirMenu.addAction(
170 "SHA384", self.__hashDirectory).setData("SHA384")
171 self.__dirMenu.addAction(
172 "SHA512", self.__hashDirectory).setData("SHA512")
173 self.__dirMenu.setEnabled(False) 161 self.__dirMenu.setEnabled(False)
162 self.__dirMenu.triggered.connect(self.__hashDirectory)
174 163
175 def __populateMenu(self, name, menu): 164 def __populateMenu(self, name, menu):
176 """ 165 """
177 Private slot to populate the tools menu with our entries. 166 Private slot to populate the tools menu with our entries.
178 167
179 @param name name of the menu (string) 168 @param name name of the menu
180 @param menu reference to the menu to be populated (QMenu) 169 @type str
170 @param menu reference to the menu to be populated
171 @type QMenu
181 """ 172 """
182 if name not in ["Tools", "PluginTools"]: 173 if name not in ["Tools", "PluginTools"]:
183 return 174 return
184 175
185 editor = e5App().getObject("ViewManager").activeWindow() 176 editor = ericApp().getObject("ViewManager").activeWindow()
186 177
187 if name == "Tools": 178 if name == "Tools":
188 if not menu.isEmpty(): 179 if not menu.isEmpty():
189 menu.addSeparator() 180 menu.addSeparator()
190 181
198 189
199 def __editorOpened(self, editor): 190 def __editorOpened(self, editor):
200 """ 191 """
201 Private slot called, when a new editor was opened. 192 Private slot called, when a new editor was opened.
202 193
203 @param editor reference to the new editor (QScintilla.Editor) 194 @param editor reference to the new editor
195 @type Editor
204 """ 196 """
205 menu = editor.getMenu("Tools") 197 menu = editor.getMenu("Tools")
206 if menu is not None: 198 if menu is not None:
207 self.__editors[editor] = [] 199 self.__editors[editor] = []
208 if not menu.isEmpty(): 200 if not menu.isEmpty():
219 211
220 def __editorClosed(self, editor): 212 def __editorClosed(self, editor):
221 """ 213 """
222 Private slot called, when an editor was closed. 214 Private slot called, when an editor was closed.
223 215
224 @param editor reference to the editor (QScintilla.Editor) 216 @param editor reference to the editor
217 @type Editor
225 """ 218 """
226 with contextlib.suppress(KeyError): 219 with contextlib.suppress(KeyError):
227 del self.__editors[editor] 220 del self.__editors[editor]
228 if not self.__editors: 221 if not self.__editors:
229 self.__fileMenu.setEnabled(False) 222 self.__fileMenu.setEnabled(False)
232 def __editorShowMenu(self, menuName, menu, editor): 225 def __editorShowMenu(self, menuName, menu, editor):
233 """ 226 """
234 Private slot called, when the the editor context menu or a submenu is 227 Private slot called, when the the editor context menu or a submenu is
235 about to be shown. 228 about to be shown.
236 229
237 @param menuName name of the menu to be shown (string) 230 @param menuName name of the menu to be shown
238 @param menu reference to the menu (QMenu) 231 @type str
232 @param menu reference to the menu
233 @type QMenu
239 @param editor reference to the editor 234 @param editor reference to the editor
235 @type Editor
240 """ 236 """
241 if ( 237 if (
242 menuName == "Tools" and 238 menuName == "Tools" and
243 self.__fileMenu.menuAction() not in menu.actions() 239 self.__fileMenu.menuAction() not in menu.actions()
244 ): 240 ):
257 253
258 def __insertHash(self, hashStr): 254 def __insertHash(self, hashStr):
259 """ 255 """
260 Private method to insert the generated hash string. 256 Private method to insert the generated hash string.
261 257
262 @param hashStr hash string (string) 258 @param hashStr hash string
259 @type str
263 """ 260 """
264 if hashStr: 261 if hashStr:
265 editor = e5App().getObject("ViewManager").activeWindow() 262 editor = ericApp().getObject("ViewManager").activeWindow()
266 line, index = editor.getCursorPosition() 263 line, index = editor.getCursorPosition()
267 # It should be done on this way to allow undo 264 # It should be done this way to allow undo
268 editor.beginUndoAction() 265 editor.beginUndoAction()
269 editor.insertAt(hashStr, line, index) 266 editor.insertAt(hashStr, line, index)
270 editor.endUndoAction() 267 editor.endUndoAction()
271 268
272 def __hashFile(self): 269 @pyqtSlot(QAction)
270 def __hashFile(self, act):
273 """ 271 """
274 Private slot to generate the hash for a file. 272 Private slot to generate the hash for a file.
275 """ 273
276 act = self.sender() 274 @param act reference to the action that was triggered
275 @type QAction
276 """
277 if act is None: 277 if act is None:
278 return 278 return
279 279
280 name = E5FileDialog.getOpenFileName( 280 name = EricFileDialog.getOpenFileName(
281 self.__ui, 281 self.__ui,
282 self.tr("Generate File Hash")) 282 self.tr("Generate File Hash"))
283 if name: 283 if name:
284 try: 284 try:
285 with open(name, "rb") as f: 285 with open(name, "rb") as f:
286 hashStr = self.Hashes[act.data()](f.read()).hexdigest() 286 hashStr = hashlib.new(act.data(), f.read()).hexdigest()
287 except OSError as err: 287 except OSError as err:
288 E5MessageBox.critical( 288 EricMessageBox.critical(
289 self.__ui, 289 self.__ui,
290 self.tr("Generate File Hash"), 290 self.tr("Generate File Hash"),
291 self.tr("""<p>The hash for <b>{0}</b> could not""" 291 self.tr("""<p>The hash for <b>{0}</b> could not"""
292 """ be generated.</p><p>Reason: {1}</p>""") 292 """ be generated.</p><p>Reason: {1}</p>""")
293 .format(name, str(err)) 293 .format(name, str(err))
294 ) 294 )
295 return 295 return
296 296
297 self.__insertHash(hashStr) 297 self.__insertHash(hashStr)
298 298
299 def __hashDirectory(self): 299 @pyqtSlot(QAction)
300 def __hashDirectory(self, act):
300 """ 301 """
301 Private slot to generate the hash for a directory. 302 Private slot to generate the hash for a directory.
302 """ 303
303 act = self.sender() 304 @param act reference to the action that was triggered
305 @type QAction
306 """
304 if act is None: 307 if act is None:
305 return 308 return
306 309
307 folder = E5FileDialog.getExistingDirectory( 310 folder = EricFileDialog.getExistingDirectory(
308 self.__ui, 311 self.__ui,
309 self.tr("Generate Directory Hash"), 312 self.tr("Generate Directory Hash"),
310 "", 313 "",
311 E5FileDialog.Options(E5FileDialog.Option(0))) 314 EricFileDialog.Option(0))
312 if folder and os.path.isdir(folder): 315 if folder and os.path.isdir(folder):
313 fails = 0 316 fails = 0
314 hashes = [] 317 hashes = []
315 for name in os.listdir(folder): 318 for name in os.listdir(folder):
316 if ( 319 if (
317 not name.startswith(".") and 320 not name.startswith(".") and
318 os.path.isfile(os.path.join(folder, name)) 321 os.path.isfile(os.path.join(folder, name))
319 ): 322 ):
320 try: 323 try:
321 with open(os.path.join(folder, name), "rb") as f: 324 with open(os.path.join(folder, name), "rb") as f:
322 hashStr = self.Hashes[act.data()]( 325 hashStr = hashlib.new(
323 f.read()).hexdigest() 326 act.data(), f.read()).hexdigest()
324 hashes.append((name, hashStr)) 327 hashes.append((name, hashStr))
325 except OSError: 328 except OSError:
326 fails += 1 329 fails += 1
327 if fails: 330 if fails:
328 E5MessageBox.critical( 331 EricMessageBox.critical(
329 self.__ui, 332 self.__ui,
330 self.tr("Generate Directory Hash"), 333 self.tr("Generate Directory Hash"),
331 self.tr("""<p>The hash for some files could not""" 334 self.tr("""<p>The hash for some files could not"""
332 """ be generated.</p>""") 335 """ be generated.</p>""")
333 ) 336 )
334 else: 337 else:
335 editor = e5App().getObject("ViewManager").activeWindow() 338 editor = ericApp().getObject("ViewManager").activeWindow()
336 line, index = editor.getCursorPosition() 339 line, index = editor.getCursorPosition()
337 indLevel = (editor.indentation(line) // 340 indLevel = (editor.indentation(line) //
338 editor.indentationWidth()) 341 editor.indentationWidth())
339 if editor.indentationsUseTabs(): 342 if editor.indentationsUseTabs():
340 indString = '\t' 343 indString = '\t'

eric ide

mercurial