Implement query params for annotation browser

This commit is contained in:
Kovid Goyal 2020-06-17 21:42:59 +05:30
parent f53ecbf7ba
commit 2c530d7c78
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 101 additions and 52 deletions

View File

@ -192,6 +192,9 @@ def create_defs():
defs['wrap_toolbar_text'] = False defs['wrap_toolbar_text'] = False
defs['dnd_merge'] = True defs['dnd_merge'] = True
defs['booklist_grid'] = False defs['booklist_grid'] = False
defs['browse_annots_restrict_to_user'] = None
defs['browse_annots_restrict_to_type'] = None
defs['browse_annots_use_stemmer'] = True
create_defs() create_defs()

View File

@ -5,13 +5,15 @@
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
import os import os
from textwrap import fill
from PyQt5.Qt import ( from PyQt5.Qt import (
QApplication, QComboBox, QCursor, QFont, QHBoxLayout, QIcon, QLabel, QSize, QApplication, QCheckBox, QComboBox, QCursor, QFont, QHBoxLayout, QIcon, QLabel,
QSplitter, Qt, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget QSize, QSplitter, Qt, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget, pyqtSignal
) )
from calibre.gui2 import Application from calibre.gui2 import Application, gprefs
from calibre.gui2.viewer.search import ResultsDelegate, SearchBox from calibre.gui2.viewer.search import ResultsDelegate, SearchBox
from calibre.gui2.widgets2 import Dialog from calibre.gui2.widgets2 import Dialog
@ -32,6 +34,8 @@ class BusyCursor(object):
class AnnotsResultsDelegate(ResultsDelegate): class AnnotsResultsDelegate(ResultsDelegate):
add_ellipsis = False
def result_data(self, result): def result_data(self, result):
if not isinstance(result, dict): if not isinstance(result, dict):
return None, None, None, None return None, None, None, None
@ -79,10 +83,78 @@ class ResultsList(QTreeWidget):
item.setData(0, Qt.UserRole, result) item.setData(0, Qt.UserRole, result)
class Restrictions(QWidget):
restrictions_changed = pyqtSignal()
def __init__(self, parent):
QWidget.__init__(self, parent)
h = QHBoxLayout(self)
h.setContentsMargins(0, 0, 0, 0)
h.addWidget(QLabel(_('Restrict to') + ': '))
la = QLabel(_('Types:'))
h.addWidget(la)
self.types_box = tb = QComboBox(self)
tb.la = la
tb.currentIndexChanged.connect(self.restrictions_changed)
connect_lambda(tb.currentIndexChanged, tb, lambda tb: gprefs.set('browse_annots_restrict_to_type', tb.currentData()))
la.setBuddy(tb)
tb.setToolTip(_('Show only annotations of the specified type'))
h.addWidget(tb)
la = QLabel(_('User:'))
h.addWidget(la)
self.user_box = ub = QComboBox(self)
ub.la = la
ub.currentIndexChanged.connect(self.restrictions_changed)
connect_lambda(ub.currentIndexChanged, ub, lambda ub: gprefs.set('browse_annots_restrict_to_user', ub.currentData()))
la.setBuddy(ub)
ub.setToolTip(_('Show only annotations created by the specified user'))
h.addWidget(ub)
h.addStretch(10)
def re_initialize(self, db):
tb = self.types_box
before = tb.currentData()
if not before:
before = gprefs['browse_annots_restrict_to_type']
tb.blockSignals(True)
tb.clear()
tb.addItem(' ', ' ')
for atype in db.all_annotation_types():
name = {'bookmark': _('Bookmarks'), 'highlight': _('Highlights')}.get(atype, atype)
tb.addItem(name, atype)
if before:
row = tb.findData(before)
if row > -1:
tb.setCurrentIndex(row)
tb.blockSignals(False)
tb_is_visible = tb.count() > 2
tb.setVisible(tb_is_visible), tb.la.setVisible(tb_is_visible)
tb = self.user_box
before = tb.currentData()
if not before:
before = gprefs['browse_annots_restrict_to_user']
tb.blockSignals(True)
tb.clear()
tb.addItem(' ', ' ')
for user_type, user in db.all_annotation_users():
q = '{}: {}'.format(user_type, user)
tb.addItem(q, '{}:{}'.format(user_type, user))
if before:
row = tb.findData(before)
if row > -1:
tb.setCurrentIndex(row)
tb.blockSignals(False)
ub_is_visible = tb.count() > 2
tb.setVisible(ub_is_visible), tb.la.setVisible(ub_is_visible)
self.setVisible(tb_is_visible or ub_is_visible)
class BrowsePanel(QWidget): class BrowsePanel(QWidget):
def __init__(self, parent): def __init__(self, parent):
QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.use_stemmer = parent.use_stemmer
self.current_query = None self.current_query = None
l = QVBoxLayout(self) l = QVBoxLayout(self)
@ -109,22 +181,10 @@ class BrowsePanel(QWidget):
nb.clicked.connect(self.show_previous) nb.clicked.connect(self.show_previous)
nb.setToolTip(_('Find previous match')) nb.setToolTip(_('Find previous match'))
h = QHBoxLayout() self.restrictions = rs = Restrictions(self)
l.addLayout(h) rs.restrictions_changed.connect(self.effective_query_changed)
h.addWidget(QLabel(_('Restrict to') + ' ')) self.use_stemmer.stateChanged.connect(self.effective_query_changed)
la = QLabel(_('Types:')) l.addWidget(rs)
h.addWidget(la)
self.types_box = tb = QComboBox(self)
tb.currentIndexChanged.connect(self.effective_query_changed)
la.setBuddy(tb)
h.addWidget(tb)
la = QLabel(_('User:'))
h.addWidget(la)
self.user_box = ub = QComboBox(self)
ub.currentIndexChanged.connect(self.effective_query_changed)
la.setBuddy(ub)
h.addWidget(ub)
h.addStretch(10)
self.results_list = rl = ResultsList(self) self.results_list = rl = ResultsList(self)
l.addWidget(rl) l.addWidget(rl)
@ -132,32 +192,7 @@ class BrowsePanel(QWidget):
def re_initialize(self): def re_initialize(self):
db = current_db() db = current_db()
self.search_box.setFocus(Qt.OtherFocusReason) self.search_box.setFocus(Qt.OtherFocusReason)
tb = self.types_box self.restrictions.re_initialize(db)
before = tb.currentData()
tb.blockSignals(True)
tb.clear()
tb.addItem(' ', ' ')
for atype in db.all_annotation_types():
name = {'bookmark': _('Bookmarks'), 'highlight': _('Highlights')}.get(atype, atype)
tb.addItem(name, atype)
if before:
row = tb.findData(before)
if row > -1:
tb.setCurrentIndex(row)
tb.blockSignals(False)
tb = self.user_box
before = tb.currentData()
tb.blockSignals(True)
tb.clear()
tb.addItem(' ', ' ')
for user_type, user in db.all_annotation_users():
q = '{}: {}'.format(user_type, user)
tb.addItem(q, '{}:{}'.format(user_type, user))
if before:
row = tb.findData(before)
if row > -1:
tb.setCurrentIndex(row)
tb.blockSignals(False)
def sizeHint(self): def sizeHint(self):
return QSize(450, 600) return QSize(450, 600)
@ -167,17 +202,18 @@ class BrowsePanel(QWidget):
text = self.search_box.lineEdit().text().strip() text = self.search_box.lineEdit().text().strip()
if not text: if not text:
return None return None
atype = self.types_box.currentData() atype = self.restrictions.types_box.currentData()
if not atype or not atype.strip(): if not atype or not atype.strip():
atype = None atype = None
user = self.user_box.currentData() user = self.restrictions.user_box.currentData()
restrict_to_user = None restrict_to_user = None
if user and ':' in user: if user and ':' in user:
restrict_to_user = user.split(':', 1) restrict_to_user = user.split(':', 1)
return { return {
'fts_engine_query': text, 'fts_engine_query': text,
'annotation_type': atype, 'annotation_type': atype,
'restrict_to_user': restrict_to_user 'restrict_to_user': restrict_to_user,
'use_stemming': bool(self.use_stemmer.isChecked()),
} }
def cleared(self): def cleared(self):
@ -227,6 +263,13 @@ class AnnotationsBrowser(Dialog):
return Dialog.keyPressEvent(self, ev) return Dialog.keyPressEvent(self, ev)
def setup_ui(self): def setup_ui(self):
self.use_stemmer = us = QCheckBox(_('Match on related English words'))
us.setChecked(gprefs['browse_annots_use_stemmer'])
us.setToolTip(fill(_(
'With this option searching for words will also match on any related English words. For'
' example: correction matches correcting and corrected as well')))
us.stateChanged.connect(lambda state: gprefs.set('browse_annots_use_stemmer', state != Qt.Unchecked))
l = QVBoxLayout(self) l = QVBoxLayout(self)
self.splitter = s = QSplitter(self) self.splitter = s = QSplitter(self)
@ -239,8 +282,9 @@ class AnnotationsBrowser(Dialog):
self.details_panel = dp = DetailsPanel(self) self.details_panel = dp = DetailsPanel(self)
s.addWidget(dp) s.addWidget(dp)
self.bb.setStandardButtons(self.bb.Close) h = QHBoxLayout()
l.addWidget(self.bb) l.addLayout(h)
h.addWidget(us), h.addStretch(10), h.addWidget(self.bb)
def show_dialog(self): def show_dialog(self):
self.browse_panel.re_initialize() self.browse_panel.re_initialize()

