Wed, 05 Feb 2014 19:13:12 +0100
Implemented template tags 'f' to 'i' (except 'if').
--- a/PluginDjangoTagsMenu.e4p Mon Feb 03 19:54:07 2014 +0100 +++ b/PluginDjangoTagsMenu.e4p Wed Feb 05 19:13:12 2014 +0100 @@ -18,6 +18,7 @@ <Source>ProjectDjangoTagsMenu/__init__.py</Source> <Source>ProjectDjangoTagsMenu/DjangoTagsMenuHandler.py</Source> <Source>ProjectDjangoTagsMenu/FindTemplateTagDialog.py</Source> + <Source>ProjectDjangoTagsMenu/DjangoTagInputDialog.py</Source> </Sources> <Forms> <Form>ProjectDjangoTagsMenu/FindTemplateTagDialog.ui</Form>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectDjangoTagsMenu/DjangoTagInputDialog.py Wed Feb 05 19:13:12 2014 +0100 @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter data for the creation of a tag. +""" + +from PyQt4.QtCore import Qt +from PyQt4.QtGui import QDialog, QDialogButtonBox, QVBoxLayout, QLabel + +from E5Gui.E5LineEdit import E5ClearableLineEdit + + +class DjangoTagInputDialog(QDialog): + """ + Class implementing a dialog to enter data for the creation of a tag. + """ + def __init__(self, labels, defaults=None, parent=None): + super(DjangoTagInputDialog, self).__init__(parent) + + assert 0 < len(labels) < 6 # max 5 entries allowed + self.__inputs = [] + + self.__topLayout = QVBoxLayout(self) + index = 0 + for label in labels: + self.__topLayout.addWidget(QLabel(label, self)) + entry = E5ClearableLineEdit(self) + if defaults and index < len(defaults): + entry.setText(defaults[index]) + self.__inputs.append(entry) + self.__topLayout.addWidget(entry) + index += 1 + self.__buttonBox = QDialogButtonBox( + QDialogButtonBox.Ok | QDialogButtonBox.Cancel, + Qt.Horizontal, self) + self.__topLayout.addWidget(self.__buttonBox) + + self.resize(400, self.minimumSizeHint().height()) + self.setSizeGripEnabled(True) + + self.__buttonBox.accepted.connect(self.accept) + self.__buttonBox.rejected.connect(self.reject) + + self.__inputs[0].selectAll() + self.__inputs[0].setFocus() + + def getData(self): + """ + Public method to retrieve the entered data. + + @return tuple containing the text of all entries (tuple of string) + """ + data = [input.text().strip() for input in self.__inputs] + return tuple(data) + + @staticmethod + def getText(parent, title, labels, defaults=[]): + """ + Static method to create the dialog and return the entered data. + + @return tuple of a tuple containing the text of all entries + (tuple of string) and a flag indicating the acceptance + state (boolean) + """ + dlg = DjangoTagInputDialog(labels, defaults, parent) + dlg.setWindowTitle(title) + if dlg.exec_() == QDialog.Accepted: + return dlg.getData(), True + else: + return tuple(), False
--- a/ProjectDjangoTagsMenu/DjangoTagsMenuHandler.py Mon Feb 03 19:54:07 2014 +0100 +++ b/ProjectDjangoTagsMenu/DjangoTagsMenuHandler.py Wed Feb 05 19:13:12 2014 +0100 @@ -8,10 +8,12 @@ """ from PyQt4.QtCore import QObject -from PyQt4.QtGui import QMenu, QInputDialog, QLineEdit +from PyQt4.QtGui import QMenu from E5Gui.E5Application import e5App +from .DjangoTagInputDialog import DjangoTagInputDialog + class DjangoTagsMenuHandler(QObject): """ @@ -54,22 +56,27 @@ @return generated menu (QMenu) """ menu = QMenu(self.tr("Tags")) - menu.addAction(self.tr("autoescape - Auto Escape Characters"), - lambda: self.__applyTemplate("autoescape")) + 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.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("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.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.addAction( + self.tr("debug - Output Debug Information"), + lambda: self.__applyTemplate("debug")) menu.addSeparator() menu.addAction( self.tr("extends - Extend a template with variable contents"), @@ -77,6 +84,27 @@ 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")) self.__tagsMenu = menu return menu @@ -106,12 +134,13 @@ templateText, replace = self.__generateTemplateText( tag, editor.selectedText()) - editor.beginUndoAction() - if replace: - editor.replaceSelectedText(templateText) - else: - editor.insert(templateText) - editor.endUndoAction() + if templateText: + editor.beginUndoAction() + if replace: + editor.replaceSelectedText(templateText) + else: + editor.insert(templateText) + editor.endUndoAction() def __generateTemplateText(self, tag, selectedText): """ @@ -119,67 +148,130 @@ @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) and a flag indicating + @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 %} " + - selectedText + - " {% endautoescape %}") + templateText = ( + "{% autoescape on %} " + selectedText + " {% endautoescape %}") replace = True elif tag == "block": - blockName, ok = QInputDialog.getText( + data, ok = DjangoTagInputDialog.getText( None, self.tr("Named Block"), - self.tr("Enter block name:"), - QLineEdit.Normal, - "block_name") - templateText = ("{% block " + - blockName.strip() + - " %} " + - selectedText + - " {% endblock %}") - replace = True + [self.tr("Enter block name:")], + ["block_name"]) + if ok: + templateText = ( + "{% block " + data[0] + " %} " + selectedText + + " {% endblock %}") + replace = True elif tag == "comment": - templateText = ("{% comment %} " + - selectedText + - " {% endcomment %}") + templateText = ( + "{% comment %} " + selectedText + " {% endcomment %}") replace = True elif tag == "csrf_token": - templateText = "{% csrf_token %}" + templateText = ("{% csrf_token %}") elif tag == "cycle": - cycleItems, ok = QInputDialog.getText( + data, ok = DjangoTagInputDialog.getText( None, self.tr("Cycle Variables"), - self.tr("Enter items to cycle separated by space"), - QLineEdit.Normal, - "item1 item2 item3") - templateText = ("{% cycle " + cycleItems.strip() + " %} ") + [self.tr("Enter items to cycle, space separated")], + ["item1 item2 item3"]) + if ok: + templateText = ("{% cycle " + data[0] + " %} ") elif tag == "debug": - templateText = "{% debug %}" + templateText = ("{% debug %}") elif tag == "extendsvariable": - extends, ok = QInputDialog.getText( + data, ok = DjangoTagInputDialog.getText( + None, + self.tr("Extends"), + [self.tr("Enter variable name:")], + ["variable"]) + if ok: + templateText = ('{% extends ' + 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 "' + 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 " + data[0] + " %} " + selectedText + + " {% endfilter %}") + replace = True + elif tag == "firstof": + data, ok = DjangoTagInputDialog.getText( None, - self.tr("Extends Variable"), - self.tr("Enter variable name:"), - QLineEdit.Normal, - "variable") - templateText = '{% extends ' + extends.strip() + ' %} ' - elif tag == "extendsfile": - extends, ok = QInputDialog.getText( + 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 " + data[0] + + ' "' + data[1] + '" %} ' + selectedText + + " {% endfilter %}") + 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 " + data[0] + " in " + data[1] + + " %} " + selectedText + " {% endfor %}") + replace = True + elif tag == "for...empty": + data, ok = DjangoTagInputDialog.getText( None, - self.tr("Extends Parent"), - self.tr("Enter parent file name:"), - QLineEdit.Normal, - "base.html") - templateText = '{% extends "' + extends.strip() + '" %} ' + 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 " + data[0] + " in " + data[1] + " %} " + + selectedText + " {% empty %} " + data[2] + " {% endfor %}") + replace = True + elif tag == "includevariable": + data, ok = DjangoTagInputDialog.getText( + None, + self.tr("Include"), + [self.tr("Enter variable name:")], + ["variable"]) + if ok: + templateText = ('{% include ' + data[0] + ' %} ') + elif tag == "includefile": + data, ok = DjangoTagInputDialog.getText( + None, + self.tr("Include"), + [self.tr("Enter file name:")], + ["other.html"]) + if ok: + templateText = ('{% include "' + data[0] + '" %} ') #################################################### ## Fallback: return just the tag name ## @@ -187,4 +279,5 @@ else: templateText = tag + return templateText, replace
--- a/ProjectDjangoTagsMenu/FindTemplateTagDialog.py Mon Feb 03 19:54:07 2014 +0100 +++ b/ProjectDjangoTagsMenu/FindTemplateTagDialog.py Wed Feb 05 19:13:12 2014 +0100 @@ -28,6 +28,7 @@ super(FindTemplateTagDialog, self).__init__(parent) self.setupUi(self) + # TODO: check tags against handler self.__completer = QCompleter(( 'autoescape', 'block', 'comment', 'csrf_token', 'cycle', 'debug', 'extends', 'filter', 'firstof', 'for', 'for...empty', 'if',