PluginToolGenerateHash.py

changeset 1
ce3163531e4b
parent 0
8014a543718a
child 4
b0a982bcf664
diff -r 8014a543718a -r ce3163531e4b PluginToolGenerateHash.py
--- a/PluginToolGenerateHash.py	Sat Dec 28 15:09:05 2013 +0100
+++ b/PluginToolGenerateHash.py	Sat Dec 28 16:30:45 2013 +0100
@@ -0,0 +1,292 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the 'Generate Hash' tool plug-in.
+"""
+
+import os
+import hashlib
+
+from PyQt4.QtCore import QObject, QTranslator
+from PyQt4.QtGui import QMenu
+
+from E5Gui.E5Application import e5App
+from E5Gui import E5FileDialog, E5MessageBox
+
+# Start-Of-Header
+name = "Generate Hash Tool Plug-in"
+author = "Detlev Offenbach <detlev@die-offenbachs.de>"
+autoactivate = True
+deactivateable = True
+version = "0.1.0"
+className = "ToolGenerateHashPlugin"
+packageName = "ToolGenerateHash"
+shortDescription = "Split, merge or convert camel case text"
+longDescription = \
+    """Plug-in to generate a hash for a selectable file or directory. The"""\
+    """ hash string will be inserted at the cursor position of the current"""\
+    """ editor. The menu will be disabled, if no editor is open."""
+needsRestart = False
+pyqtApi = 2
+# End-Of-Header
+
+error = ""
+
+
+class ToolGenerateHashPlugin(QObject):
+    """
+    Class implementing the 'Generate Hash' tool plug-in.
+    """
+    Hashes = {
+        "MD5": hashlib.md5,
+        "SHA1": hashlib.sha1,
+        "SHA224": hashlib.sha224,
+        "SHA256": hashlib.sha256,
+        "SHA384": hashlib.sha384,
+        "SHA512": hashlib.sha512,
+    }
+    
+    def __init__(self, ui):
+        """
+        Constructor
+        
+        @param ui reference to the user interface object (UI.UserInterface)
+        """
+        QObject.__init__(self, ui)
+        self.__ui = ui
+        
+        self.__translator = None
+        self.__loadTranslator()
+        
+        self.__initMenus()
+        
+        self.__editors = {}
+    
+    def activate(self):
+        """
+        Public method to activate this plugin.
+        
+        @return tuple of None and activation status (boolean)
+        """
+        global error
+        error = ""     # clear previous error
+        
+        self.__ui.showMenu.connect(self.__populateMenu)
+        
+        e5App().getObject("ViewManager").editorOpenedEd.connect(
+            self.__editorOpened)
+        e5App().getObject("ViewManager").editorClosedEd.connect(
+            self.__editorClosed)
+        
+        for editor in e5App().getObject("ViewManager").getOpenEditors():
+            self.__editorOpened(editor)
+        
+        return None, True
+    
+    def deactivate(self):
+        """
+        Public method to deactivate this plugin.
+        """
+        self.__ui.showMenu.disconnect(self.__populateMenu)
+        
+        e5App().getObject("ViewManager").editorOpenedEd.disconnect(
+            self.__editorOpened)
+        e5App().getObject("ViewManager").editorClosedEd.disconnect(
+            self.__editorClosed)
+        
+        for editor, acts in self.__editors.items():
+            editor.showMenu.disconnect(self.__editorShowMenu)
+            menu = editor.getMenu("Tools")
+            if menu is not None:
+                for act in acts:
+                    menu.removeAction(act)
+        self.__editors = {}
+    
+    def __loadTranslator(self):
+        """
+        Private method to load the translation file.
+        """
+        if self.__ui is not None:
+            loc = self.__ui.getLocale()
+            if loc and loc != "C":
+                locale_dir = os.path.join(
+                    os.path.dirname(__file__), "ToolGenerateHash", "i18n")
+                translation = "generatehash_{0}".format(loc)
+                translator = QTranslator(None)
+                loaded = translator.load(translation, locale_dir)
+                if loaded:
+                    self.__translator = translator
+                    e5App().installTranslator(self.__translator)
+                else:
+                    print("Warning: translation file '{0}' could not be"
+                          " loaded.".format(translation))
+                    print("Using default.")
+    
+    def __initMenus(self):
+        """
+        Private method to initialize the hash generation menus.
+        """
+        self.__fileMenu = QMenu(self.tr("Generate File Hash"))
+        self.__fileMenu.addAction("MD5", self.__hashFile).setData("MD5")
+        self.__fileMenu.addAction("SHA1", self.__hashFile).setData("SHA1")
+        self.__fileMenu.addAction("SHA224", self.__hashFile).setData("SHA224")
+        self.__fileMenu.addAction("SHA256", self.__hashFile).setData("SHA256")
+        self.__fileMenu.addAction("SHA384", self.__hashFile).setData("SHA384")
+        self.__fileMenu.addAction("SHA512", self.__hashFile).setData("SHA512")
+        
+        self.__dirMenu = QMenu(self.tr("Generate Directory Hash"))
+        self.__dirMenu.addAction(
+            "MD5", self.__hashDirectory).setData("MD5")
+        self.__dirMenu.addAction(
+            "SHA1", self.__hashDirectory).setData("SHA1")
+        self.__dirMenu.addAction(
+            "SHA224", self.__hashDirectory).setData("SHA224")
+        self.__dirMenu.addAction(
+            "SHA256", self.__hashDirectory).setData("SHA256")
+        self.__dirMenu.addAction(
+            "SHA384", self.__hashDirectory).setData("SHA384")
+        self.__dirMenu.addAction(
+            "SHA512", self.__hashDirectory).setData("SHA512")
+    
+    def __populateMenu(self, name, menu):
+        """
+        Private slot to populate the tools menu with our entries.
+        
+        @param name name of the menu (string)
+        @param menu reference to the menu to be populated (QMenu)
+        """
+        if name != "Tools":
+            return
+        
+        editor = e5App().getObject("ViewManager").activeWindow()
+        
+        if not menu.isEmpty():
+            menu.addSeparator()
+        
+        act = menu.addMenu(self.__fileMenu)
+        act.setEnabled(editor is not None)
+        act = menu.addMenu(self.__dirMenu)
+        act.setEnabled(editor is not None)
+    
+    def __editorOpened(self, editor):
+        """
+        Private slot called, when a new editor was opened.
+        
+        @param editor reference to the new editor (QScintilla.Editor)
+        """
+        menu = editor.getMenu("Tools")
+        if menu is not None:
+            self.__editors[editor] = []
+            if not menu.isEmpty():
+                act = menu.addSeparator()
+                self.__editors[editor].append(act)
+            act = menu.addMenu(self.__fileMenu)
+            self.__editors[editor].append(act)
+            act = menu.addMenu(self.__dirMenu)
+            self.__editors[editor].append(act)
+    
+    def __editorClosed(self, editor):
+        """
+        Private slot called, when an editor was closed.
+        
+        @param editor reference to the editor (QScintilla.Editor)
+        """
+        try:
+            del self.__editors[editor]
+        except KeyError:
+            pass
+    
+    def __insertHash(self, hashStr):
+        """
+        Private method to insert the generated hash string.
+        
+        @param hashStr hash string (string)
+        """
+        if hashStr:
+            editor = e5App().getObject("ViewManager").activeWindow()
+            line, index = editor.getCursorPosition()
+            # It should be done on this way to allow undo
+            editor.beginUndoAction()
+            editor.insertAt(hashStr, line, index)
+            editor.endUndoAction()
+    
+    def __hashFile(self):
+        """
+        Private slot to generate the hash for a file.
+        """
+        act = self.sender()
+        if act is None:
+            return
+        
+        name = E5FileDialog.getOpenFileName(
+            self.__ui,
+            self.trUtf8("Generate File Hash"))
+        if name:
+            try:
+                f = open(name, "rb")
+                hashStr = self.Hashes[act.data()](f.read()).hexdigest()
+                f.close()
+            except (IOError, OSError) as err:
+                E5MessageBox.critical(
+                    self.__ui,
+                    self.trUtf8("Generate File Hash"),
+                    self.trUtf8("""<p>The hash for <b>{0}</b> could not"""
+                                """ be generated.</p><p>Reason: {1}</p>""")
+                    .format(name, str(err))
+                )
+                return
+            
+            self.__insertHash(hashStr)
+    
+    def __hashDirectory(self):
+        """
+        Private slot to generate the hash for a directory.
+        """
+        act = self.sender()
+        if act is None:
+            return
+        
+        folder = E5FileDialog.getExistingDirectory(
+            self.__ui,
+            self.trUtf8("Generate Directory Hash"),
+            "",
+            E5FileDialog.Options(E5FileDialog.Option(0)))
+        if folder and os.path.isdir(folder):
+            fails = 0
+            hashes = []
+            for name in os.listdir(folder):
+                if not name.startswith(".") and \
+                        os.path.isfile(os.path.join(folder, name)):
+                    try:
+                        f = open(os.path.join(folder, name), "rb")
+                        hashStr = self.Hashes[act.data()](f.read()).hexdigest()
+                        f.close()
+                        hashes.append((name, hashStr))
+                    except (IOError, OSError):
+                        fails += 1
+            if fails:
+                E5MessageBox.critical(
+                    self.__ui,
+                    self.trUtf8("Generate Directory Hash"),
+                    self.trUtf8("""<p>The hash for some files could not"""
+                                """ be generated.</p>""")
+                )
+            else:
+                editor = e5App().getObject("ViewManager").activeWindow()
+                line, index = editor.getCursorPosition()
+                indLevel = (editor.indentation(line) //
+                            editor.indentationWidth())
+                if editor.indentationsUseTabs():
+                    indString = '\t'
+                else:
+                    indString = editor.indentationWidth() * ' '
+                indent = (indLevel + 1) * indString
+                code = ["["]
+                for hash in hashes:
+                    code.append("{0}{1},".format(indent, str(hash)))
+                code.append("{0}]".format(indLevel * indString))
+                
+                self.__insertHash(os.linesep.join(code))

eric ide

mercurial