View Single Post
Old 08-30-2021, 04:56 AM   #8
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,118
Karma: 1954138
Join Date: Aug 2015
Device: Kindle
Action to launch tag editor

Code:
from qt.core import (QApplication, Qt, QWidget, QVBoxLayout, QHBoxLayout,
                     QGroupBox, QComboBox, QPushButton, QRadioButton)

from calibre.gui2.dialogs.tag_editor import TagEditor

from calibre_plugins.action_chains.actions.base import ChainAction
from calibre_plugins.action_chains.templates import check_template, TEMPLATE_ERROR
from calibre_plugins.action_chains.templates.dialogs import TemplateBox

def get_possible_cols(db):
    fm = db.field_metadata.custom_field_metadata()
    cols = [ col for col, cmeta in fm.items() if cmeta['is_multiple'] ]
    cols = [ col for col in cols if fm[col]['datatype'] not in ['composite',None] ]
    cols.insert(0, 'tags')
    return cols

class ItemEditorConfig(QWidget):
    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        self.gui = plugin_action.gui
        self.db = self.gui.current_db
        self.possible_cols = self.get_possible_cols()
        self.template = ''
        self._init_controls()

    def _init_controls(self):
        self.blockSignals(True)
        l = self.l = QVBoxLayout()
        self.setLayout(l)

        col_box = QGroupBox(_('Choose column:'))
        l.addWidget(col_box)
        col_box_layout = QVBoxLayout()
        col_box.setLayout(col_box_layout)

        name_layout = QHBoxLayout()
        col_box_layout.addLayout(name_layout)     
        name_opt = self.name_opt = QRadioButton(_('By column name'))
        name_layout.addWidget(name_opt)
        name_opt.setChecked(True)
        
        self.col_combobox = QComboBox()
        self.col_combobox.addItems(self.possible_cols)
        self.col_combobox.setCurrentText('tags')
        name_layout.addWidget(self.col_combobox)

        highlighted_opt = self.highlighted_opt = QRadioButton(_('Currently highlighted column'))
        col_box_layout.addWidget(highlighted_opt)

        template_layout = QHBoxLayout()
        col_box_layout.addLayout(template_layout)     
        template_opt = self.template_opt = QRadioButton(_('By template'))
        template_layout.addWidget(template_opt)
        
        self.template_button = QPushButton(_('Add template'))
        self.template_button.clicked.connect(self._on_template_button_clicked)
        template_layout.addWidget(self.template_button)

        l.addStretch(1)
        self.setMinimumSize(400,200)
        self.blockSignals(False)

    def get_possible_cols(self):
        return get_possible_cols(self.db)

    def _on_template_button_clicked(self):
        d = TemplateBox(self, self.plugin_action, template_text=self.template)
        if d.exec_() == d.Accepted:
            self.template = d.template
            self.template_button.setText(_('Edit template'))

    def load_settings(self, settings):
        if settings:
            if settings['col_opt'] == 'name':
                self.name_opt.setChecked(True)
                self.col_combobox.setCurrentText(settings['col_name'])
            elif settings['col_opt'] == 'highlighted':
                self.highlighted_opt.setChecked(True)
            elif settings['col_opt'] == 'template':
                self.template_opt.setChecked(True)
                self.template = settings['template']
                if self.template:
                    self.template_button.setText('Edit template')

    def save_settings(self):
        settings = {}
        if self.name_opt.isChecked():
            settings['col_opt'] = 'name'
            settings['col_name'] = self.col_combobox.currentText()
        elif self.highlighted_opt.isChecked():
            settings['col_opt'] = 'highlighted'
        else:
            settings['col_opt'] = 'template'
            settings['template'] = self.template
        return settings

class ItemEditorAction(ChainAction):

    name = 'Item Editor'

    def run(self, gui, settings, chain):
        db = gui.current_db
        rows = gui.current_view().selectionModel().selectedRows()
        book_ids = [ gui.library_view.model().db.id(row.row()) for row in rows ]

        if settings['col_opt'] == 'name':
            col_name = settings['col_name']
        elif settings['col_opt'] == 'highlighted':
            index = gui.library_view.currentIndex()
            column_map = gui.library_view.model().column_map
            col_name = column_map[index.column()]
        else:
            col_name = chain.evaluate_template(settings['template'])

        if col_name not in get_possible_cols(db):
            return

        if col_name == 'tags':
            key = None
        else:
            key = col_name
        
        if len(book_ids) == 0:
            return
        elif len(book_ids) == 1:
            book_id = book_ids[0]
        else:
            book_id = None

        d = TagEditor(gui, db, book_id, key)
        QApplication.setOverrideCursor(Qt.ArrowCursor)
        try:
            d.exec_()
        finally:
            QApplication.restoreOverrideCursor()
        if d.result() == d.Accepted:
            val = d.tags
            id_map = {book_id: val for book_id in book_ids}
            db.new_api.set_field(col_name, id_map)

        del d

    def config_widget(self):
        return ItemEditorConfig

    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'))
        if settings['col_opt'] == 'name':
            col_name = settings['col_name']
            if not col_name in get_possible_cols(db):
                return (_('Column Error'), _('Cannot find a column with name "{}" in current library'.format(col_name)))
        elif settings['col_opt'] == 'template':
            if not settings.get('template'):
                return (_('Empty Template Error'), _('Template for column name cannot be empty'))
            is_template_valid = check_template(settings['template'], self.plugin_action, print_error=False)
            if is_template_valid is not True:
                return is_template_valid
        return True
Warning: If you apply this action on multiple selected books, you will lose all preexisting tags on these books, as they will be overwritten by the new ones.

Note: you will need to configure this action before running it to choose the column.

Last edited by capink; 01-07-2022 at 06:10 AM.
capink is offline   Reply With Quote