PluginSplitMergeCamelCase.py

Wed, 24 Jun 2020 17:48:21 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 24 Jun 2020 17:48:21 +0200
changeset 42
81b488b5ad5d
parent 41
a7bfbf2f4348
child 44
bc1a5c665e18
permissions
-rw-r--r--

Removed support for Python2.

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

# Copyright (c) 2013 - 2020 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 = "3.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
# 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 = {}
        self.__mainActions = []
    
    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)
        
        menu = self.__ui.getMenu("plugin_tools")
        if menu is not None:
            if not menu.isEmpty():
                act = menu.addSeparator()
                self.__mainActions.append(act)
            act = menu.addMenu(self.__menu)
            self.__mainActions.append(act)
        
        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)
        
        menu = self.__ui.getMenu("plugin_tools")
        if menu is not None:
            for act in self.__mainActions:
                menu.removeAction(act)
        self.__mainActions = []

        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 not in ["Tools", "PluginTools"]:
            return
        
        editor = e5App().getObject("ViewManager").activeWindow()
        
        if name == "Tools":
            if not menu.isEmpty():
                menu.addSeparator()
            act = menu.addMenu(self.__menu)
            act.setEnabled(editor is not None and editor.hasSelectedText())
        elif name == "PluginTools" and self.__mainActions:
            self.__menu.setEnabled(editor is not None and
                                   editor.hasSelectedText())
    
    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":
            if self.__menu.menuAction() not in menu.actions():
                # Re-add our menu
                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)
            
            self.__menu.setEnabled(editor.hasSelectedText())
    
    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)

#
# eflag: noqa = M801

eric ide

mercurial