mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Annots browser: Allow browsing upto 4096 annotations with no search query
This commit is contained in:
parent
1f3b5993b7
commit
21f3348ab7
@ -1820,12 +1820,49 @@ class DB(object):
|
||||
raise FTSQueryError(fts_engine_query, query, e)
|
||||
|
||||
def all_annotations_for_book(self, book_id):
|
||||
for (fmt, user_type, user, data) in self.execute('SELECT format, user_type, user, annot_data FROM annotations WHERE book=?', (book_id,)):
|
||||
for (fmt, user_type, user, data) in self.execute('SELECT id, book, format, user_type, user, annot_data FROM annotations WHERE book=?', (book_id,)):
|
||||
|
||||
try:
|
||||
yield {'format': fmt, 'user_type': user_type, 'user': user, 'annotation': json.loads(data)}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def all_annotations(self, restrict_to_user=None, limit=None, annotation_type=None):
|
||||
ls = json.loads
|
||||
q = 'SELECT id, book, format, user_type, user, annot_data FROM annotations'
|
||||
data = []
|
||||
if restrict_to_user or annotation_type:
|
||||
q += ' WHERE '
|
||||
if restrict_to_user is not None:
|
||||
data.extend(restrict_to_user)
|
||||
q += ' user_type = ? AND user = ?'
|
||||
if annotation_type:
|
||||
data.append(annotation_type)
|
||||
q += ' annot_type = ? '
|
||||
q += ' ORDER BY timestamp'
|
||||
if limit is not None:
|
||||
q += ' LIMIT %d' % limit
|
||||
for (rowid, book_id, fmt, user_type, user, annot_data) in self.execute(q, tuple(data)):
|
||||
try:
|
||||
annot = ls(annot_data)
|
||||
atype = annot['type']
|
||||
except Exception:
|
||||
continue
|
||||
text = ''
|
||||
if atype == 'bookmark':
|
||||
text = annot['title']
|
||||
elif atype == 'highlight':
|
||||
text = annot.get('highlighted_text') or ''
|
||||
yield {
|
||||
'id': rowid,
|
||||
'book_id': book_id,
|
||||
'format': fmt,
|
||||
'user_type': user_type,
|
||||
'user': user,
|
||||
'text': text,
|
||||
'annotation': annot,
|
||||
}
|
||||
|
||||
def all_annotation_users(self):
|
||||
return self.execute('SELECT DISTINCT user_type, user FROM annotations')
|
||||
|
||||
|
@ -2310,6 +2310,10 @@ class Cache(object):
|
||||
def all_annotation_types(self):
|
||||
return tuple(self.backend.all_annotation_types())
|
||||
|
||||
@read_api
|
||||
def all_annotations(self, restrict_to_user=None, limit=None, annotation_type=None):
|
||||
return tuple(self.backend.all_annotations(restrict_to_user, limit, annotation_type))
|
||||
|
||||
@read_api
|
||||
def search_annotations(
|
||||
self,
|
||||
|
@ -9,7 +9,7 @@ from textwrap import fill
|
||||
|
||||
from PyQt5.Qt import (
|
||||
QApplication, QCheckBox, QComboBox, QCursor, QFont, QHBoxLayout, QIcon, QLabel,
|
||||
QPalette, QPushButton, QSize, QSplitter, Qt, QTextBrowser, QToolButton,
|
||||
QPalette, QPushButton, QSize, QSplitter, Qt, QTextBrowser, QTimer, QToolButton,
|
||||
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget, pyqtSignal
|
||||
)
|
||||
|
||||
@ -43,16 +43,17 @@ class BusyCursor(object):
|
||||
class AnnotsResultsDelegate(ResultsDelegate):
|
||||
|
||||
add_ellipsis = False
|
||||
emphasize_text = True
|
||||
|
||||
def result_data(self, result):
|
||||
if not isinstance(result, dict):
|
||||
return None, None, None, None
|
||||
full_text = result['text'].replace('0x1f', ' ')
|
||||
parts = full_text.split('\x1d')
|
||||
full_text = result['text'].replace('\x1f', ' ')
|
||||
parts = full_text.split('\x1d', 2)
|
||||
before = after = ''
|
||||
if len(parts) > 2:
|
||||
before, text = parts[:2]
|
||||
after = ' '.join(parts[2:]).replace('\x1d', '')
|
||||
after = parts[2].replace('\x1d', '')
|
||||
elif len(parts) == 2:
|
||||
before, text = parts
|
||||
else:
|
||||
@ -82,8 +83,9 @@ class ResultsList(QTreeWidget):
|
||||
if isinstance(r, dict):
|
||||
self.open_annotation.emit(r['book_id'], r['format'], r['annotation'])
|
||||
|
||||
def set_results(self, results):
|
||||
def set_results(self, results, emphasize_text):
|
||||
self.clear()
|
||||
self.delegate.emphasize_text = emphasize_text
|
||||
self.number_of_results = 0
|
||||
self.item_map = []
|
||||
book_id_map = {}
|
||||
@ -191,8 +193,12 @@ class Restrictions(QWidget):
|
||||
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))
|
||||
q = display_name = '{}: {}'.format(user_type, user)
|
||||
if q == 'web: *':
|
||||
display_name = _('Anonymous content server users')
|
||||
elif q == 'local: viewer':
|
||||
display_name = _('Local viewer users')
|
||||
tb.addItem(display_name, '{}:{}'.format(user_type, user))
|
||||
if before:
|
||||
row = tb.findData(before)
|
||||
if row > -1:
|
||||
@ -218,7 +224,7 @@ class BrowsePanel(QWidget):
|
||||
l.addLayout(h)
|
||||
self.search_box = sb = SearchBox(self)
|
||||
sb.initialize('library-annotations-browser-search-box')
|
||||
sb.cleared.connect(self.cleared)
|
||||
sb.cleared.connect(self.cleared, type=Qt.QueuedConnection)
|
||||
sb.lineEdit().returnPressed.connect(self.show_next)
|
||||
sb.lineEdit().setPlaceholderText(_('Enter words to search for'))
|
||||
h.addWidget(sb)
|
||||
@ -251,45 +257,46 @@ class BrowsePanel(QWidget):
|
||||
db = current_db()
|
||||
self.search_box.setFocus(Qt.OtherFocusReason)
|
||||
self.restrictions.re_initialize(db)
|
||||
self.cleared()
|
||||
self.current_query = None
|
||||
self.results_list.clear()
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(450, 600)
|
||||
|
||||
@property
|
||||
def restrict_to_user(self):
|
||||
user = self.restrictions.user_box.currentData()
|
||||
if user and ':' in user:
|
||||
return user.split(':', 1)
|
||||
|
||||
@property
|
||||
def effective_query(self):
|
||||
text = self.search_box.lineEdit().text().strip()
|
||||
if not text:
|
||||
return None
|
||||
atype = self.restrictions.types_box.currentData()
|
||||
if not atype or not atype.strip():
|
||||
atype = None
|
||||
user = self.restrictions.user_box.currentData()
|
||||
restrict_to_user = None
|
||||
if user and ':' in user:
|
||||
restrict_to_user = user.split(':', 1)
|
||||
return {
|
||||
'fts_engine_query': text,
|
||||
'annotation_type': atype,
|
||||
'restrict_to_user': restrict_to_user,
|
||||
'annotation_type': (atype or '').strip(),
|
||||
'restrict_to_user': self.restrict_to_user,
|
||||
'use_stemming': bool(self.use_stemmer.isChecked()),
|
||||
}
|
||||
|
||||
def cleared(self):
|
||||
self.current_query = None
|
||||
self.results_list.clear()
|
||||
self.effective_query_changed()
|
||||
|
||||
def do_find(self, backwards=False):
|
||||
q = self.effective_query
|
||||
if not q:
|
||||
return
|
||||
if q == self.current_query:
|
||||
self.results_list.show_next(backwards)
|
||||
return
|
||||
with BusyCursor():
|
||||
db = current_db()
|
||||
if not q['fts_engine_query']:
|
||||
results = db.all_annotations(restrict_to_user=q['restrict_to_user'], limit=4096, annotation_type=q['annotation_type'])
|
||||
else:
|
||||
results = db.search_annotations(highlight_start='\x1d', highlight_end='\x1d', snippet_size=64, **q)
|
||||
self.results_list.set_results(results)
|
||||
|
||||
self.results_list.set_results(results, bool(q['fts_engine_query']))
|
||||
self.current_query = q
|
||||
|
||||
def effective_query_changed(self):
|
||||
@ -454,6 +461,8 @@ class AnnotationsBrowser(Dialog):
|
||||
h.addWidget(us), h.addStretch(10), h.addWidget(self.bb)
|
||||
|
||||
def show_dialog(self):
|
||||
if self.browse_panel.current_query is None:
|
||||
QTimer.singleShot(80, self.browse_panel.effective_query_changed)
|
||||
if self.parent() is None:
|
||||
self.exec_()
|
||||
else:
|
||||
|
@ -17,6 +17,7 @@ from calibre.gui2.widgets2 import HistoryComboBox
|
||||
class ResultsDelegate(QStyledItemDelegate): # {{{
|
||||
|
||||
add_ellipsis = True
|
||||
emphasize_text = True
|
||||
|
||||
def result_data(self, result):
|
||||
if not hasattr(result, 'is_hidden'):
|
||||
@ -37,8 +38,11 @@ class ResultsDelegate(QStyledItemDelegate): # {{{
|
||||
c = p.color(group, c)
|
||||
painter.setPen(c)
|
||||
font = option.font
|
||||
if self.emphasize_text:
|
||||
emphasis_font = QFont(font)
|
||||
emphasis_font.setBold(True)
|
||||
else:
|
||||
emphasis_font = font
|
||||
flags = Qt.AlignTop | Qt.TextSingleLine | Qt.TextIncludeTrailingSpaces
|
||||
rect = option.rect.adjusted(option.decorationSize.width() + 4 if is_hidden else 0, 0, 0, 0)
|
||||
painter.setClipRect(rect)
|
||||
|
Loading…
x
Reference in New Issue
Block a user