View File

@ -449,6 +449,8 @@ class SearchInput(QWidget): # {{{
class ResultsDelegate(QStyledItemDelegate): # {{{ class ResultsDelegate(QStyledItemDelegate): # {{{
add_ellipsis = True
def result_data(self, result): def result_data(self, result):
if not isinstance(result, SearchResult): if not isinstance(result, SearchResult):
return None, None, None, None return None, None, None, None
@ -512,7 +514,7 @@ class ResultsDelegate(QStyledItemDelegate): # {{{
r.setRight(x + left_width) r.setRight(x + left_width)
painter.setFont(normal_font) painter.setFont(normal_font)
ebefore = nfm.elidedText(before, Qt.ElideLeft, left_width) ebefore = nfm.elidedText(before, Qt.ElideLeft, left_width)
if ebefore == before: if self.add_ellipsis and ebefore == before:
ebefore = '' + before[1:] ebefore = '' + before[1:]
r.setLeft(x) r.setLeft(x)
x += painter.drawText(r, flags, ebefore).width() x += painter.drawText(r, flags, ebefore).width()
@ -526,7 +528,7 @@ class ResultsDelegate(QStyledItemDelegate): # {{{
r = rect.adjusted(0, 0, 0, 0) r = rect.adjusted(0, 0, 0, 0)
r.setLeft(x) r.setLeft(x)
eafter = nfm.elidedText(after, Qt.ElideRight, right_width) eafter = nfm.elidedText(after, Qt.ElideRight, right_width)
if eafter == after: if self.add_ellipsis and eafter == after:
eafter = after[:-1] + '' eafter = after[:-1] + ''
painter.setFont(normal_font) painter.setFont(normal_font)
painter.drawText(r, flags, eafter) painter.drawText(r, flags, eafter)