Add button line to FTS cards

This commit is contained in:
Kovid Goyal 2026-03-15 15:38:51 +05:30
parent b6e47e44d7
commit 9b41ea2bbc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 66 additions and 11 deletions

View File

@ -23,6 +23,7 @@ from qt.core import (
QTextDocument,
QTimer,
QUrl,
QVariant,
QVBoxLayout,
QWidget,
pyqtSignal,
@ -32,7 +33,7 @@ from calibre import prepare_string_for_xml
from calibre.db.cache import Cache
from calibre.ebooks.metadata import authors_to_string, fmt_sidx
from calibre.gui2 import config
from calibre.gui2.fts.utils import get_db
from calibre.gui2.fts.utils import get_db, jump_shortcut
from calibre.gui2.widgets import BusyCursor
from calibre.utils.img import resize_to_fit
@ -69,6 +70,42 @@ def default_cover():
return ic.pixmap(ic.availableSizes()[0]).toImage()
@lru_cache(maxsize=8)
def icon_resource_provider(qurl: QUrl) -> QVariant:
if qurl.scheme() == 'calibre-icon':
ic = QIcon.cached_icon(qurl.path().lstrip('/'))
if ic.is_ok():
dpr = QApplication.instance().devicePixelRatio()
pmap = ic.pixmap(ic.availableSizes()[0])
sz = QSizeF(16 * dpr, 16 * dpr).toSize()
pmap = pmap.scaled(sz, transformMode=Qt.TransformationMode.SmoothTransformation)
pmap.setDevicePixelRatio(dpr)
return pmap
return QVariant()
@lru_cache(maxsize=256)
def button_line(book_id: int, has_book: bool) -> str:
template = (
f'<a style="text-decoration: none" href="calibre://{{which}}/{book_id}" title="{{tt}}">'
'<img valign="bottom" src="calibre-icon:///{icon}">\xa0{text}</a>\xa0\xa0\xa0'
)
if has_book:
li = template.format(which='reindex', icon='view-refresh.png', text=_('Re-index'), tt=_(
'Re-index this book. Useful if the book has been changed outside of calibre, and thus not automatically re-indexed.'))
else:
li = template.format(which='unindex', icon='trash.png', text=_('Un-index'), tt=_(
'This book has been deleted from the library but is still present in the'
' full text search index. Remove it.'))
return (
template.format(which='jump', icon='lt.png', text=_('Select'), tt=_(
'Scroll to this book in the calibre library book list and select it [{}]').format(jump_shortcut())) +
template.format(which='mark', icon='marked.png', text=_('Mark'), tt=_(
'Put a pin on this book in the calibre library, for future reference.\n'
'You can search for marked books using the search term: {0}').format('marked:true')) +
li)
class CardData:
_height: int = -1
@ -133,9 +170,11 @@ class CardData:
<big><b>{prepare_string_for_xml(self.results.title)}</b></big><br>
{prepare_string_for_xml(authors_to_string(self.results.authors))}<br>
{series}
{button_line(self.results.book_id, self.results.book_in_db)}
'''
doc = QTextDocument()
doc.setDocumentMargin(0)
doc.setResourceProvider(icon_resource_provider)
doc.addResource(int(QTextDocument.ResourceType.ImageResource), QUrl('card://thumb'), c)
doc.setHtml(html)
self.doc = doc
@ -224,8 +263,10 @@ class VirtualCardContainer(QWidget):
authors = db._all_field_for('authors', all_books, [_('Unknown author')])
series = db._all_field_for('series', all_books, '')
series_indices = db._all_field_for('series_index', all_books, 1)
abids = db._all_book_ids(lambda x: x)
in_db = {bid: bid in abids for bid in all_books}
for card in self._cards:
card.results.preload(titles, authors, series, series_indices)
card.results.preload(titles, authors, series, series_indices, in_db)
def matches_found(self, num):
self._cards = tuple(CardData(r) for r in self.model.results) if num > 0 else ()
@ -459,3 +500,6 @@ class CardsView(QWidget):
def shutdown(self):
self.view.shutdown()
def current_result(self):
return None, None

View File

@ -47,7 +47,7 @@ from calibre.db import FTSQueryError
from calibre.ebooks.metadata import authors_to_string, fmt_sidx
from calibre.gui2 import config, error_dialog, gprefs, info_dialog, question_dialog, safe_open_url
from calibre.gui2.fts.cards import CardsView
from calibre.gui2.fts.utils import get_db, markup_text
from calibre.gui2.fts.utils import get_db, jump_shortcut, markup_text
from calibre.gui2.library.models import render_pin
from calibre.gui2.ui import get_gui
from calibre.gui2.viewer.widgets import ResultsDelegate, SearchBox
@ -58,7 +58,6 @@ from calibre.utils.localization import ngettext
ROOT = QModelIndex()
sanitize_text_pat = re.compile(r'\s+')
fts_url = 'https://www.sqlite.org/fts5.html#full_text_query_syntax'
jump_shortcut = ''
def mark_books(*book_ids):
@ -128,7 +127,7 @@ class SearchDelegate(ResultsDelegate):
class Results:
_title = _authors = _series = _series_index = None
_title = _authors = _series = _series_index = _book_in_db = None
def __init__(self, book_id):
self.book_id = book_id
@ -206,11 +205,18 @@ class Results:
self._series_index = 1
return self._series_index
def preload(self, titles, authors, series, series_indices):
@property
def book_in_db(self):
if self._book_in_db is None:
self._book_in_db = get_db().has_book(self.book_id)
return self._book_in_db
def preload(self, titles, authors, series, series_indices, in_db):
self._title = titles[self.book_id]
self._authors = authors[self.book_id]
self._series = series[self.book_id]
self._series_index = series_indices[self.book_id]
self._book_in_db = in_db[self.book_id]
class ResultsModel(QAbstractItemModel):
@ -713,11 +719,11 @@ class ResultDetails(QWidget):
ict = '<img valign="bottom" src="calibre-icon:///{}" width=16 height=16>'
text += '<p><a href="calibre://jump" title="{1}">{2}\xa0{0}</a>\xa0\xa0\xa0 '.format(
_('Select'), '<p>' + _('Scroll to this book in the calibre library book list and select it [{}]').format(
jump_shortcut), ict.format('lt.png'))
jump_shortcut()), ict.format('lt.png'))
text += '<a href="calibre://mark" title="{1}">{2}\xa0{0}</a></p>'.format(
_('Mark'), '<p>' + _(
'Put a pin on this book in the calibre library, for future reference.'
' You can search for marked books using the search term: {0}').format('<p>marked:true'), ict.format('marked.png'))
'Put a pin on this book in the calibre library, for future reference.\n'
'You can search for marked books using the search term: {0}').format('<p>marked:true'), ict.format('marked.png'))
if get_db().has_id(results.book_id):
text += '<p><a href="calibre://reindex" title="{1}">{2}\xa0{0}</a>'.format(
_('Re-index'), _('Re-index this book. Useful if the book has been changed outside of calibre, and thus not automatically re-indexed.'),
@ -883,12 +889,11 @@ class ResultsPanel(QWidget):
switch_to_scan_panel = pyqtSignal()
def __init__(self, parent=None):
global jump_shortcut
super().__init__(parent)
self.jump_to_current_book_action = ac = QAction(self)
ac.triggered.connect(self.jump_to_current_book)
ac.setShortcut(QKeySequence('Ctrl+S', QKeySequence.SequenceFormat.PortableText))
jump_shortcut = ac.shortcut().toString(QKeySequence.SequenceFormat.NativeText)
jump_shortcut(ac.shortcut().toString(QKeySequence.SequenceFormat.NativeText))
if isinstance(parent, QDialog):
parent.finished.connect(self.shutdown)
self.results_model = m = ResultsModel(self)

View File

@ -23,3 +23,9 @@ def markup_text(text: str) -> str:
return '<b><i>' if closing else '</i></b>'
return re.sub(r'\x1d', sub, prepare_string_for_xml(text))
def jump_shortcut(new_val: str = '') -> str:
if new_val:
setattr(jump_shortcut, 'ans', new_val)
return getattr(jump_shortcut, 'ans', '')