mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Save mode and case sensitivity for searches
This commit is contained in:
parent
0b4ae4a23c
commit
61a90e70e7
@ -11,14 +11,14 @@ from threading import Thread
|
|||||||
|
|
||||||
import regex
|
import regex
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QCheckBox, QComboBox, QHBoxLayout, QIcon, Qt, QToolButton, QVBoxLayout, QWidget,
|
QCheckBox, QComboBox, QHBoxLayout, QIcon, QListWidget, Qt, QToolButton,
|
||||||
pyqtSignal
|
QVBoxLayout, QWidget, pyqtSignal
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre.ebooks.conversion.search_replace import REGEX_FLAGS
|
from calibre.ebooks.conversion.search_replace import REGEX_FLAGS
|
||||||
from calibre.gui2.viewer.web_view import get_data, get_manifest, vprefs
|
from calibre.gui2.viewer.web_view import get_data, get_manifest, vprefs
|
||||||
from calibre.gui2.widgets2 import HistoryComboBox
|
from calibre.gui2.widgets2 import HistoryComboBox
|
||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type, iteritems
|
||||||
from polyglot.functools import lru_cache
|
from polyglot.functools import lru_cache
|
||||||
from polyglot.queue import Queue
|
from polyglot.queue import Queue
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ class SearchResult(object):
|
|||||||
self.file_name = name
|
self.file_name = name
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1024)
|
@lru_cache(maxsize=None)
|
||||||
def searchable_text_for_name(name):
|
def searchable_text_for_name(name):
|
||||||
ans = []
|
ans = []
|
||||||
serialized_data = json.loads(get_data(name)[0])
|
serialized_data = json.loads(get_data(name)[0])
|
||||||
@ -72,7 +72,7 @@ def searchable_text_for_name(name):
|
|||||||
for child in serialized_data['tree']['c']:
|
for child in serialized_data['tree']['c']:
|
||||||
if child.get('n') == 'body':
|
if child.get('n') == 'body':
|
||||||
stack.append(child)
|
stack.append(child)
|
||||||
ignore_text = {'script':True, 'style':True, 'title': True}
|
ignore_text = {'script':True, 'style':True, 'title':True}
|
||||||
while stack:
|
while stack:
|
||||||
node = stack.pop()
|
node = stack.pop()
|
||||||
if isinstance(node, unicode_type):
|
if isinstance(node, unicode_type):
|
||||||
@ -101,6 +101,16 @@ def search_in_name(name, search_query, ctx_size=50):
|
|||||||
yield before, match.group(), after
|
yield before, match.group(), after
|
||||||
|
|
||||||
|
|
||||||
|
class SearchBox(HistoryComboBox):
|
||||||
|
|
||||||
|
history_saved = pyqtSignal(object, object)
|
||||||
|
|
||||||
|
def save_history(self):
|
||||||
|
ret = HistoryComboBox.save_history(self)
|
||||||
|
self.history_saved.emit(self.text(), self.history)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class SearchInput(QWidget):
|
class SearchInput(QWidget):
|
||||||
|
|
||||||
do_search = pyqtSignal(object)
|
do_search = pyqtSignal(object)
|
||||||
@ -113,11 +123,13 @@ class SearchInput(QWidget):
|
|||||||
h.setContentsMargins(0, 0, 0, 0)
|
h.setContentsMargins(0, 0, 0, 0)
|
||||||
l.addLayout(h)
|
l.addLayout(h)
|
||||||
|
|
||||||
self.search_box = sb = HistoryComboBox(self)
|
self.search_box = sb = SearchBox(self)
|
||||||
|
sb.initialize('viewer-search-panel-expression')
|
||||||
|
sb.item_selected.connect(self.saved_search_selected)
|
||||||
|
sb.history_saved.connect(self.history_saved)
|
||||||
sb.lineEdit().setPlaceholderText(_('Search'))
|
sb.lineEdit().setPlaceholderText(_('Search'))
|
||||||
sb.lineEdit().setClearButtonEnabled(True)
|
sb.lineEdit().setClearButtonEnabled(True)
|
||||||
sb.lineEdit().returnPressed.connect(self.find_next)
|
sb.lineEdit().returnPressed.connect(self.find_next)
|
||||||
sb.initialize('viewer-search-box-history')
|
|
||||||
h.addWidget(sb)
|
h.addWidget(sb)
|
||||||
|
|
||||||
self.next_button = nb = QToolButton(self)
|
self.next_button = nb = QToolButton(self)
|
||||||
@ -152,10 +164,31 @@ class SearchInput(QWidget):
|
|||||||
cs.setChecked(bool(vprefs.get('viewer-search-case-sensitive', False)))
|
cs.setChecked(bool(vprefs.get('viewer-search-case-sensitive', False)))
|
||||||
h.addWidget(cs)
|
h.addWidget(cs)
|
||||||
|
|
||||||
|
def history_saved(self, new_text, history):
|
||||||
|
sss = vprefs.get('saved-search-settings') or {}
|
||||||
|
sss[new_text] = {'case_sensitive': self.case_sensitive.isChecked(), 'mode': self.query_type.currentData()}
|
||||||
|
history = frozenset(history)
|
||||||
|
sss = {k: v for k, v in iteritems(sss) if k in history}
|
||||||
|
vprefs['saved-search-settings'] = sss
|
||||||
|
|
||||||
|
def saved_search_selected(self):
|
||||||
|
text = self.search_box.currentText().strip()
|
||||||
|
s = (vprefs.get('saved-search-settings') or {}).get(text)
|
||||||
|
if s:
|
||||||
|
if 'case_sensitive' in s:
|
||||||
|
self.case_sensitive.setChecked(s['case_sensitive'])
|
||||||
|
if 'mode' in s:
|
||||||
|
idx = self.query_type.findData(s['mode'])
|
||||||
|
if idx > -1:
|
||||||
|
self.query_type.setCurrentIndex(idx)
|
||||||
|
|
||||||
def search_query(self, backwards=False):
|
def search_query(self, backwards=False):
|
||||||
text = self.search_box.currentText().strip()
|
text = self.search_box.currentText().strip()
|
||||||
if text:
|
if text:
|
||||||
return Search(text, self.query_type.currentData() or 'normal', self.case_sensitive.isChecked(), backwards)
|
return Search(
|
||||||
|
text, self.query_type.currentData() or 'normal',
|
||||||
|
self.case_sensitive.isChecked(), backwards
|
||||||
|
)
|
||||||
|
|
||||||
def emit_search(self, backwards=False):
|
def emit_search(self, backwards=False):
|
||||||
vprefs['viewer-search-case-sensitive'] = self.case_sensitive.isChecked()
|
vprefs['viewer-search-case-sensitive'] = self.case_sensitive.isChecked()
|
||||||
@ -177,6 +210,12 @@ class SearchInput(QWidget):
|
|||||||
le.selectAll()
|
le.selectAll()
|
||||||
|
|
||||||
|
|
||||||
|
class Results(QListWidget):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QListWidget.__init__(self, parent)
|
||||||
|
|
||||||
|
|
||||||
class SearchPanel(QWidget):
|
class SearchPanel(QWidget):
|
||||||
|
|
||||||
search_requested = pyqtSignal(object)
|
search_requested = pyqtSignal(object)
|
||||||
@ -192,6 +231,9 @@ class SearchPanel(QWidget):
|
|||||||
self.results_found.connect(self.on_result_found, type=Qt.QueuedConnection)
|
self.results_found.connect(self.on_result_found, type=Qt.QueuedConnection)
|
||||||
si.do_search.connect(self.search_requested)
|
si.do_search.connect(self.search_requested)
|
||||||
l.addWidget(si)
|
l.addWidget(si)
|
||||||
|
self.results = r = Results(self)
|
||||||
|
l.addWidget(r)
|
||||||
|
|
||||||
l.addStretch(10)
|
l.addStretch(10)
|
||||||
|
|
||||||
def focus_input(self):
|
def focus_input(self):
|
||||||
|
@ -249,7 +249,7 @@ class EbookViewer(MainWindow):
|
|||||||
self.search_widget.focus_input()
|
self.search_widget.focus_input()
|
||||||
|
|
||||||
def start_search(self, search_query):
|
def start_search(self, search_query):
|
||||||
name = self.web_view.current_name
|
name = self.web_view.current_content_file
|
||||||
if name:
|
if name:
|
||||||
self.search_widget.start_search(search_query, name)
|
self.search_widget.start_search(search_query, name)
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
self._page = WebPage(self)
|
self._page = WebPage(self)
|
||||||
self.bridge.bridge_ready.connect(self.on_bridge_ready)
|
self.bridge.bridge_ready.connect(self.on_bridge_ready)
|
||||||
self.bridge.view_created.connect(self.on_view_created)
|
self.bridge.view_created.connect(self.on_view_created)
|
||||||
self.bridge.content_file_changed.connect(self.on_content_file_created)
|
self.bridge.content_file_changed.connect(self.on_content_file_changed)
|
||||||
self.bridge.set_session_data.connect(self.set_session_data)
|
self.bridge.set_session_data.connect(self.set_session_data)
|
||||||
self.bridge.set_local_storage.connect(self.set_local_storage)
|
self.bridge.set_local_storage.connect(self.set_local_storage)
|
||||||
self.bridge.reload_book.connect(self.reload_book)
|
self.bridge.reload_book.connect(self.reload_book)
|
||||||
@ -566,7 +566,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
def on_view_created(self, data):
|
def on_view_created(self, data):
|
||||||
self.view_created.emit(data)
|
self.view_created.emit(data)
|
||||||
|
|
||||||
def on_content_file_created(self, data):
|
def on_content_file_changed(self, data):
|
||||||
self.current_content_file = data
|
self.current_content_file = data
|
||||||
|
|
||||||
def start_book_load(self, initial_position=None):
|
def start_book_load(self, initial_position=None):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user