mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04: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