View Single Post
Old 12-24-2020, 09:30 AM   #173
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,198
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
EDIT: A modified version of this action is available as a builtin action in the action chains plugin starting from version 1.4.0. The builtin action is called "Search Using Templates".

This is a custom action that allows constructing a calibre search using calibre template editor. The search can be a simple text search or a search constructed from a template.

Code:
# python3 compatibility
from six import text_type as unicode

from calibre import prints
from calibre.constants import DEBUG
from calibre.gui2 import error_dialog
from calibre.ebooks.metadata.book.formatter import SafeFormat

from calibre_plugins.action_chains.actions.base import ChainAction
from calibre_plugins.action_chains.database import is_search_valid
from calibre_plugins.action_chains.templates import check_template, get_metadata_object
from calibre_plugins.action_chains.templates.dialogs import TemplateBox

try:
    load_translations()
except NameError:
    prints("ActionsChain::action/search.py - exception when loading translations")

class TemplateSearchWidget(TemplateBox):
    def __init__(self, parent, plugin_action, action, name, title):
        self.plugin_action = plugin_action
        self.action = action
        self.gui = plugin_action.gui
        self.db = self.gui.current_db
        mi = get_metadata_object(self.gui)
        TemplateBox.__init__(
                self,
                parent,
                plugin_action,
                template_text='',
                placeholder_text=_('Enter a search expression here. It can be either '
                                   'an ordinary text string or a template.'),
                mi=mi
            )
        self.setWindowTitle(title)

    def textbox_changed(self):
        TemplateBox.textbox_changed(self)
        template = self.template_value.text()
        text = SafeFormat().safe_format(template, self.mi, 'Exception: ', self.mi, template_functions=self.plugin_action.template_functions)
        if text:
            ok = is_search_valid(self.db, text) and not text.lower().startswith('exception:')
            ss = 'QLineEdit { border: 2px solid %s; border-radius: 3px }' % (
            '#50c878' if ok else '#FF2400')
            self.template_value.setStyleSheet(ss)
        else:
            self.template_value.setStyleSheet('')

    def load_settings(self, settings):
        if settings:
            template = settings['template']
            self.textbox.insertPlainText(template)

    def save_settings(self):
        settings = {}
        settings['template'] = unicode(self.textbox.toPlainText()).rstrip()
        return settings

    def accept(self):
        self.settings = self.save_settings()
        # validate settings
        is_valid = self.action.validate(self.settings)
        if is_valid is not True:
            msg, details = is_valid
            error_dialog(
                self,
                msg,
                details,
                show=True
            )
            return
        TemplateBox.accept(self)

class TemplateSearchAction(ChainAction):

    name = 'Template Search'

    def run(self, gui, settings, chain):
        template = settings['template']
        template_output = chain.evaluate_template(template, book_id=None)
        gui.search.clear()
        gui.search.set_search_string(template_output)

    def validate(self, settings):
        gui = self.plugin_action.gui
        db = gui.current_db
        if not settings:
            return (_('Settings Error'), _('You must configure this action before running it'))
        mi = get_metadata_object(gui)
        is_template_valid = check_template(settings['template'], self.plugin_action, print_error=False)
        if is_template_valid is not True:
            return is_template_valid
        search_text = SafeFormat().safe_format(settings['template'], mi, 'Exception: ', mi, template_functions=self.plugin_action.template_functions)
        if not is_search_valid(db, search_text):
            return (_('Settings Error'), _('Search ({}) is not valid'.format(search_text)))
        return True

    def config_widget(self):
        return TemplateSearchWidget
N.B This custom action will not work with Action Chains versions < 1.2.0

Last edited by capink; 04-25-2021 at 06:18 AM.
capink is offline   Reply With Quote