Commit for testing after making a tabbed window and embedding the template tester

This commit is contained in:
Charles Haley 2020-09-30 22:50:26 +01:00
parent 78e9858f4d
commit e08fb5f231
7 changed files with 450 additions and 360 deletions

View File

@ -935,10 +935,10 @@ class ActionTemplateTester(InterfaceActionBase):
description = _('Show an editor for testing templates')
class ActionStoredTemplates(InterfaceActionBase):
name = 'Stored Templates'
actual_plugin = 'calibre.gui2.actions.show_stored_templates:ShowStoredTemplatesAction'
description = _('Show a dialog for creating and managing stored templates')
class ActionTemplateFunctions(InterfaceActionBase):
name = 'Template Functions'
actual_plugin = 'calibre.gui2.actions.show_stored_templates:ShowTemplateFunctionsAction'
description = _('Show a dialog for creating and managing template functions and stored templates')
class ActionSaveToDisk(InterfaceActionBase):
@ -1105,7 +1105,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionCopyToLibrary, ActionTweakEpub, ActionUnpackBook, ActionNextMatch, ActionStore,
ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy,
ActionMarkBooks, ActionEmbed, ActionTemplateTester, ActionTagMapper, ActionAuthorMapper,
ActionVirtualLibrary, ActionBrowseAnnotations, ActionStoredTemplates]
ActionVirtualLibrary, ActionBrowseAnnotations, ActionTemplateFunctions]
# }}}
@ -1278,18 +1278,6 @@ class TemplateFunctions(PreferencesPlugin):
description = _('Create your own template functions')
class StoredTemplates(PreferencesPlugin):
name = 'StoredTemplates'
icon = I('template_funcs.png')
gui_name = _('Stored templates')
category = 'Advanced'
gui_category = _('Advanced')
category_order = 5
name_order = 6
config_widget = 'calibre.gui2.preferences.stored_templates'
description = _('Create stored calibre templates')
class Email(PreferencesPlugin):
name = 'Email'
icon = I('mail.png')
@ -1394,7 +1382,7 @@ class Misc(PreferencesPlugin):
plugins += [LookAndFeel, Behavior, Columns, Toolbar, Search, InputOptions,
CommonOptions, OutputOptions, Adding, Saving, Sending, Plugboard,
Email, Server, Plugins, Tweaks, Misc, TemplateFunctions,
StoredTemplates, MetadataSources, Keyboard, IgnoredDevices]
MetadataSources, Keyboard, IgnoredDevices]
# }}}

View File

@ -11,20 +11,20 @@ from calibre.gui2.actions import InterfaceAction
from calibre.gui2.preferences.main import Preferences
class ShowStoredTemplatesAction(InterfaceAction):
class ShowTemplateFunctionsAction(InterfaceAction):
name = 'Stored Template'
action_spec = (_('Stored Templates'), 'debug.png', None, ())
name = 'Template Functions'
action_spec = (_('Template Functions'), 'debug.png', None, ())
dont_add_to = frozenset(('context-menu-device',))
action_type = 'current'
def genesis(self):
self.previous_text = _('Manage stored templates')
self.previous_text = _('Manage template functions')
self.first_time = True
self.qaction.triggered.connect(self.show_template_editor)
def show_template_editor(self, *args):
d = Preferences(self.gui, initial_plugin=('Advanced', 'StoredTemplates'),
d = Preferences(self.gui, initial_plugin=('Advanced', 'TemplateFunctions'),
close_after_initial=True)
d.exec_()

View File

@ -213,7 +213,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
def __init__(self, parent, text, mi=None, fm=None, color_field=None,
icon_field_key=None, icon_rule_kind=None, doing_emblem=False,
text_is_placeholder=False):
text_is_placeholder=False, dialog_is_st_editor=False):
QDialog.__init__(self, parent)
Ui_TemplateDialog.__init__(self)
self.setupUi(self)
@ -221,6 +221,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.coloring = color_field is not None
self.iconing = icon_field_key is not None
self.embleming = doing_emblem
self.dialog_is_st_editor = dialog_is_st_editor
cols = []
if fm is not None:
@ -273,6 +274,14 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.icon_kind.setCurrentIndex(dex)
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
if dialog_is_st_editor:
self.buttonBox.setVisible(False)
else:
self.new_doc_label.setVisible(False)
self.new_doc.setVisible(False)
self.template_name_label.setVisible(False)
self.template_name.setVisible(False)
if mi:
self.mi = mi
else:
@ -467,6 +476,27 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.rule = ('', txt)
QDialog.accept(self)
def reject(self):
QDialog.reject(self)
if self.dialog_is_st_editor:
parent = self.parent()
while True:
if hasattr(parent, 'reject'):
parent.reject()
break
parent = parent.parent()
if parent is None:
break
class EmbeddedTemplateDialog(TemplateDialog):
def __init__(self, parent):
TemplateDialog.__init__(self, parent, "Foo", text_is_placeholder=True,
dialog_is_st_editor=True)
self.setParent(parent)
self.setWindowFlags(Qt.Widget)
if __name__ == '__main__':
app = QApplication([])

View File

@ -141,11 +141,68 @@
</layout>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="textbox"/>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="template_name_label">
<property name="text">
<string>Template &amp;name:</string>
</property>
<property name="buddy">
<cstring>template_name</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="template_name">
<property name="editable">
<bool>true</bool>
</property>
<property name="toolTip">
<string>The name of the callable template</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel">
<property name="text">
<string>T&amp;emplate:</string>
</property>
<property name="buddy">
<cstring>textbox</cstring>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPlainTextEdit" name="textbox">
<property name="toolTip">
<string>The template program text</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="new_doc_label">
<property name="text">
<string>D&amp;ocumentation:</string>
</property>
<property name="buddy">
<cstring>new_doc</cstring>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QTextEdit" name="new_doc">
<property name="toolTip">
<string>Documentation for the function being defined or edited</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel">
<property name="text">
@ -173,7 +230,7 @@
</property>
</widget>
</item>
<item row="6" column="1">
<item row="6" column="1" colspan="3">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QSpinBox" name="font_size_box"/>
@ -203,14 +260,24 @@
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<item row="7" column="0" colspan="5">
<widget class="QFrame">
<property name="frameShape">
<enum>QFrame::HLine</enum>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="8" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Template Function Reference</string>
</property>
<property name="buddy">
<cstring>function</cstring>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Function &amp;name:</string>
@ -220,10 +287,10 @@
</property>
</widget>
</item>
<item row="8" column="1">
<item row="9" column="1" colspan="3">
<widget class="QComboBox" name="function"/>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>&amp;Function type:</string>
@ -236,14 +303,14 @@
</property>
</widget>
</item>
<item row="9" column="1">
<item row="10" column="1" colspan="3">
<widget class="QLineEdit" name="func_type">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Documentation:</string>
@ -256,7 +323,7 @@
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Code:</string>
@ -269,7 +336,7 @@
</property>
</widget>
</item>
<item row="10" column="1">
<item row="11" column="1" colspan="3">
<widget class="QPlainTextEdit" name="documentation">
<property name="maximumSize">
<size>
@ -279,17 +346,17 @@
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1" colspan="3">
<widget class="QPlainTextEdit" name="source_code"/>
</item>
<item row="12" column="1">
<item row="13" column="1">
<widget class="QLabel" name="template_tutorial">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<widget class="QLabel" name="template_func_reference">
<property name="openExternalLinks">
<bool>true</bool>

View File

@ -1,211 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import traceback
from PyQt5.Qt import (Qt, QGridLayout, QLabel, QSpacerItem, QSizePolicy,
QComboBox, QTextEdit, QHBoxLayout, QPushButton)
from calibre.gui2 import error_dialog
from calibre.gui2.dialogs.template_line_editor import TemplateLineEditor
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.utils.formatter_functions import (formatter_functions,
compile_user_function, compile_user_template_functions,
load_user_template_functions, function_pref_is_python,
function_pref_name)
from polyglot.builtins import native_string_type, unicode_type
class ConfigWidget(ConfigWidgetBase):
def genesis(self, gui):
self.gui = gui
self.db = gui.library_view.model().db
help_text = '<p>' + _('''
Here you can add and remove stored templates used in template processing.
You use a stored template in another template with the 'call' template
function, as in 'call(somename, arguments...). Stored templates must use
General Program Mode -- they must begin with the text 'program:'.
In the stored template you get the arguments using the 'arguments()'
template function, as in arguments(var1, var2, ...). The calling arguments
are copied to the named variables.
''') + '</p>'
l = QGridLayout(self)
w = QLabel(help_text)
w.setWordWrap(True)
l.addWidget(w, 0, 0, 1, 2)
lab = QLabel(_('&Name'))
l.addWidget(lab, 1, 0)
self.function_name = w = QComboBox(self)
w.setEditable(True)
lab.setBuddy(w)
w.setToolTip(_('The name of the function, used in a call statement'))
l.addWidget(w, 1, 1)
lab = QLabel(_('&Template'))
l.addWidget(lab, 2, 0)
lb = QHBoxLayout()
self.program = w = TemplateLineEditor(self)
w.setPlaceholderText(_('The GPM template.'))
lab.setBuddy(w)
lb.addWidget(w, stretch=1)
self.editor_button = b = QPushButton(_('&Open template editor'))
b.clicked.connect(w.open_editor)
lb.addWidget(b)
l.addLayout(lb, 2, 1)
lab = QLabel(_('&Documentation'))
l.addWidget(lab, 3, 0, Qt.AlignTop)
self.documentation = w = QTextEdit(self)
w.setPlaceholderText(_('A description of the template. Whatever you wish ...'))
lab.setBuddy(w)
l.addWidget(w, 3, 1)
lb = QHBoxLayout()
lb.addStretch(1)
self.clear_button = w = QPushButton(_('C&lear'))
lb.addWidget(w)
self.delete_button = w = QPushButton(_('&Delete'))
lb.addWidget(w)
self.replace_button = w = QPushButton(_('&Replace'))
lb.addWidget(w)
self.create_button = w = QPushButton(_('&Create'))
lb.addWidget(w)
lb.addStretch(1)
l.addLayout(lb, 9, 1)
l.addItem(QSpacerItem(10, 10, vPolicy=QSizePolicy.Expanding), 10, 0, -1, -1)
self.setLayout(l)
def initialize(self):
self.funcs = {}
for v in self.db.prefs.get('user_template_functions', []):
if not function_pref_is_python(v):
self.funcs.update({function_pref_name(v):compile_user_function(*v)})
self.build_function_names_box()
self.function_name.currentIndexChanged[native_string_type].connect(self.function_index_changed)
self.function_name.editTextChanged.connect(self.function_name_edited)
self.documentation.textChanged.connect(self.enable_replace_button)
self.program.textChanged.connect(self.enable_replace_button)
self.create_button.clicked.connect(self.create_button_clicked)
self.delete_button.clicked.connect(self.delete_button_clicked)
self.create_button.setEnabled(False)
self.delete_button.setEnabled(False)
self.replace_button.setEnabled(False)
self.clear_button.clicked.connect(self.clear_button_clicked)
self.replace_button.clicked.connect(self.replace_button_clicked)
def enable_replace_button(self):
self.replace_button.setEnabled(self.delete_button.isEnabled())
def clear_button_clicked(self):
self.build_function_names_box()
self.program.clear()
self.documentation.clear()
self.create_button.setEnabled(False)
self.delete_button.setEnabled(False)
def build_function_names_box(self, scroll_to=''):
self.function_name.blockSignals(True)
func_names = sorted(self.funcs)
self.function_name.clear()
self.function_name.addItem('')
self.function_name.addItems(func_names)
self.function_name.setCurrentIndex(0)
self.function_name.blockSignals(False)
if scroll_to:
idx = self.function_name.findText(scroll_to)
if idx >= 0:
self.function_name.setCurrentIndex(idx)
def delete_button_clicked(self):
name = unicode_type(self.function_name.currentText())
if name in self.funcs:
del self.funcs[name]
self.changed_signal.emit()
self.create_button.setEnabled(True)
self.delete_button.setEnabled(False)
self.build_function_names_box()
self.program.setReadOnly(False)
else:
error_dialog(self.gui, _('Stored templates'),
_('Function not defined'), show=True)
def create_button_clicked(self, use_name=None):
self.changed_signal.emit()
name = use_name if use_name else unicode_type(self.function_name.currentText())
for k,v in formatter_functions().get_functions().items():
if k == name and v.is_python:
error_dialog(self.gui, _('Stored templates'),
_('Name %s is already used for template function')%(name,), show=True)
try:
prog = unicode_type(self.program.text())
if not prog.startswith('program:'):
error_dialog(self.gui, _('Stored templates'),
_('The stored template must begin with "program:"'), show=True)
cls = compile_user_function(name, unicode_type(self.documentation.toPlainText()),
0, prog)
self.funcs[name] = cls
self.build_function_names_box(scroll_to=name)
except:
error_dialog(self.gui, _('Stored templates'),
_('Exception while storing template'), show=True,
det_msg=traceback.format_exc())
def function_name_edited(self, txt):
self.documentation.setReadOnly(False)
self.create_button.setEnabled(True)
self.replace_button.setEnabled(False)
self.program.setReadOnly(False)
def function_index_changed(self, txt):
txt = unicode_type(txt)
self.create_button.setEnabled(False)
if not txt:
self.program.clear()
self.documentation.clear()
self.documentation.setReadOnly(False)
return
func = self.funcs[txt]
self.documentation.setText(func.doc)
self.program.setText(func.program_text)
self.delete_button.setEnabled(True)
self.program.setReadOnly(False)
self.replace_button.setEnabled(False)
def replace_button_clicked(self):
name = unicode_type(self.function_name.currentText())
self.delete_button_clicked()
self.create_button_clicked(use_name=name)
def refresh_gui(self, gui):
pass
def commit(self):
# formatter_functions().reset_to_builtins()
pref_value = [v for v in self.db.prefs.get('user_template_functions', [])
if function_pref_is_python(v)]
for v in self.funcs.values():
pref_value.append(v.to_pref())
self.db.new_api.set_pref('user_template_functions', pref_value)
funcs = compile_user_template_functions(pref_value)
self.db.new_api.set_user_template_functions(funcs)
self.gui.library_view.model().refresh()
load_user_template_functions(self.db.library_id, [], funcs)
return False
if __name__ == '__main__':
from PyQt5.Qt import QApplication
app = QApplication([])
test_widget('Advanced', 'StoredTemplates')

