ProjectDjangoTagsMenu/DjangoTagsMenuHandler.py

Fri, 07 Feb 2014 18:21:09 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 07 Feb 2014 18:21:09 +0100
changeset 7
8d928ad07c0a
parent 6
5f1c0ebbdf5f
child 8
7e8f788fe340
permissions
-rw-r--r--

Implemented template filters 'a' to 'f'.

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

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

"""
Module implementing the Django tags menu handler.
"""

import os

from PyQt4.QtCore import QObject
from PyQt4.QtGui import QMenu, QInputDialog

from E5Gui.E5Application import e5App
from E5Gui import E5FileDialog

from .DjangoTagInputDialog import DjangoTagInputDialog


class DjangoTagsMenuHandler(QObject):
    """
    Class implementing the Django tags menu handler.
    """
    def __init__(self, ui, parent=None):
        """
        Constructor
        
        @param ui reference to the user interface object (UI.UserInterface)
        @param parent reference to the parent object (QObject)
        """
        super(DjangoTagsMenuHandler, self).__init__(parent)
        self.__ui = ui
        
        self.__findDialog = None
    
    def closeAllWindows(self):
        """
        Public method to close all dialogs managed by the handler.
        """
        if self.__findDialog:
            self.__findDialog.close()
    
    def initMenus(self, mainMenu):
        """
        Public method to initialize the various menus.
        
        @param mainMenu reference to the main tags menu (QMenu)
        """
        mainMenu.addAction(self.tr("Django Template Tags Locator"),
                           self.__findTemplateTag)
        mainMenu.addSeparator()
        mainMenu.addMenu(self.__initTagsMenu())
        mainMenu.addMenu(self.__initFiltersMenu())
    
    def __initTagsMenu(self):
        """
        Private method to initialize the tags menu.
        
        @return generated menu (QMenu)
        """
        menu = QMenu(self.tr("Tags"))
        menu.addAction(
            self.tr("autoescape - Auto Escape Characters"),
            lambda: self.__applyTemplate("autoescape"))
        menu.addSeparator()
        menu.addAction(
            self.tr("block - Named Block"),
            lambda: self.__applyTemplate("block"))
        menu.addSeparator()
        menu.addAction(
            self.tr("comment - Multiline Comment"),
            lambda: self.__applyTemplate("comment"))
        menu.addAction(
            self.tr("csrf_token - Cross Site Request Forgery Token"),
            lambda: self.__applyTemplate("csrf_token"))
        menu.addAction(
            self.tr("cycle - Cycle variables each time used"),
            lambda: self.__applyTemplate("cycle"))
        menu.addSeparator()
        menu.addAction(
            self.tr("debug - Output Debug Information"),
            lambda: self.__applyTemplate("debug"))
        menu.addSeparator()
        menu.addAction(
            self.tr("extends - Extend a template with variable contents"),
            lambda: self.__applyTemplate("extendsvariable"))
        menu.addAction(
            self.tr("extends - Extend a template with file"),
            lambda: self.__applyTemplate("extendsfile"))
        menu.addSeparator()
        menu.addAction(
            self.tr("filter - Filtered Block for one or more filters"),
            lambda: self.__applyTemplate("filter"))
        menu.addAction(
            self.tr("firstof - Outputs first argument variable that is True"),
            lambda: self.__applyTemplate("firstof"))
        menu.addAction(
            self.tr("for - For Loop"),
            lambda: self.__applyTemplate("for"))
        menu.addAction(
            self.tr("for...empty - For Loop with fallback for empty loop"),
            lambda: self.__applyTemplate("for...empty"))
        menu.addSeparator()
        # TODO: add 'if...' templates here
        menu.addAction(
            self.tr("include - Render template given by variable"),
            lambda: self.__applyTemplate("includevariable"))
        menu.addAction(
            self.tr("include - Render template given by file name"),
            lambda: self.__applyTemplate("includefile"))
        menu.addSeparator()
        menu.addAction(
            self.tr("load - Load a custom template tag set"),
            lambda: self.__applyTemplate("load"))
        menu.addSeparator()
        menu.addAction(
            self.tr("now - Display current date and time"),
            lambda: self.__applyTemplate("now"))
        menu.addSeparator()
        menu.addAction(
            self.tr("regroup - Regroup list of alike objects by a common"
                    " attribute"),
            lambda: self.__applyTemplate("regroup"))
        menu.addSeparator()
        menu.addAction(
            self.tr("spaceless - Remove whitespace between HTML tags"),
            lambda: self.__applyTemplate("spaceless"))
        menu.addAction(
            self.tr("ssi - Output contents of a given file into the page"),
            lambda: self.__applyTemplate("ssi"))
        menu.addAction(
            self.tr("ssi - Output contents of a given file into the page"
                    " (dialog selection)"),
            lambda: self.__applyTemplate("ssifile"))
        menu.addSeparator()
        menu.addAction(
            self.tr("templatetag - Output syntax characters used for"
                    " template"),
            lambda: self.__applyTemplate("templatetag"))
        menu.addSeparator()
        menu.addAction(
            self.tr("url - Return an absolute path reference"),
            lambda: self.__applyTemplate("url"))
        menu.addAction(
            self.tr("url...as - Return an absolute path reference"),
            lambda: self.__applyTemplate("urlas"))
        menu.addSeparator()
        menu.addAction(
            self.tr("verbatim - Output block contents without rendering"),
            lambda: self.__applyTemplate("verbatim"))
        menu.addSeparator()
        menu.addAction(
            self.tr("widthratio - Calculate width ratio"),
            lambda: self.__applyTemplate("verbatim"))
        menu.addAction(
            self.tr("with - Cache a complex variable under a simpler name"),
            lambda: self.__applyTemplate("verbatim"))
        
        self.__tagsMenu = menu
        return menu
    
    def __initFiltersMenu(self):
        """
        Private method to initialize the filters menu.
        
        @return generated menu (QMenu)
        """
        menu = QMenu(self.tr("Filters"))
        menu.addAction(
            self.tr("add - Add variable or string"),
            lambda: self.__applyTemplate("add"))
        menu.addAction(
            self.tr("addslashes - Add slashes before quotes"),
            lambda: self.__applyTemplate("addslashes"))
        menu.addSeparator()
        menu.addAction(
            self.tr("capfirst - Capitalize first character"),
            lambda: self.__applyTemplate("capfirst"))
        menu.addAction(
            self.tr("center - Center value"),
            lambda: self.__applyTemplate("center"))
        menu.addAction(
            self.tr("cut - Cut characters"),
            lambda: self.__applyTemplate("cut"))
        menu.addSeparator()
        menu.addAction(
            self.tr("date - Format date"),
            lambda: self.__applyTemplate("date"))
        menu.addAction(
            self.tr("default - Use dafault if False"),
            lambda: self.__applyTemplate("default"))
        menu.addAction(
            self.tr("default_if_none - Use default if None"),
            lambda: self.__applyTemplate("default_if_none"))
        menu.addAction(
            self.tr("dictsort - Sort dictionaries"),
            lambda: self.__applyTemplate("dictsort"))
        menu.addAction(
            self.tr("dictsortreversed - Sort dictionaries reversed"),
            lambda: self.__applyTemplate("dictsortreversed"))
        menu.addAction(
            self.tr("divisibleby - Check divisibility"),
            lambda: self.__applyTemplate("divisibleby"))
        menu.addSeparator()
        menu.addAction(
            self.tr("escape - Escape  as HTML"),
            lambda: self.__applyTemplate("escape"))
        menu.addAction(
            self.tr("escapejs - Escape as JavaScript"),
            lambda: self.__applyTemplate("escapejs"))
        menu.addSeparator()
        menu.addAction(
            self.tr("filesizeformat - Format file sizes"),
            lambda: self.__applyTemplate("filesizeformat"))
        menu.addAction(
            self.tr("first - First item of a list"),
            lambda: self.__applyTemplate("first"))
        menu.addAction(
            self.tr("fix_ampersands - Replace ampersands"),
            lambda: self.__applyTemplate("fix_ampersands"))
        menu.addAction(
            self.tr("floatformat - Format floating numbers"),
            lambda: self.__applyTemplate("floatformat"))
        menu.addAction(
            self.tr("force_escape - Escape as HTML immediately"),
            lambda: self.__applyTemplate("force_escape"))
        menu.addSeparator()
        
        self.__filtersMenu = menu
        return menu
    
    def __findTemplateTag(self):
        """
        Private slot to find a template tag and insert its text.
        """
        if self.__findDialog is None:
            from .FindTemplateTagDialog import FindTemplateTagDialog
            self.__findDialog = FindTemplateTagDialog()
            self.__findDialog.tag.connect(self.__applyTemplate)
        self.__findDialog.show()
        self.__findDialog.raise_()
        self.__findDialog.activateWindow()
    
    def __applyTemplate(self, tag):
        """
        Private slot to generate and insert the template text.
        
        @param tag name of the tag to insert (string)
        """
        editor = e5App().getObject("ViewManager").activeWindow()
        if editor is None:
            return
        
        templateText, replace = self.__generateTemplateText(
            tag, editor.selectedText())
        
        if templateText:
            editor.beginUndoAction()
            if replace:
                editor.replaceSelectedText(templateText)
            else:
                editor.insert(templateText)
            editor.endUndoAction()
    
    def __generateTemplateText(self, tag, selectedText):
        """
        Private slot to generate the template text.
        
        @param tag name of the tag to insert (string)
        @param selectedText selected text of the current editor (string)
        @return tuple of generated template text (string), a flag indicating
            to perform a replace operation (boolean)
        """
        # TODO: complete the tag generation logic
        replace = False         # safe value
        ok = True
        templateText = ""
        
        ####################################################
        ## Template Tags                                  ##
        ####################################################
        
        if tag == "autoescape":
            templateText = (
                "{{% autoescape on %}} {0} {{% endautoescape %}}".format(
                    selectedText))
            replace = True
        elif tag == "block":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Named Block"),
                [self.tr("Enter block name:")],
                ["block_name"])
            if ok:
                templateText = "{{% block {0} %}} {1} {{% endblock %}}".format(
                    data[0], selectedText)
                replace = True
        elif tag == "comment":
            templateText = "{{% comment %}} {0} {{% endcomment %}}".format(
                selectedText)
            replace = True
        elif tag == "csrf_token":
            templateText = "{% csrf_token %}"
        elif tag == "cycle":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Cycle Variables"),
                [self.tr("Enter items to cycle, space separated")],
                ["item1 item2 item3"])
            if ok:
                templateText = "{{% cycle {0} %}}".format(data[0])
        elif tag == "debug":
            templateText = "{% debug %}"
        elif tag == "extendsvariable":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Extends"),
                [self.tr("Enter variable name:")],
                ["variable"])
            if ok:
                templateText = "{{% extends {0} %}}".format(data[0])
        elif tag == "extendsfile":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Extends"),
                [self.tr("Enter parent file name:")],
                ["base.html"])
            if ok:
                templateText = '{{% extends "{0}" %}}'.format(data[0])
        elif tag == "filter":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Tag Filters"),
                [self.tr("Multiple filters with arguments, pipes separated:")],
                ["lower|safe"])
            if ok:
                templateText = (
                    "{{% filter {0} %}} {1} {{% endfilter %}}".format(
                        data[0], selectedText))
                replace = True
        elif tag == "firstof":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("First Of"),
                [self.tr("Enter multiple variables, space separated:"),
                 self.tr("Enter fallback value:")],
                ["var1 var2", "fallback_value"])
            if ok:
                templateText = (
                    '{{% filter force_escape %}}{{% firstof {0} "{1}" %}}'
                    ' {2} {{% endfilter %}}'.format(
                        data[0], data[1], selectedText))
                replace = True
        elif tag == "for":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("For Loop"),
                [self.tr("Enter variable to use for iteration:"),
                 self.tr("Enter sequence to iterate over:")],
                ["item", "values"])
            if ok:
                templateText = (
                    "{{% for {0} in {1} %}} {2} {{% endfor %}}".format(
                        data[0], data[1], selectedText))
                replace = True
        elif tag == "for...empty":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("For Loop"),
                [self.tr("Enter variable to use for iteration:"),
                 self.tr("Enter sequence to iterate over:"),
                 self.tr("Enter output to use if loop is empty:")],
                ["item", "values", '"Nothing."'])
            if ok:
                templateText = (
                    "{{% for {0} in {1} %}} {2} {{% empty %}} {3}"
                    " {{% endfor %}}".format(
                        data[0], data[1], selectedText, data[2]))
                replace = True
        elif tag == "includevariable":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Include"),
                [self.tr("Enter variable name:")],
                ["variable"])
            if ok:
                templateText = '{{% include {0} %}}'.format(data[0])
        elif tag == "includefile":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Include"),
                [self.tr("Enter file name:")],
                ["other.html"])
            if ok:
                templateText = '{{% include "{0}" %}}'.format(data[0])
        elif tag == "load":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Load"),
                [self.tr("Enter template tag set to load:")],
                ["foo bar"])
            if ok:
                templateText = '{{% load "{0}" %}}'.format(data[0])
        elif tag == "now":
            dateformat, ok = QInputDialog.getItem(
                None,
                self.tr("Now"),
                self.tr("Current date time format:"),
                ["DATETIME_FORMAT", "SHORT_DATETIME_FORMAT",
                 "SHORT_DATE_FORMAT", "DATE_FORMAT"],
                0, False)
            if ok:
                templateText = '{{% now "{0}" %}}'.format(dateformat)
        elif tag == "regroup":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Regroup List"),
                [self.tr("List Variable:"), self.tr("Common Attribute:"),
                 self.tr("Name of resulting list:")],
                ["cities", "country", "country_list"])
            if ok:
                templateText = '{{% regroup {0} by {1} as {2} %}}'.format(
                    data[0], data[1], data[2])
        elif tag == "spaceless":
            templateText = "{{% spaceless %}} {0} {{% endspaceless %}}".format(
                selectedText)
            replace = True
        elif tag == "ssi":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("SSI"),
                [self.tr("Full path to template:")],
                ["/tmp/ssi_template.html"])
            if ok:
                templateText = '{{% ssi "{0}" parsed %}}'.format(data[0])
        elif tag == "ssifile":
            ssi = E5FileDialog.getOpenFileName(
                None,
                self.tr("SSI"),
                os.path.expanduser("~"),
                self.tr("All Files (*)"))
            if ssi:
                templateText = '{{% ssi "{0}" parsed %}}'.format(ssi)
        elif tag == "templatetag":
            templatetag, ok = QInputDialog.getItem(
                None,
                self.tr("Template Tag"),
                self.tr("Argument:"),
                ["block", "variable", "brace", "comment"],
                0, False)
            if ok:
                templateText = (
                    '{{% templatetag open{0} %}} {1} {{% templatetag'
                    ' close{0} %}}'.format(templatetag, selectedText))
                replace = True
        elif tag == "url":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("URL"),
                [self.tr("View method name:"),
                 self.tr("Optional arguments (space separated):")],
                ["path.to.some_view", "var1 var2"])
            if ok:
                if data[1]:
                    data[1] = ' ' + data[1]
                templateText = '{{% url "{0}"{1} %}}'.format(
                    data[0], data[1])
        elif tag == "urlas":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("URL...as"),
                [self.tr("View method name:"),
                 self.tr("Optional arguments (space separated):"),
                 self.tr("URL name:")],
                ["path.to.some_view", "var1 var2", "url_name"])
            if ok:
                if data[1]:
                    data[1] = ' ' + data[1]
                templateText = '{{% url "{0}"{1} as {2} %}}'.format(
                    data[0], data[1], data[2])
        elif tag == "verbatim":
            templateText = "{{% verbatim %}} {0} {{% endverbatim %}}".format(
                selectedText)
            replace = True
        elif tag == "widthratio":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Width Ratio"),
                [self.tr("Variable:"),
                 self.tr("Maximum Value:"),
                 self.tr("Maximum Width:")],
                ["variable", "max_value", "max_width"])
            if ok:
                templateText = "{{% widthratio {0} {1} {2} %}}".format(
                    data[0], data[1], data[2])
        elif tag == "with":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Cache Variables"),
                [self.tr("Variables to cache as key=value (space separated):")
                 ],
                ["variable1=foo.bar variable2=bar.baz"])
            if ok:
                templateText = '{{% with {0} %}} {1} {{% endwith %}}'.format(
                    data[0], selectedText)
        
        ####################################################
        ## Template Filters                                  ##
        ####################################################
        
        elif tag == "add":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Add Variable or String"),
                [self.tr("Variables or String to add:")
                 ],
                ["variable"])
            if ok:
                templateText = "|add:{0}".format(data[0])
        elif tag == "addslashes":
            templateText = "|addslashes "
        elif tag == "capfirst":
            templateText = "|capfirst "
        elif tag == "center":
            width, ok = QInputDialog.getInt(
                None,
                self.tr("Center Value"),
                self.tr("Enter width of the output:"),
                10, 1, 99, 1)
            if ok:
                templateText = '|center:"{0}"'.format(width)
        elif tag == "cut":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Cut Characters"),
                [self.tr("Characters to cut:")
                 ],
                [" "])
            if ok:
                templateText = '|cut:"{0}"'.format(data[0])
        elif tag == "date":
            date, ok = QInputDialog.getItem(
                None,
                self.tr("Format Date"),
                self.tr("Enter date format:"),
                ["DATETIME_FORMAT", "SHORT_DATETIME_FORMAT",
                 "SHORT_DATE_FORMAT", "DATE_FORMAT"],
                0, True)
            if ok:
                templateText = '|date:"{0}" '.format(date)
        elif tag == "default":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Default Value if False"),
                [self.tr("Enter default value if result is False:")
                 ],
                ["nothing"])
            if ok:
                templateText = '|default:"{0}" '.format(data[0])
        elif tag == "default_if_none":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Default Value if None"),
                [self.tr("Enter default value if result is None:")
                 ],
                ["nothing"])
            if ok:
                templateText = '|default:"{0}" '.format(data[0])
        elif tag == "dictsort":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Sort Dictionaries"),
                [self.tr("Enter key to sort on:")
                 ],
                ["key"])
            if ok:
                templateText = '|dictsort:"{0}" '.format(data[0])
        elif tag == "dictsortreversed":
            data, ok = DjangoTagInputDialog.getText(
                None,
                self.tr("Sort Dictionaries reversed"),
                [self.tr("Enter key to sort on:")
                 ],
                ["key"])
            if ok:
                templateText = '|dictsortreversed:"{0}" '.format(data[0])
        elif tag == "divisibleby":
            divisor, ok = QInputDialog.getInt(
                None,
                self.tr("Check Divisibility"),
                self.tr("Enter divisor value:"),
                2, 1, 99, 1)
            if ok:
                templateText = '|divisibleby:"{0}" '.format(divisor)
        elif tag == "escape":
            templateText = '|escape '
        elif tag == "escapejs":
            templateText = '|escapejs '
        elif tag == "filesizeformat":
            templateText = '|filesizeformat '
        elif tag == "first":
            templateText = '|first '
        elif tag == "fix_ampersands":
            templateText = '|fix_ampersands '
        elif tag == "floatformat":
            decimals, ok = QInputDialog.getInt(
                None,
                self.tr("Format Floating Number"),
                self.tr("Enter number of decimal places:"),
                2, -20, 20, 1)
            if ok:
                templateText = '|floatformat:"{0}" '.format(decimals)
        elif tag == "force_escape":
            templateText = '|force_escape '
        
        ####################################################
        ## Fallback: return just the tag name             ##
        ####################################################
        
        else:
            templateText = tag
        
        return templateText, replace

eric ide

mercurial