mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-04 03:27:00 -05:00 
			
		
		
		
	Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
		
						commit
						623b1d69f2
					
				@ -677,10 +677,17 @@ Here is an example of a PTM template that produces a list of all the authors for
 | 
			
		||||
    def evaluate(book, context):
 | 
			
		||||
        if book.series is None:
 | 
			
		||||
            return ''
 | 
			
		||||
        db = context.db.new_api
 | 
			
		||||
        ans = set()
 | 
			
		||||
        db = context.db
 | 
			
		||||
        for id_ in db.search_getting_ids(f'series:"={book.series}"', ''):
 | 
			
		||||
            ans.update(v.strip() for v in db.new_api.field_for('author_sort', id_).split('&'))
 | 
			
		||||
        # Get the list of books in the series
 | 
			
		||||
        ids = db.search(f'series:"={book.series}"', '')
 | 
			
		||||
        if ids:
 | 
			
		||||
            # Get all the author_sort values for the books in the series
 | 
			
		||||
            author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
 | 
			
		||||
            # Add the names to the result set, removing duplicates
 | 
			
		||||
            for aus in author_sorts:
 | 
			
		||||
                ans.update(v.strip() for v in aus.split('&'))
 | 
			
		||||
        # Make a sorted comma-separated string from the result set
 | 
			
		||||
        return ', '.join(v.replace(',', ';') for v in sorted(ans))
 | 
			
		||||
 | 
			
		||||
The output in :guilabel:`Book details` looks like this:
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,8 @@ from calibre import sanitize_file_name
 | 
			
		||||
from calibre.constants import config_dir
 | 
			
		||||
from calibre.ebooks.metadata.book.base import Metadata
 | 
			
		||||
from calibre.ebooks.metadata.book.formatter import SafeFormat
 | 
			
		||||
from calibre.gui2 import gprefs, error_dialog, choose_files, choose_save_file, pixmap_to_data
 | 
			
		||||
from calibre.gui2 import (gprefs, error_dialog, choose_files, choose_save_file,
 | 
			
		||||
                          pixmap_to_data, question_dialog)
 | 
			
		||||
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
 | 
			
		||||
from calibre.library.coloring import (displayable_columns, color_row_key)
 | 
			
		||||
from calibre.utils.config_base import tweaks
 | 
			
		||||
