mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Rather than remove matches for hidden text, simply mark them as not visible
This commit is contained in:
parent
ae109d8f91
commit
6c29207c87
@ -10,9 +10,9 @@ from threading import Thread
|
|||||||
|
|
||||||
import regex
|
import regex
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QCheckBox, QComboBox, QHBoxLayout, QIcon, QLabel, QListWidget, QListWidgetItem,
|
QCheckBox, QComboBox, QHBoxLayout, QIcon, QLabel, QListWidget,
|
||||||
QStaticText, QStyle, QStyledItemDelegate, Qt, QToolButton, QVBoxLayout, QWidget,
|
QListWidgetItem, QStaticText, QStyle, QStyledItemDelegate, Qt, QToolButton,
|
||||||
pyqtSignal
|
QVBoxLayout, QWidget, pyqtSignal
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre.ebooks.conversion.search_replace import REGEX_FLAGS
|
from calibre.ebooks.conversion.search_replace import REGEX_FLAGS
|
||||||
@ -20,7 +20,6 @@ from calibre.gui2 import warning_dialog
|
|||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
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 calibre.utils.monotonic import monotonic
|
|
||||||
from polyglot.builtins import iteritems, unicode_type
|
from polyglot.builtins import iteritems, unicode_type
|
||||||
from polyglot.functools import lru_cache
|
from polyglot.functools import lru_cache
|
||||||
from polyglot.queue import Queue
|
from polyglot.queue import Queue
|
||||||
@ -116,7 +115,7 @@ class SearchFinished(object):
|
|||||||
|
|
||||||
class SearchResult(object):
|
class SearchResult(object):
|
||||||
|
|
||||||
__slots__ = ('search_query', 'before', 'text', 'after', 'q', 'spine_idx', 'index', 'file_name', '_static_text')
|
__slots__ = ('search_query', 'before', 'text', 'after', 'q', 'spine_idx', 'index', 'file_name', '_static_text', 'is_hidden')
|
||||||
|
|
||||||
def __init__(self, search_query, before, text, after, q, name, spine_idx, index):
|
def __init__(self, search_query, before, text, after, q, name, spine_idx, index):
|
||||||
self.search_query = search_query
|
self.search_query = search_query
|
||||||
@ -125,6 +124,7 @@ class SearchResult(object):
|
|||||||
self.spine_idx, self.index = spine_idx, index
|
self.spine_idx, self.index = spine_idx, index
|
||||||
self.file_name = name
|
self.file_name = name
|
||||||
self._static_text = None
|
self._static_text = None
|
||||||
|
self.is_hidden = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def static_text(self):
|
def static_text(self):
|
||||||
@ -148,11 +148,11 @@ class SearchResult(object):
|
|||||||
def for_js(self):
|
def for_js(self):
|
||||||
return {
|
return {
|
||||||
'file_name': self.file_name, 'spine_idx': self.spine_idx, 'index': self.index, 'text': self.text,
|
'file_name': self.file_name, 'spine_idx': self.spine_idx, 'index': self.index, 'text': self.text,
|
||||||
'before': self.before, 'after': self.after, 'mode': self.search_query.mode
|
'before': self.before, 'after': self.after, 'mode': self.search_query.mode, 'q': self.q
|
||||||
}
|
}
|
||||||
|
|
||||||
def is_result(self, result_from_js):
|
def is_result(self, result_from_js):
|
||||||
return result_from_js['spine_idx'] == self.spine_idx and self.index == result_from_js['index'] and result_from_js['text'] == self.text
|
return result_from_js['spine_idx'] == self.spine_idx and self.index == result_from_js['index'] and result_from_js['q'] == self.q
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
@ -344,8 +344,14 @@ class ResultsDelegate(QStyledItemDelegate): # {{{
|
|||||||
c = p.color(group, c)
|
c = p.color(group, c)
|
||||||
painter.setClipRect(option.rect)
|
painter.setClipRect(option.rect)
|
||||||
painter.setPen(c)
|
painter.setPen(c)
|
||||||
|
height = result.static_text.size().height()
|
||||||
|
tl = option.rect.topLeft()
|
||||||
|
x, y = tl.x(), tl.y()
|
||||||
|
y += (option.rect.height() - height) // 2
|
||||||
|
if result.is_hidden:
|
||||||
|
x += option.decorationSize.width() + 4
|
||||||
try:
|
try:
|
||||||
painter.drawStaticText(option.rect.topLeft(), result.static_text)
|
painter.drawStaticText(x, y, result.static_text)
|
||||||
except Exception:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@ -360,21 +366,23 @@ class Results(QListWidget): # {{{
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QListWidget.__init__(self, parent)
|
QListWidget.__init__(self, parent)
|
||||||
self.setFocusPolicy(Qt.NoFocus)
|
self.setFocusPolicy(Qt.NoFocus)
|
||||||
self.setStyleSheet('QListWidget::item { padding: 3px; }')
|
|
||||||
self.delegate = ResultsDelegate(self)
|
self.delegate = ResultsDelegate(self)
|
||||||
self.setItemDelegate(self.delegate)
|
self.setItemDelegate(self.delegate)
|
||||||
self.itemClicked.connect(self.item_activated)
|
self.itemClicked.connect(self.item_activated)
|
||||||
|
self.blank_icon = QIcon(I('blank.png'))
|
||||||
|
|
||||||
def add_result(self, result):
|
def add_result(self, result):
|
||||||
i = QListWidgetItem(' ', self)
|
i = QListWidgetItem(' ', self)
|
||||||
i.setData(Qt.UserRole, result)
|
i.setData(Qt.UserRole, result)
|
||||||
|
i.setIcon(self.blank_icon)
|
||||||
return self.count()
|
return self.count()
|
||||||
|
|
||||||
def item_activated(self):
|
def item_activated(self):
|
||||||
i = self.currentItem()
|
i = self.currentItem()
|
||||||
if i:
|
if i:
|
||||||
sr = i.data(Qt.UserRole)
|
sr = i.data(Qt.UserRole)
|
||||||
self.show_search_result.emit(sr)
|
if not sr.is_hidden:
|
||||||
|
self.show_search_result.emit(sr)
|
||||||
|
|
||||||
def find_next(self, previous):
|
def find_next(self, previous):
|
||||||
if self.count() < 1:
|
if self.count() < 1:
|
||||||
@ -386,24 +394,14 @@ class Results(QListWidget): # {{{
|
|||||||
self.item_activated()
|
self.item_activated()
|
||||||
|
|
||||||
def search_result_not_found(self, sr):
|
def search_result_not_found(self, sr):
|
||||||
remove = None
|
|
||||||
for i in range(self.count()):
|
for i in range(self.count()):
|
||||||
item = self.item(i)
|
item = self.item(i)
|
||||||
r = item.data(Qt.UserRole)
|
r = item.data(Qt.UserRole)
|
||||||
if r.is_result(sr):
|
if r.is_result(sr):
|
||||||
remove = i
|
r.is_hidden = True
|
||||||
if remove is not None:
|
item.setToolTip(_('This text is hidden in the book, so cannot be displayed'))
|
||||||
q = sr['spine_idx']
|
item.setIcon(QIcon(I('dialog_warning.png')))
|
||||||
for i in range(remove + 1, self.count()):
|
break
|
||||||
item = self.item(i)
|
|
||||||
r = item.data(Qt.UserRole)
|
|
||||||
if r.spine_index != q:
|
|
||||||
break
|
|
||||||
r.index -= 1
|
|
||||||
self.takeItem(remove)
|
|
||||||
if self.count():
|
|
||||||
self.setCurrentRow(min(remove, self.count()-1))
|
|
||||||
self.item_activated()
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
@ -520,24 +518,8 @@ class SearchPanel(QWidget): # {{{
|
|||||||
|
|
||||||
def search_result_not_found(self, sr):
|
def search_result_not_found(self, sr):
|
||||||
self.results.search_result_not_found(sr)
|
self.results.search_result_not_found(sr)
|
||||||
if self.results.count():
|
|
||||||
now = monotonic()
|
|
||||||
if self.last_hidden_text_warning is None or self.current_search != self.last_hidden_text_warning[1] or now - self.last_hidden_text_warning[0] > 5:
|
|
||||||
self.last_hidden_text_warning = now, self.current_search
|
|
||||||
warning_dialog(self, _('Hidden text'), _(
|
|
||||||
'Some search results were for hidden or non-reflowable text, they will be removed.'), show=True)
|
|
||||||
elif self.last_hidden_text_warning is not None:
|
|
||||||
self.last_hidden_text_warning = now, self.last_hidden_text_warning[1]
|
|
||||||
|
|
||||||
if not self.results.count() and not self.spinner.is_running:
|
|
||||||
self.show_no_results_found()
|
|
||||||
|
|
||||||
def show_no_results_found(self):
|
def show_no_results_found(self):
|
||||||
has_hidden_text = self.last_hidden_text_warning is not None and self.last_hidden_text_warning[1] == self.current_search
|
msg = _('No matches were found for:')
|
||||||
if self.current_search:
|
warning_dialog(self, _('No matches found'), msg + ' <b>{}</b>'.format(self.current_search.text), show=True)
|
||||||
if has_hidden_text:
|
|
||||||
msg = _('No displayable matches were found for:')
|
|
||||||
else:
|
|
||||||
msg = _('No matches were found for:')
|
|
||||||
warning_dialog(self, _('No matches found'), msg + ' <b>{}</b>'.format(self.current_search.text), show=True)
|
|
||||||
# }}}
|
# }}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user