diff --git a/src/calibre/gui2/fts/cards.py b/src/calibre/gui2/fts/cards.py index 8df3425d0e..543a401db3 100644 --- a/src/calibre/gui2/fts/cards.py +++ b/src/calibre/gui2/fts/cards.py @@ -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'' + '\xa0{text}\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: {prepare_string_for_xml(self.results.title)}
{prepare_string_for_xml(authors_to_string(self.results.authors))}
{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 diff --git a/src/calibre/gui2/fts/search.py b/src/calibre/gui2/fts/search.py index 1cdb67f2c2..587b2b905c 100644 --- a/src/calibre/gui2/fts/search.py +++ b/src/calibre/gui2/fts/search.py @@ -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 = '' text += '

{2}\xa0{0}\xa0\xa0\xa0 '.format( _('Select'), '

' + _('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 += '{2}\xa0{0}

'.format( _('Mark'), '

' + _( - '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('

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('

marked:true'), ict.format('marked.png')) if get_db().has_id(results.book_id): text += '

{2}\xa0{0}'.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) diff --git a/src/calibre/gui2/fts/utils.py b/src/calibre/gui2/fts/utils.py index 77926511e7..9f2c1fd836 100644 --- a/src/calibre/gui2/fts/utils.py +++ b/src/calibre/gui2/fts/utils.py @@ -23,3 +23,9 @@ def markup_text(text: str) -> str: return '' if closing else '' 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', '')