diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index 7d8f16856b..0c9d7221e0 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -22,7 +22,7 @@ from functools import partial import apsw from calibre import as_unicode, force_unicode, isbytestring, prints -from calibre.constants import filesystem_encoding, iswindows, plugins, preferred_encoding, builtin_colors_light, builtin_decorations +from calibre.constants import builtin_colors_light, builtin_decorations, filesystem_encoding, iswindows, plugins, preferred_encoding from calibre.db import SPOOL_SIZE, FTSQueryError from calibre.db.annotations import annot_db_data, unicode_normalize from calibre.db.constants import ( @@ -2563,6 +2563,8 @@ class DB: q += ' WHERE ' + ' AND '.join(restrict_clauses) q += ' ORDER BY timestamp DESC ' count = 0 + query_style = None if annotation_style is None else tuple(annotation_style.items()) + sentinel = object() for (rowid, book_id, fmt, user_type, user, annot_data) in self.execute(q, tuple(data)): if restrict_to_book_ids is not None and book_id not in restrict_to_book_ids: continue @@ -2577,13 +2579,9 @@ class DB: if atype == 'bookmark': text = annot['title'] elif atype == 'highlight': - if annotation_style: - query_style = ls(annotation_style) - # Accept only if the styles in annotation_style are all present in the annotation style - annot_style = annot.get('style', {}) - if not all(annot_style.get(k) == v for k, v in query_style.items()): - continue - + if query_style is not None and ((s := annot.get('style')) is None + or not all(s.get(k, sentinel) == v for k, v in query_style)): + continue text = annot.get('highlighted_text') or '' yield { 'id': rowid, @@ -2604,7 +2602,7 @@ class DB: def all_annotation_types(self): for x in self.execute('SELECT DISTINCT annot_type FROM annotations'): yield x[0] - + def all_annotation_styles(self): all_styles = builtin_colors_light | builtin_decorations styles = {} diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 06256d3a7c..292c66dc9e 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -3448,11 +3448,14 @@ class Cache: return tuple(self.backend.all_annotation_types()) @read_api - def all_annotations(self, restrict_to_user=None, limit=None, annotation_type=None, annotation_style=None, ignore_removed=False, restrict_to_book_ids=None): + def all_annotations( + self, restrict_to_user=None, limit=None, annotation_type=None, annotation_style=None, + ignore_removed=False, restrict_to_book_ids=None, + ): ''' Return a tuple of all annotations matching the specified criteria. - `ignore_removed` controls whether removed (deleted) annotations are also returned. Removed annotations are just a skeleton - used for merging of annotations. + `ignore_removed` controls whether removed (deleted) annotations are also returned. + Removed annotations are just a skeleton used for merging of annotations. ''' return tuple(self.backend.all_annotations(restrict_to_user, limit, annotation_type, annotation_style, ignore_removed, restrict_to_book_ids)) diff --git a/src/calibre/gui2/library/annotations.py b/src/calibre/gui2/library/annotations.py index 86f9301786..1e0bf5e0ef 100644 --- a/src/calibre/gui2/library/annotations.py +++ b/src/calibre/gui2/library/annotations.py @@ -627,17 +627,17 @@ class Restrictions(QWidget): before = gprefs['browse_annots_restrict_to_type'] tb.blockSignals(True) tb.clear() - tb.addItem(' ', ' ') + tb.addItem(' ', {}) annotation_types = db.all_annotation_types() for atype in annotation_types: - tb.addItem(annotation_title(atype), atype) + tb.addItem(annotation_title(atype), {'type': atype}) if before: row = tb.findData(before) if row > -1: tb.setCurrentIndex(row) - + # Append highlight colors after the 'highlight' entry, if it exists - highlight_row = tb.findData('highlight') + highlight_row = tb.findData({'type': 'highlight'}) if highlight_row > -1: from calibre.gui2.viewer.highlights import decoration_for_style dpr = self.devicePixelRatioF() @@ -645,9 +645,10 @@ class Restrictions(QWidget): model = tb.model() highlight_color_row = 1 all_styles = db.all_annotation_styles() + translate = _ for style_name, style in all_styles.items(): - item = QStandardItem(_(annotation_title(style_name))) - item.setData('highlight:{}'.format(json.dumps(style)), Qt.ItemDataRole.UserRole) + item = QStandardItem(translate(annotation_title(style_name))) + item.setData({'type': 'highlight', 'style': style}, Qt.ItemDataRole.UserRole) dec = decoration_for_style(self.palette(), style, self.icon_size, dpr, is_dark) if dec: item.setData(dec, Qt.ItemDataRole.DecorationRole) @@ -677,6 +678,7 @@ class Restrictions(QWidget): self.rla.setVisible(tb_is_visible or ub_is_visible) self.setVisible(True) + class BrowsePanel(QWidget): current_result_changed = pyqtSignal(object) @@ -751,13 +753,15 @@ class BrowsePanel(QWidget): @property def effective_query(self): text = self.search_box.lineEdit().text().strip() - annotation_data = self.restrictions.types_box.currentData().split(':', 1) - atype = annotation_data[0] if annotation_data else '' - astyle = annotation_data[1] if len(annotation_data) > 1 else None + data = self.restrictions.types_box.currentData() + atype, style = '', None + if isinstance(data, dict): + atype = data.get('type') or '' + style = data.get('style') return { 'fts_engine_query': text, 'annotation_type': atype.strip(), - 'annotation_style': astyle.strip() if astyle else None, + 'annotation_style': style, 'restrict_to_user': self.restrict_to_user, 'use_stemming': bool(self.use_stemmer.isChecked()), 'restrict_to_book_ids': self.restrictions.effective_restrict_to_book_ids,