This commit is contained in:
Kovid Goyal 2025-06-29 07:36:19 +05:30
commit e008592fe7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 51 additions and 40 deletions

View File

@ -885,3 +885,39 @@ def field_from_string(field, raw, field_metadata):
if val is object:
val = raw
return val
def get_model_metadata_instance():
'''
Get a metadata instance that contains all the fields in the current database
with the fields to a plausible value. This function must only be used in
the GUI thread.
'''
from calibre.gui2 import is_gui_thread
if not is_gui_thread():
raise ValueError('get_model_metadata_instance() must only be used in the GUI thread')
mi = Metadata(_('Title'), [_('Author')])
mi.author_sort = _('Author Sort')
mi.series = ngettext('Series', 'Series', 1)
mi.series_index = 3
mi.rating = 4.0
mi.tags = [_('Tag 1'), _('Tag 2')]
mi.languages = ['eng']
mi.id = -1
from calibre.gui2.ui import get_gui
from calibre.utils.date import DEFAULT_DATE
fm = get_gui().current_db.new_api.field_metadata
mi.set_all_user_metadata(fm.custom_field_metadata())
for col in mi.get_all_user_metadata(False):
if fm[col]['datatype'] == 'datetime':
mi.set(col, DEFAULT_DATE)
elif fm[col]['datatype'] in ('int', 'float', 'rating'):
mi.set(col, 2)
elif fm[col]['datatype'] == 'bool':
mi.set(col, False)
elif fm[col]['is_multiple']:
mi.set(col, [col])
else:
mi.set(col, col, 1)
return mi

View File

@ -44,7 +44,7 @@ from qt.core import (
from calibre import sanitize_file_name
from calibre.constants import config_dir, iswindows
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.book.base import get_model_metadata_instance
from calibre.ebooks.metadata.book.formatter import SafeFormat
from calibre.gui2 import choose_files, choose_save_file, error_dialog, gprefs, info_dialog, pixmap_to_data, question_dialog, safe_open_url
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
@ -52,13 +52,12 @@ from calibre.gui2.dialogs.template_general_info import GeneralInformationDialog
from calibre.gui2.widgets2 import Dialog, HTMLDisplay
from calibre.library.coloring import color_row_key, displayable_columns
from calibre.utils.config_base import tweaks
from calibre.utils.date import DEFAULT_DATE
from calibre.utils.ffml_processor import MARKUP_ERROR, FFMLProcessor
from calibre.utils.formatter import PythonTemplateContext, StopException
from calibre.utils.formatter_functions import StoredObjectType, formatter_functions
from calibre.utils.icu import lower as icu_lower
from calibre.utils.icu import sort_key
from calibre.utils.localization import localize_user_manual_link, ngettext
from calibre.utils.localization import localize_user_manual_link
from calibre.utils.resources import get_path as P
@ -718,40 +717,11 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
the contents of the field selectors for editing rules.
'''
self.fm = fm
from calibre.gui2.ui import get_gui
if mi:
if not isinstance(mi, (tuple, list)):
mi = (mi, )
else:
mi = Metadata(_('Title'), [_('Author')])
mi.author_sort = _('Author Sort')
mi.series = ngettext('Series', 'Series', 1)
mi.series_index = 3
mi.rating = 4.0
mi.tags = [_('Tag 1'), _('Tag 2')]
mi.languages = ['eng']
mi.id = -1
if self.fm is not None:
mi.set_all_user_metadata(self.fm.custom_field_metadata())
else:
# No field metadata. Grab a copy from the current library so
# that we can validate any custom column names. The values for
# the columns will all be empty, which in some very unusual
# cases might cause formatter errors. We can live with that.
fm = get_gui().current_db.new_api.field_metadata
mi.set_all_user_metadata(fm.custom_field_metadata())
for col in mi.get_all_user_metadata(False):
if fm[col]['datatype'] == 'datetime':
mi.set(col, DEFAULT_DATE)
elif fm[col]['datatype'] in ('int', 'float', 'rating'):
mi.set(col, 2)
elif fm[col]['datatype'] == 'bool':
mi.set(col, False)
elif fm[col]['is_multiple']:
mi.set(col, [col])
else:
mi.set(col, col, 1)
mi = (mi, )
mi = (get_model_metadata_instance(), )
self.mi = mi
tv = self.template_value
tv.setColumnCount(3)

View File

@ -2025,17 +2025,22 @@ class TemplateFormatter(string.Formatter):
self.restore_state(state)
class ValidateFormatter(TemplateFormatter):
'''
Provides a formatter that substitutes the validation string for every value
class ValidateFormatter:
'''
Provides a formatter that uses a fake book. This class must be used only
in the GUI thread.
def get_value(self, key, args, kwargs):
return self._validation_string
It is a class instead of a function for compatibility reasons.
'''
def validate(self, template):
from calibre.ebooks.metadata.book.base import Metadata
return self.unsafe_format(template, {}, Metadata(''))
from calibre.gui2 import is_gui_thread
if not is_gui_thread():
raise ValueError('A ValidateFormatter must only be used in the GUI thread')
from calibre.ebooks.metadata.book.base import get_model_metadata_instance
from calibre.ebooks.metadata.book.formatter import SafeFormat
return SafeFormat().unsafe_format(template, {}, get_model_metadata_instance())
validation_formatter = ValidateFormatter()