mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Implement query params for annotation browser
This commit is contained in:
parent
f53ecbf7ba
commit
2c530d7c78
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user