Start searching at current spine item

This commit is contained in:
Kovid Goyal 2021-02-24 12:21:52 +05:30
parent 8799260f2f
commit 66a7213c27
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -51,6 +51,9 @@ quote_map= {'"':'"“”', "'": "'"}
qpat = regex.compile(r'''(['"])''') qpat = regex.compile(r'''(['"])''')
spat = regex.compile(r'(\s+)') spat = regex.compile(r'(\s+)')
invisible_chars = '(?:[\u00ad\u200c\u200d]{0,1})' invisible_chars = '(?:[\u00ad\u200c\u200d]{0,1})'
SEARCH_RESULT_ROLE = Qt.ItemDataRole.UserRole
RESULT_NUMBER_ROLE = SEARCH_RESULT_ROLE + 1
SPINE_IDX_ROLE = RESULT_NUMBER_ROLE + 1
def text_to_regex(text): def text_to_regex(text):
@ -458,7 +461,7 @@ class Results(QTreeWidget): # {{{
def current_item_changed(self, current, previous): def current_item_changed(self, current, previous):
if current is not None: if current is not None:
r = current.data(0, Qt.ItemDataRole.UserRole) r = current.data(0, SEARCH_RESULT_ROLE)
if isinstance(r, SearchResult): if isinstance(r, SearchResult):
self.current_result_changed.emit(r) self.current_result_changed.emit(r)
else: else:
@ -475,10 +478,12 @@ class Results(QTreeWidget): # {{{
section_id = -1 section_id = -1
section_key = section_id section_key = section_id
section = self.section_map.get(section_key) section = self.section_map.get(section_key)
spine_idx = getattr(result, 'spine_idx', -1)
if section is None: if section is None:
section = QTreeWidgetItem([section_title], 1) section = QTreeWidgetItem([section_title], 1)
section.setFlags(Qt.ItemFlag.ItemIsEnabled) section.setFlags(Qt.ItemFlag.ItemIsEnabled)
section.setFont(0, self.section_font) section.setFont(0, self.section_font)
section.setData(0, SPINE_IDX_ROLE, spine_idx)
lines = [] lines = []
for i, node in enumerate(toc_nodes): for i, node in enumerate(toc_nodes):
lines.append('\xa0\xa0' * i + '' + (node.get('title') or _('Unknown'))) lines.append('\xa0\xa0' * i + '' + (node.get('title') or _('Unknown')))
@ -487,12 +492,19 @@ class Results(QTreeWidget): # {{{
tt += '\n' + '\n'.join(lines) tt += '\n' + '\n'.join(lines)
section.setToolTip(0, tt) section.setToolTip(0, tt)
self.section_map[section_key] = section self.section_map[section_key] = section
self.addTopLevelItem(section) for s in range(self.topLevelItemCount()):
ti = self.topLevelItem(s)
if ti.data(0, SPINE_IDX_ROLE) > spine_idx:
self.insertTopLevelItem(s, section)
break
else:
self.addTopLevelItem(section)
section.setExpanded(True) section.setExpanded(True)
item = QTreeWidgetItem(section, [' '], 2) item = QTreeWidgetItem(section, [' '], 2)
item.setFlags(Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemNeverHasChildren) item.setFlags(Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemNeverHasChildren)
item.setData(0, Qt.ItemDataRole.UserRole, result) item.setData(0, SEARCH_RESULT_ROLE, result)
item.setData(0, Qt.ItemDataRole.UserRole + 1, len(self.search_results)) item.setData(0, RESULT_NUMBER_ROLE, len(self.search_results))
item.setData(0, SPINE_IDX_ROLE, spine_idx)
if isinstance(result, SearchResult): if isinstance(result, SearchResult):
tt = '<p>…' + escape(result.before, False) + '<b>' + escape( tt = '<p>…' + escape(result.before, False) + '<b>' + escape(
result.text, False) + '</b>' + escape(result.after, False) + '' result.text, False) + '</b>' + escape(result.after, False) + ''
@ -507,7 +519,7 @@ class Results(QTreeWidget): # {{{
def item_activated(self): def item_activated(self):
i = self.currentItem() i = self.currentItem()
if i: if i:
sr = i.data(0, Qt.ItemDataRole.UserRole) sr = i.data(0, SEARCH_RESULT_ROLE)
if isinstance(sr, SearchResult): if isinstance(sr, SearchResult):
if not sr.is_hidden: if not sr.is_hidden:
self.show_search_result.emit(sr) self.show_search_result.emit(sr)
@ -518,7 +530,7 @@ class Results(QTreeWidget): # {{{
item = self.currentItem() item = self.currentItem()
if item is None: if item is None:
return return
i = int(item.data(0, Qt.ItemDataRole.UserRole + 1)) i = int(item.data(0, RESULT_NUMBER_ROLE))
i += -1 if previous else 1 i += -1 if previous else 1
i %= self.number_of_results i %= self.number_of_results
self.setCurrentItem(self.item_map[i]) self.setCurrentItem(self.item_map[i])
@ -527,7 +539,7 @@ class Results(QTreeWidget): # {{{
def search_result_not_found(self, sr): def search_result_not_found(self, sr):
for i in range(self.number_of_results): for i in range(self.number_of_results):
item = self.item_map[i] item = self.item_map[i]
r = item.data(0, Qt.ItemDataRole.UserRole) r = item.data(0, SEARCH_RESULT_ROLE)
if r.is_result(sr): if r.is_result(sr):
r.is_hidden = True r.is_hidden = True
item.setIcon(0, self.not_found_icon) item.setIcon(0, self.not_found_icon)
@ -537,7 +549,7 @@ class Results(QTreeWidget): # {{{
def current_result_is_hidden(self): def current_result_is_hidden(self):
item = self.currentItem() item = self.currentItem()
if item is not None: if item is not None:
sr = item.data(0, Qt.ItemDataRole.UserRole) sr = item.data(0, SEARCH_RESULT_ROLE)
if isinstance(sr, SearchResult) and sr.is_hidden: if isinstance(sr, SearchResult) and sr.is_hidden:
return True return True
return False return False
@ -557,6 +569,11 @@ class Results(QTreeWidget): # {{{
if self.number_of_results: if self.number_of_results:
item = self.item_map[0] item = self.item_map[0]
self.setCurrentItem(item) self.setCurrentItem(item)
def ensure_current_result_visible(self):
item = self.currentItem()
if item is not None:
self.scrollToItem(item)
# }}} # }}}
@ -648,14 +665,16 @@ class SearchPanel(QWidget): # {{{
if spine_idx < 0: if spine_idx < 0:
self.results_found.emit(SearchFinished(search_query)) self.results_found.emit(SearchFinished(search_query))
continue continue
for name in spine: num_in_spine = len(spine)
for n in range(num_in_spine):
idx = (spine_idx + n) % num_in_spine
name = spine[idx]
counter = Counter() counter = Counter()
spine_idx = idx_map[name]
try: try:
for i, result in enumerate(search_in_name(name, search_query)): for i, result in enumerate(search_in_name(name, search_query)):
before, text, after, offset = result before, text, after, offset = result
q = (before or '')[-5:] + text + (after or '')[:5] q = (before or '')[-5:] + text + (after or '')[:5]
self.results_found.emit(SearchResult(search_query, before, text, after, q, name, spine_idx, counter[q], offset)) self.results_found.emit(SearchResult(search_query, before, text, after, q, name, idx, counter[q], offset))
counter[q] += 1 counter[q] += 1
except Exception: except Exception:
import traceback import traceback
@ -667,7 +686,9 @@ class SearchPanel(QWidget): # {{{
return return
if isinstance(result, SearchFinished): if isinstance(result, SearchFinished):
self.spinner.stop() self.spinner.stop()
if not self.results.number_of_results: if self.results.number_of_results:
self.results.ensure_current_result_visible()
else:
self.show_no_results_found() self.show_no_results_found()
return return
if self.results.add_result(result) == 1: if self.results.add_result(result) == 1: