diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index 7c10ede34d..b542593a79 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -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]
# }}}
diff --git a/src/calibre/gui2/actions/show_stored_templates.py b/src/calibre/gui2/actions/show_stored_templates.py
index 9164a7d5ba..33fe1f8d38 100644
--- a/src/calibre/gui2/actions/show_stored_templates.py
+++ b/src/calibre/gui2/actions/show_stored_templates.py
@@ -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_()
diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py
index 81706fbb40..89d88e3c19 100644
--- a/src/calibre/gui2/dialogs/template_dialog.py
+++ b/src/calibre/gui2/dialogs/template_dialog.py
@@ -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([])
diff --git a/src/calibre/gui2/dialogs/template_dialog.ui b/src/calibre/gui2/dialogs/template_dialog.ui
index 9f6d38399c..6c5b45f666 100644
--- a/src/calibre/gui2/dialogs/template_dialog.ui
+++ b/src/calibre/gui2/dialogs/template_dialog.ui
@@ -141,11 +141,68 @@
- ' + _('''
- 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.
- ''') + '
' + _(''' + 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. + ''') + '
' + 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) diff --git a/src/calibre/gui2/preferences/template_functions.ui b/src/calibre/gui2/preferences/template_functions.ui index 56111e6831..da04514b69 100644 --- a/src/calibre/gui2/preferences/template_functions.ui +++ b/src/calibre/gui2/preferences/template_functions.ui @@ -6,155 +6,251 @@