PluginSplitMergeCamelCase.py

Thu, 01 Jan 2015 13:27:35 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 01 Jan 2015 13:27:35 +0100
changeset 29
84d19316f5f8
parent 24
37d06c3a577e
child 30
018aac3a028a
permissions
-rw-r--r--

Updated copyright for 2015.

# -*- coding: utf-8 -*-

# Copyright (c) 2013 - 2015 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the split, merge or convert camel case plug-in.
"""

import os
import re

from PyQt5.QtCore import QObject, QTranslator
from PyQt5.QtWidgets import QMenu

from E5Gui.E5Application import e5App

# Start-Of-Header
name = "Camel Case Handling Plug-in"
author = "Detlev Offenbach <detlev@die-offenbachs.de>"
autoactivate = True
deactivateable = True
version = "2.0.0"
className = "SplitMergeCamelCasePlugin"
packageName = "SplitMergeCamelCase"
shortDescription = "Split, merge or convert camel case text"
longDescription = \
    """This plug-in implements a tool to split, merge or convert""" \
    """ camel case text. It works with the text of the current""" \
    """ editor. The menu entries will only be selectable, if the""" \
    """ current editor has some selected text."""
needsRestart = False
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""


class SplitMergeCamelCasePlugin(QObject):
    """
    Class implementing the split, merge or convert camel case plug-in.
    """
    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.__initMenu()
        
        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__), "SplitMergeCamelCase", "i18n")
                translation = "splitmergecamelcase_{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 __initMenu(self):
        """
        Private method to initialize the camel case handling menu.
        """
        self.__menu = QMenu(self.tr("CamelCase Handling"))
        self.__menu.addAction(self.tr("Split from CamelCase"),
                              self.__splitCamelCase)
        self.__menu.addAction(self.tr("Merge to CamelCase"),
                              self.__mergeCamelCase)
        self.__menu.addAction(self.tr("CamelCase to under_score"),
                              self.__camelCaseToUnderscore)
        self.__menu.addAction(self.tr("under_score to CamelCase"),
                              self.__underscoreToCamelCase)
        self.__menu.addAction(
            self.tr("under_score to CamelCase (upper case first)"),
            self.__underscoreToCamelCaseUppercaseFirst)
    
    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.__menu)
        act.setEnabled(editor is not None and editor.selectedText() != '')
    
    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.__menu)
            self.__editors[editor].append(act)
            editor.showMenu.connect(self.__editorShowMenu)
    
    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 __editorShowMenu(self, menuName, menu, editor):
        """
        Private slot called, when the the editor context menu or a submenu is
        about to be shown.
        
        @param menuName name of the menu to be shown (string)
        @param menu reference to the menu (QMenu)
        @param editor reference to the editor
        """
        if menuName == "Tools":
            self.__menu.setEnabled(editor.selectedText() != '')
    
    def __applyChange(self, newText, editor):
        """
        Private method to change the selected text.
        
        @param newText new (converted) text (string)
        @param editor reference to the editor to apply the text
            change to (Editor)
        """
        editor.beginUndoAction()
        editor.replaceSelectedText(newText)
        editor.endUndoAction()
    
    def __splitCamelCase(self):
        """
        Private slot to split the selected camel case text.
        """
        editor = e5App().getObject("ViewManager").activeWindow()
        if editor is None:
            return
        
        text = editor.selectedText()
        if text:
            newText = re.sub(r"([A-Z])", r" \1", text)
            if newText.startswith(" "):
                newText = newText[1:]
            if newText != text:
                self.__applyChange(newText, editor)
    
    def __mergeCamelCase(self):
        """
        Private slot to merge the selected text to camel case.
        """
        editor = e5App().getObject("ViewManager").activeWindow()
        if editor is None:
            return
        
        text = editor.selectedText()
        if text:
            newText = "".join(text.split())
            if newText != text:
                self.__applyChange(newText, editor)
    
    def __camelCaseToUnderscore(self):
        """
        Private slot to convert camel case text to underscore separated text.
        """
        editor = e5App().getObject("ViewManager").activeWindow()
        if editor is None:
            return
        
        text = editor.selectedText()
        if text:
            newText = re.sub(r"([A-Z])", r"_\1", text).lower()
            if newText.startswith("_"):
                newText = newText[1:]
            if newText != text:
                self.__applyChange(newText, editor)
    
    def __underscoreToCamelCase(self, uppercaseFirst=False):
        """
        Private slot to convert underscore separated text to camel case.
        
        @param uppercaseFirst flag indicating to upper case the
            first character (boolean)
        """
        editor = e5App().getObject("ViewManager").activeWindow()
        if editor is None:
            return
        
        text = editor.selectedText()
        if text:
            newText = "".join([s.capitalize() for s in text.split("_")])
            if not uppercaseFirst:
                newText = newText[0].lower() + newText[1:]
            if newText != text:
                self.__applyChange(newText, editor)
    
    def __underscoreToCamelCaseUppercaseFirst(self):
        """
        Private slot to convert underscore separated text to camel case
        upper casing the first character.
        """
        self.__underscoreToCamelCase(True)

eric ide

mercurial