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):
|
def evaluate(book, context):
|
||||||
if book.series is None:
|
if book.series is None:
|
||||||
return ''
|
return ''
|
||||||
|
db = context.db.new_api
|
||||||
ans = set()
|
ans = set()
|
||||||
db = context.db
|
# Get the list of books in the series
|
||||||
for id_ in db.search_getting_ids(f'series:"={book.series}"', ''):
|
ids = db.search(f'series:"={book.series}"', '')
|
||||||
ans.update(v.strip() for v in db.new_api.field_for('author_sort', id_).split('&'))
|
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))
|
return ', '.join(v.replace(',', ';') for v in sorted(ans))
|
||||||
|
|
||||||
The output in :guilabel:`Book details` looks like this:
|
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.constants import config_dir
|
||||||
from calibre.ebooks.metadata.book.base import Metadata
|
from calibre.ebooks.metadata.book.base import Metadata
|
||||||
from calibre.ebooks.metadata.book.formatter import SafeFormat
|
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.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
|
||||||
from calibre.library.coloring import (displayable_columns, color_row_key)
|
from calibre.library.coloring import (displayable_columns, color_row_key)
|
||||||
from calibre.utils.config_base import tweaks
|
from calibre.utils.config_base import tweaks
|
||||||
@ -84,45 +85,30 @@ class TemplateHighlighter(QSyntaxHighlighter):
|
|||||||
r.append((re.compile(a), b))
|
r.append((re.compile(a), b))
|
||||||
|
|
||||||
if not for_python:
|
if not for_python:
|
||||||
a(
|
a(r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
|
||||||
r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
|
r"|\$+#?[a-zA-Z]\w*",
|
||||||
r"|\$+#?[a-zA-Z]\w*",
|
"identifier")
|
||||||
"identifier")
|
|
||||||
|
|
||||||
a(r"^program:", "keymode")
|
a(r"^program:", "keymode")
|
||||||
a(
|
a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]), "keyword")
|
||||||
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]),
|
a("|".join([r"\b%s\b" % builtin for builtin in
|
||||||
"keyword")
|
|
||||||
|
|
||||||
a(
|
|
||||||
"|".join([r"\b%s\b" % builtin for builtin in
|
|
||||||
(builtin_functions if builtin_functions else
|
(builtin_functions if builtin_functions else
|
||||||
formatter_functions().get_builtins())]),
|
formatter_functions().get_builtins())]),
|
||||||
"builtin")
|
"builtin")
|
||||||
|
|
||||||
a(r"""(?<!:)'[^']*'|"[^"]*\"""", "string")
|
a(r"""(?<!:)'[^']*'|"[^"]*\"""", "string")
|
||||||
else:
|
else:
|
||||||
a(r"^python:", "keymode")
|
a(r"^python:", "keymode")
|
||||||
|
a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]), "keyword")
|
||||||
a(
|
a("|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS_PYTHON]), "builtin")
|
||||||
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]),
|
a("|".join([r"\b%s\b" % constant for constant in self.CONSTANTS_PYTHON]), "constant")
|
||||||
"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"\bPyQt6\b|\bqt.core\b|\bQt?[A-Z][a-z]\w+\b", "pyqt")
|
||||||
a(r"@\w+(\.\w+)?\b", "decorator")
|
a(r"@\w+(\.\w+)?\b", "decorator")
|
||||||
|
|
||||||
a(r"""('|").*?\1""", "string")
|
a(r"""('|").*?\1""", "string")
|
||||||
stringRe = r"""((?:"|'){3}).*?\1"""
|
stringRe = r"""((?:"|'){3}).*?\1"""
|
||||||
a(stringRe, "string")
|
a(stringRe, "string")
|
||||||
self.stringRe = re.compile(stringRe)
|
self.stringRe = re.compile(stringRe)
|
||||||
self.tripleSingleRe = re.compile(r"""'''(?!")""")
|
self.tripleSingleRe = re.compile(r"""'''(?!")""")
|
||||||
self.tripleDoubleRe = re.compile(r'''"""(?!')''')
|
self.tripleDoubleRe = re.compile(r'''"""(?!')''')
|
||||||
|
a(r'#[^\n]*', "comment")
|
||||||
a(
|
a(
|
||||||
r"\b[+-]?[0-9]+[lL]?\b"
|
r"\b[+-]?[0-9]+[lL]?\b"
|
||||||
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
|
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
|
||||||
@ -197,17 +183,6 @@ class TemplateHighlighter(QSyntaxHighlighter):
|
|||||||
elif text[0] == "#":
|
elif text[0] == "#":
|
||||||
self.setFormat(0, textLength, self.Formats["comment"])
|
self.setFormat(0, textLength, self.Formats["comment"])
|
||||||
return
|
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 regex, format_ in self.Rules:
|
||||||
for m in regex.finditer(text):
|
for m in regex.finditer(text):
|
||||||
@ -430,6 +405,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.textbox.setPlainText(text)
|
self.textbox.setPlainText(text)
|
||||||
else:
|
else:
|
||||||
text = ''
|
text = ''
|
||||||
|
self.original_text = text
|
||||||
|
|
||||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
|
||||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel'))
|
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_table_widths'] = self.table_column_widths
|
||||||
gprefs['template_editor_dialog_geometry'] = bytearray(self.saveGeometry())
|
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):
|
def accept(self):
|
||||||
txt = str(self.textbox.toPlainText()).rstrip()
|
txt = str(self.textbox.toPlainText()).rstrip()
|
||||||
if (self.coloring or self.iconing or self.embleming) and not txt:
|
if (self.coloring or self.iconing or self.embleming) and not txt:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user