mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Full text search window: Add actions to the context menu to open the book at the clicked on result. Also allow using the view book shortcut to open the currently selected search result. Fixes #2052462 [[Enhancement] Press V to view book in the Full text search dialog](https://bugs.launchpad.net/calibre/+bug/2052462)
This commit is contained in:
parent
f179b8c9b9
commit
2132e31339
@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from qt.core import (
|
from qt.core import (
|
||||||
QDialogButtonBox, QHBoxLayout, QIcon, QLabel, QSize, QStackedWidget, QVBoxLayout, Qt
|
QAction, QDialogButtonBox, QHBoxLayout, QIcon, QLabel, QSize, QStackedWidget, Qt,
|
||||||
|
QVBoxLayout,
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre.gui2 import warning_dialog
|
from calibre.gui2 import error_dialog, warning_dialog
|
||||||
from calibre.gui2.fts.scan import ScanStatus
|
from calibre.gui2.fts.scan import ScanStatus
|
||||||
from calibre.gui2.fts.search import ResultsPanel
|
from calibre.gui2.fts.search import ResultsPanel
|
||||||
from calibre.gui2.fts.utils import get_db
|
from calibre.gui2.fts.utils import get_db
|
||||||
|
from calibre.gui2.ui import get_gui
|
||||||
from calibre.gui2.widgets2 import Dialog
|
from calibre.gui2.widgets2 import Dialog
|
||||||
|
|
||||||
|
|
||||||
@ -21,6 +23,16 @@ class FTSDialog(Dialog):
|
|||||||
default_buttons=QDialogButtonBox.StandardButton.Close)
|
default_buttons=QDialogButtonBox.StandardButton.Close)
|
||||||
self.setWindowIcon(QIcon.ic('fts.png'))
|
self.setWindowIcon(QIcon.ic('fts.png'))
|
||||||
self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowMinMaxButtonsHint)
|
self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowMinMaxButtonsHint)
|
||||||
|
self.view_action = ac = QAction(self)
|
||||||
|
ac.triggered.connect(self.view_current_book)
|
||||||
|
gui = get_gui()
|
||||||
|
if gui is not None:
|
||||||
|
ac.setShortcuts(gui.iactions['View'].menuless_qaction.shortcuts())
|
||||||
|
self.addAction(ac)
|
||||||
|
|
||||||
|
def view_current_book(self):
|
||||||
|
if not self.results_panel.view_current_result():
|
||||||
|
error_dialog(self, _('No result selected'), _('Cannot view book as no result is selected'), show=True)
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
l = QVBoxLayout(self)
|
l = QVBoxLayout(self)
|
||||||
|
@ -57,6 +57,31 @@ def jump_to_book(book_id, parent=None):
|
|||||||
' only search currently visible books.'), show=True)
|
' only search currently visible books.'), show=True)
|
||||||
|
|
||||||
|
|
||||||
|
def show_in_viewer(book_id, text, fmt):
|
||||||
|
text = text.strip('…').replace('\x1d', '').replace('\xa0', ' ')
|
||||||
|
text = sanitize_text_pat.sub(' ', text)
|
||||||
|
gui = get_gui()
|
||||||
|
if gui is not None:
|
||||||
|
if fmt in config['internally_viewed_formats']:
|
||||||
|
gui.iactions['View'].view_format_by_id(book_id, fmt, open_at=f'search:{text}')
|
||||||
|
else:
|
||||||
|
gui.iactions['View'].view_format_by_id(book_id, fmt)
|
||||||
|
|
||||||
|
|
||||||
|
def open_book(results, match_index=None):
|
||||||
|
gui = get_gui()
|
||||||
|
if gui is None:
|
||||||
|
return
|
||||||
|
book_id = results.book_id
|
||||||
|
if match_index is None:
|
||||||
|
gui.iactions['View'].view_historical(book_id)
|
||||||
|
return
|
||||||
|
result_dict = results.result_dicts[match_index]
|
||||||
|
formats = results.formats[match_index]
|
||||||
|
from calibre.gui2.actions.view import preferred_format
|
||||||
|
show_in_viewer(book_id, result_dict['text'], preferred_format(formats))
|
||||||
|
|
||||||
|
|
||||||
class SearchDelegate(ResultsDelegate):
|
class SearchDelegate(ResultsDelegate):
|
||||||
|
|
||||||
def result_data(self, result):
|
def result_data(self, result):
|
||||||
@ -429,11 +454,27 @@ class ResultsView(QTreeView):
|
|||||||
if results:
|
if results:
|
||||||
m.addAction(QIcon.ic('lt.png'), _('Jump to this book in the library'), partial(jump_to_book, results.book_id, self))
|
m.addAction(QIcon.ic('lt.png'), _('Jump to this book in the library'), partial(jump_to_book, results.book_id, self))
|
||||||
m.addAction(QIcon.ic('marked.png'), _('Mark this book in the library'), partial(mark_books, results.book_id))
|
m.addAction(QIcon.ic('marked.png'), _('Mark this book in the library'), partial(mark_books, results.book_id))
|
||||||
|
if match is not None:
|
||||||
|
match = index.row()
|
||||||
|
m.addAction(QIcon.ic('view.png'), _('Open this book at this search result'), partial(open_book, results, match_index=match))
|
||||||
|
else:
|
||||||
|
m.addAction(QIcon.ic('view.png'), _('Open this book'), partial(open_book, results))
|
||||||
m.addSeparator()
|
m.addSeparator()
|
||||||
m.addAction(QIcon.ic('plus.png'), _('Expand all'), self.expandAll)
|
m.addAction(QIcon.ic('plus.png'), _('Expand all'), self.expandAll)
|
||||||
m.addAction(QIcon.ic('minus.png'), _('Collapse all'), self.collapseAll)
|
m.addAction(QIcon.ic('minus.png'), _('Collapse all'), self.collapseAll)
|
||||||
m.exec(self.mapToGlobal(pos))
|
m.exec(self.mapToGlobal(pos))
|
||||||
|
|
||||||
|
def view_current_result(self):
|
||||||
|
idx = self.currentIndex()
|
||||||
|
if idx.isValid():
|
||||||
|
results, match = self.m.data_for_index(idx)
|
||||||
|
if results:
|
||||||
|
if match is not None:
|
||||||
|
match = idx.row()
|
||||||
|
open_book(results, match)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Spinner(ProgressIndicator):
|
class Spinner(ProgressIndicator):
|
||||||
|
|
||||||
@ -813,6 +854,9 @@ class ResultsPanel(QWidget):
|
|||||||
if st is not None:
|
if st is not None:
|
||||||
s.restoreState(st)
|
s.restoreState(st)
|
||||||
|
|
||||||
|
def view_current_result(self):
|
||||||
|
return self.results_view.view_current_result()
|
||||||
|
|
||||||
def clear_history(self):
|
def clear_history(self):
|
||||||
self.sip.clear_history()
|
self.sip.clear_history()
|
||||||
|
|
||||||
@ -824,14 +868,7 @@ class ResultsPanel(QWidget):
|
|||||||
|
|
||||||
def show_in_viewer(self, book_id, result_num, fmt):
|
def show_in_viewer(self, book_id, result_num, fmt):
|
||||||
r = self.results_view.m.get_result(book_id, result_num)
|
r = self.results_view.m.get_result(book_id, result_num)
|
||||||
text = r['text'].strip('…').replace('\x1d', '').replace('\xa0', ' ')
|
show_in_viewer(book_id, r['text'], fmt)
|
||||||
text = sanitize_text_pat.sub(' ', text)
|
|
||||||
gui = get_gui()
|
|
||||||
if gui is not None:
|
|
||||||
if fmt in config['internally_viewed_formats']:
|
|
||||||
gui.iactions['View'].view_format_by_id(book_id, fmt, open_at=f'search:{text}')
|
|
||||||
else:
|
|
||||||
gui.iactions['View'].view_format_by_id(book_id, fmt)
|
|
||||||
|
|
||||||
def request_stop_search(self):
|
def request_stop_search(self):
|
||||||
if question_dialog(self, _('Are you sure?'), _('Abort the current search?')):
|
if question_dialog(self, _('Are you sure?'), _('Abort the current search?')):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user