View File

@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
import json, traceback
from PyQt5.Qt import QDialogButtonBox
from PyQt5.Qt import Qt, QDialogButtonBox, QSizePolicy
from calibre.gui2 import error_dialog, warning_dialog
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
@ -78,6 +78,17 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
</p>
''')
self.textBrowser.setHtml(help_text)
help_text = '<p>' + _('''
Here you can add and remove stored templates used in template processing.
You use a stored template in another template with the 'call' template
function, as in 'call(somename, arguments...). Stored templates must use
General Program Mode -- they must begin with the text 'program:'.
In the stored template you get the arguments using the 'arguments()'
template function, as in arguments(var1, var2, ...). The calling arguments
are copied to the named variables.
''') + '</p>'
self.st_textBrowser.setHtml(help_text)
self.st_textBrowser.adjustSize()
def initialize(self):
try:
@ -92,6 +103,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.builtins = formatter_functions().get_builtins_and_aliases()
self.st_funcs = {}
for v in self.db.prefs.get('user_template_functions', []):
if not function_pref_is_python(v):
self.st_funcs.update({function_pref_name(v):compile_user_function(*v)})
self.build_function_names_box()
self.function_name.currentIndexChanged[native_string_type].connect(self.function_index_changed)
self.function_name.editTextChanged.connect(self.function_name_edited)
@ -108,6 +124,24 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.program.setTabStopWidth(20)
self.highlighter = PythonHighlighter(self.program.document())
self.st_build_function_names_box()
self.template_editor.template_name.currentIndexChanged[native_string_type].connect(self.st_function_index_changed)
self.template_editor.template_name.editTextChanged.connect(self.st_template_name_edited)
self.template_editor.new_doc.textChanged.connect(self.st_enable_replace_button)
self.template_editor.textbox.textChanged.connect(self.st_enable_replace_button)
self.st_create_button.clicked.connect(self.st_create_button_clicked)
self.st_delete_button.clicked.connect(self.st_delete_button_clicked)
self.st_create_button.setEnabled(False)
self.st_delete_button.setEnabled(False)
self.st_replace_button.setEnabled(False)
self.st_clear_button.clicked.connect(self.st_clear_button_clicked)
self.st_replace_button.clicked.connect(self.st_replace_button_clicked)
self.st_button_layout.insertSpacing(0, 90)
self.template_editor.new_doc.setFixedHeight(50)
# Python funtion tab
def enable_replace_button(self):
self.replace_button.setEnabled(self.delete_button.isEnabled())
@ -228,12 +262,98 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
def refresh_gui(self, gui):
pass
# Stored template tab
def st_enable_replace_button(self):
self.st_replace_button.setEnabled(self.st_delete_button.isEnabled())
def st_clear_button_clicked(self):
self.st_build_function_names_box()
self.template_editor.textbox.clear()
self.template_editor.new_doc.clear()
self.st_create_button.setEnabled(False)
self.st_delete_button.setEnabled(False)
def st_build_function_names_box(self, scroll_to=''):
self.template_editor.template_name.blockSignals(True)
func_names = sorted(self.st_funcs)
self.template_editor.template_name.clear()
self.template_editor.template_name.addItem('')
self.template_editor.template_name.addItems(func_names)
self.template_editor.template_name.setCurrentIndex(0)
self.template_editor.template_name.blockSignals(False)
if scroll_to:
idx = self.template_editor.template_name.findText(scroll_to)
if idx >= 0:
self.template_editor.template_name.setCurrentIndex(idx)
def st_delete_button_clicked(self):
name = unicode_type(self.template_editor.template_name.currentText())
if name in self.st_funcs:
del self.st_funcs[name]
self.changed_signal.emit()
self.st_create_button.setEnabled(True)
self.st_delete_button.setEnabled(False)
self.st_build_function_names_box()
self.template_editor.textbox.setReadOnly(False)
else:
error_dialog(self.gui, _('Stored templates'),
_('Function not defined'), show=True)
def st_create_button_clicked(self, use_name=None):
self.changed_signal.emit()
name = use_name if use_name else unicode_type(self.template_editor.template_name.currentText())
for k,v in formatter_functions().get_functions().items():
if k == name and v.is_python:
error_dialog(self.gui, _('Stored templates'),
_('Name %s is already used for template function')%(name,), show=True)
try:
prog = unicode_type(self.template_editor.textbox.toPlainText())
if not prog.startswith('program:'):
error_dialog(self.gui, _('Stored templates'),
_('The stored template must begin with "program:"'), show=True)
cls = compile_user_function(name, unicode_type(self.template_editor.new_doc.toPlainText()),
0, prog)
self.st_funcs[name] = cls
self.st_build_function_names_box(scroll_to=name)
except:
error_dialog(self.gui, _('Stored templates'),
_('Exception while storing template'), show=True,
det_msg=traceback.format_exc())
def st_template_name_edited(self, txt):
self.st_create_button.setEnabled(True)
self.st_replace_button.setEnabled(False)
self.template_editor.textbox.setReadOnly(False)
def st_function_index_changed(self, txt):
txt = unicode_type(txt)
self.st_create_button.setEnabled(False)
if not txt:
self.template_editor.textbox.clear()
self.template_editor.new_doc.clear()
return
func = self.st_funcs[txt]
self.template_editor.new_doc.setPlainText(func.doc)
self.template_editor.textbox.setPlainText(func.program_text)
self.st_delete_button.setEnabled(True)
self.template_editor.textbox.setReadOnly(False)
self.st_replace_button.setEnabled(False)
def st_replace_button_clicked(self):
name = unicode_type(self.template_editor.template_name.currentText())
self.st_delete_button_clicked()
self.st_create_button_clicked(use_name=name)
def commit(self):
pref_value = [v for v in self.db.prefs.get('user_template_functions', [])
if not function_pref_is_python(v)]
pref_value = []
for name, cls in iteritems(self.funcs):
print(name)
if name not in self.builtins:
pref_value.append(cls.to_pref())
for v in self.st_funcs.values():
pref_value.append(v.to_pref())
self.db.new_api.set_pref('user_template_functions', pref_value)
funcs = compile_user_template_functions(pref_value)
self.db.new_api.set_user_template_functions(funcs)

View File

@ -6,155 +6,251 @@
<rect>
<x>0</x>
<y>0</y>
<width>798</width>
<height>672</height>
<width>788</width>
<height>663</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Function:</string>
</property>
<property name="buddy">
<cstring>function_name</cstring>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>&amp;Stored Templates</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2" stretch="0">
<widget class="QTextBrowser" name="st_textBrowser"/>
</item>
<item row="3" column="1" stretch="1">
<widget class="EmbeddedTemplateDialog" name="template_editor">
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="function_name">
<property name="toolTip">
<string>Enter the name of the function to create.</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Argument &amp;count:</string>
</property>
<property name="buddy">
<cstring>argument_count</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="argument_count">
<property name="toolTip">
<string>Set this to -1 if the function takes a variable number of arguments</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QTextEdit" name="documentation"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Documentation:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="buddy">
<cstring>documentation</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item row="3" column="0">
<layout class="QVBoxLayout" name="st_button_layout">
<item>
<widget class="QPushButton" name="clear_button">
<widget class="QPushButton" name="st_clear_button">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="delete_button">
<widget class="QPushButton" name="st_delete_button">
<property name="text">
<string>&amp;Delete</string>
<string>D&amp;elete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="replace_button">
<widget class="QPushButton" name="st_replace_button">
<property name="text">
<string>&amp;Replace</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="create_button">
<widget class="QPushButton" name="st_create_button">
<property name="text">
<string>C&amp;reate</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="horizontalLayout1">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Program code (Follow Python indenting rules):</string>
<item row="5" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="buddy">
<cstring>program</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="program">
<property name="minimumSize">
<property name="sizeHint" stdset="0">
<size>
<width>400</width>
<height>0</height>
<width>20</width>
<height>400</height>
</size>
</property>
<property name="documentTitle">
<string notr="true"/>
</property>
<property name="tabStopWidth">
<number>30</number>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>&amp;Template Functions</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>F&amp;unction:</string>
</property>
<property name="buddy">
<cstring>function_name</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="function_name">
<property name="toolTip">
<string>Enter the name of the function to create.</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Argument &amp;count:</string>
</property>
<property name="buddy">
<cstring>argument_count</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="argument_count">
<property name="toolTip">
<string>Set this to -1 if the function takes a variable number of arguments</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QTextEdit" name="documentation"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>D&amp;ocumentation:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="buddy">
<cstring>documentation</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="clear_button">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="delete_button">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="replace_button">
<property name="text">
<string>Replace</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="create_button">
<property name="text">
<string>C&amp;reate</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="horizontalLayout1">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>P&amp;rogram code (Follow Python indenting rules):</string>
</property>
<property name="buddy">
<cstring>program</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="program">
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="documentTitle">
<string notr="true"/>
</property>
<property name="tabStopWidth">
<number>30</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
</layout>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QTextBrowser" name="textBrowser"/>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
<customwidgets>
<customwidget>
<class>EmbeddedTemplateDialog</class>
<extends>TemplateDialog</extends>
<header>calibre/gui2/dialogs/template_dialog.h</header>
</customwidget>
<customwidget>
<class>TemplateDialog</class>
<extends>QDialog</extends>
<header>calibre/gui2/dialogs/template_dialog.h</header>
</customwidget>
</customwidgets>
</ui>