@ -84,45 +85,30 @@ class TemplateHighlighter(QSyntaxHighlighter):
 | 
			
		||||
            r.append((re.compile(a), b))
 | 
			
		||||
 | 
			
		||||
        if not for_python:
 | 
			
		||||
            a(
 | 
			
		||||
                r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
 | 
			
		||||
                r"|\$+#?[a-zA-Z]\w*",
 | 
			
		||||
                "identifier")
 | 
			
		||||
 | 
			
		||||
            a(r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
 | 
			
		||||
              r"|\$+#?[a-zA-Z]\w*",
 | 
			
		||||
              "identifier")
 | 
			
		||||
            a(r"^program:", "keymode")
 | 
			
		||||
            a(
 | 
			
		||||
                "|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]),
 | 
			
		||||
                "keyword")
 | 
			
		||||
 | 
			
		||||
            a(
 | 
			
		||||
                "|".join([r"\b%s\b" % builtin for builtin in
 | 
			
		||||
            a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]), "keyword")
 | 
			
		||||
            a("|".join([r"\b%s\b" % builtin for builtin in
 | 
			
		||||
                            (builtin_functions if builtin_functions else
 | 
			
		||||
                                                formatter_functions().get_builtins())]),
 | 
			
		||||
                "builtin")
 | 
			
		||||
 | 
			
		||||
            a(r"""(?<!:)'[^']*'|"[^"]*\"""", "string")
 | 
			
		||||
        else:
 | 
			
		||||
            a(r"^python:", "keymode")
 | 
			
		||||
 | 
			
		||||
            a(
 | 
			
		||||
                "|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]),
 | 
			
		||||
                "keyword")
 | 
			
		||||
            a(
 | 
			
		||||
                "|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS_PYTHON]),
 | 
			
		||||
                "builtin")
 | 
			
		||||
            a(
 | 
			
		||||
                "|".join([r"\b%s\b" % constant for constant in self.CONSTANTS_PYTHON]),
 | 
			
		||||
                "constant")
 | 
			
		||||
 | 
			
		||||
            a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]), "keyword")
 | 
			
		||||
            a("|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS_PYTHON]), "builtin")
 | 
			
		||||
            a("|".join([r"\b%s\b" % constant for constant in self.CONSTANTS_PYTHON]), "constant")
 | 
			
		||||
            a(r"\bPyQt6\b|\bqt.core\b|\bQt?[A-Z][a-z]\w+\b", "pyqt")
 | 
			
		||||
            a(r"@\w+(\.\w+)?\b", "decorator")
 | 
			
		||||
 | 
			
		||||
            a(r"""('|").*?\1""", "string")
 | 
			
		||||
            stringRe = r"""((?:"|'){3}).*?\1"""
 | 
			
		||||
            a(stringRe, "string")
 | 
			
		||||
            self.stringRe = re.compile(stringRe)
 | 
			
		||||
            self.tripleSingleRe = re.compile(r"""'''(?!")""")
 | 
			
		||||
            self.tripleDoubleRe = re.compile(r'''"""(?!')''')
 | 
			
		||||
            a(r'#[^\n]*', "comment")
 | 
			
		||||
        a(
 | 
			
		||||
            r"\b[+-]?[0-9]+[lL]?\b"
 | 
			
		||||
            r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
 | 
			
		||||
@ -197,17 +183,6 @@ class TemplateHighlighter(QSyntaxHighlighter):
 | 
			
		||||
        elif text[0] == "#":
 | 
			
		||||
            self.setFormat(0, textLength, self.Formats["comment"])
 | 
			
		||||
            return
 | 
			
		||||
        elif self.for_python:
 | 
			
		||||
            stack = []
 | 
			
		||||
            for i, c in enumerate(text):
 | 
			
		||||
                if c in ('"', "'"):
 | 
			
		||||
                    if stack and stack[-1] == c:
 | 
			
		||||
                        stack.pop()
 | 
			
		||||
                    else:
 | 
			
		||||
                        stack.append(c)
 | 
			
		||||
                elif c == "#" and len(stack) == 0:
 | 
			
		||||
                    self.setFormat(i, len(text), self.Formats["comment"])
 | 
			
		||||
                    return
 | 
			
		||||
 | 
			
		||||
        for regex, format_ in self.Rules:
 | 
			
		||||
            for m in regex.finditer(text):
 | 
			
		||||
@ -430,6 +405,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
 | 
			
		||||
                self.textbox.setPlainText(text)
 | 
			
		||||
        else:
 | 
			
		||||
            text = ''
 | 
			
		||||
        self.original_text = text
 | 
			
		||||
 | 
			
		||||
        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
 | 
			
		||||
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel'))
 | 
			
		||||
 | 
			
		||||
@ -852,6 +829,16 @@ def evaluate(book, context):
 | 
			
		||||
        gprefs['template_editor_table_widths'] = self.table_column_widths
 | 
			
		||||
        gprefs['template_editor_dialog_geometry'] = bytearray(self.saveGeometry())
 | 
			
		||||
 | 
			
		||||
    def keyPressEvent(self, ev):
 | 
			
		||||
        if ev.key() == Qt.Key.Key_Escape:
 | 
			
		||||
            # Check about ESC to avoid killing the dialog by mistake
 | 
			
		||||
            if self.textbox.toPlainText() != self.original_text:
 | 
			
		||||
                r = question_dialog(self, _('Discard changes?'),
 | 
			
		||||
                      _('Do you really want to close this dialog, discarding any changes?'))
 | 
			
		||||
                if not r:
 | 
			
		||||
                    return
 | 
			
		||||
        QDialog.keyPressEvent(self, ev)
 | 
			
		||||
 | 
			
		||||
    def accept(self):
 | 
			
		||||
        txt = str(self.textbox.toPlainText()).rstrip()
 | 
			
		||||
        if (self.coloring or self.iconing or self.embleming) and not txt:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user