Search result highlighting
Disable UI elements when irrelevant
This commit is contained in:
2
TODO
2
TODO
@@ -62,6 +62,7 @@ TODO
|
||||
✓ Make the bookmark dock float over the reading area
|
||||
✓ Spacebar should not cut off lines at the top
|
||||
✓ Track open bookmark windows so they can be closed quickly at exit
|
||||
✓ Search document using QTextCursor
|
||||
Double page / column view
|
||||
✓ For comics
|
||||
Caching is currently non fuctional
|
||||
@@ -70,7 +71,6 @@ TODO
|
||||
Annotation preview in listView
|
||||
Disable buttons for annotations, search in images
|
||||
Adjust key navigation according to viewport dimensions
|
||||
Search document using QTextCursor
|
||||
Redo context menu order
|
||||
Filetypes:
|
||||
✓ pdf support
|
||||
|
@@ -643,6 +643,14 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
if self.bookToolBar.fontButton.isChecked():
|
||||
self.bookToolBar.customize_view_on()
|
||||
|
||||
# Disable irrelevant buttons in image view mode
|
||||
if current_tab.are_we_doing_images_only:
|
||||
self.bookToolBar.searchButton.setEnabled(False)
|
||||
self.bookToolBar.annotationButton.setEnabled(False)
|
||||
else:
|
||||
self.bookToolBar.searchButton.setEnabled(True)
|
||||
self.bookToolBar.annotationButton.setEnabled(True)
|
||||
|
||||
current_position = current_metadata['position']
|
||||
current_toc = [i[0] for i in current_metadata['content']]
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import re
|
||||
import pathlib
|
||||
|
||||
from multiprocessing.dummy import Pool
|
||||
@@ -217,18 +218,25 @@ class BackGroundTextSearch(QtCore.QThread):
|
||||
surroundingTextCursor = QtGui.QTextCursor(chapterDocument)
|
||||
surroundingTextCursor.setPosition(
|
||||
result_position, QtGui.QTextCursor.MoveAnchor)
|
||||
# Get words before and after
|
||||
surroundingTextCursor.movePosition(
|
||||
QtGui.QTextCursor.WordLeft, QtGui.QTextCursor.MoveAnchor, 2)
|
||||
QtGui.QTextCursor.WordLeft, QtGui.QTextCursor.MoveAnchor, 3)
|
||||
surroundingTextCursor.movePosition(
|
||||
QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor, 5) # 2n + 1
|
||||
QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor, 6)
|
||||
surrounding_text = surroundingTextCursor.selection().toPlainText()
|
||||
surrounding_text = surrounding_text.replace('\n', ' ')
|
||||
|
||||
# Case insensitive replace for find results
|
||||
replace_pattern = re.compile(re.escape(self.search_text), re.IGNORECASE)
|
||||
surrounding_text = replace_pattern.sub(
|
||||
f'<b>{self.search_text}</b>', surrounding_text)
|
||||
|
||||
try:
|
||||
self.search_results[chapter].append(
|
||||
(result_position, surrounding_text))
|
||||
(result_position, surrounding_text, self.search_text))
|
||||
except KeyError:
|
||||
self.search_results[chapter] = [(result_position, surrounding_text)]
|
||||
self.search_results[chapter] = [
|
||||
(result_position, surrounding_text, self.search_text)]
|
||||
|
||||
new_position = result_position + len(self.search_text)
|
||||
findResultCursor = chapterDocument.find(
|
||||
|
@@ -74,12 +74,12 @@ class BookToolBar(QtWidgets.QToolBar):
|
||||
self.fontButton.setCheckable(True)
|
||||
self.fontButton.triggered.connect(self.toggle_font_settings)
|
||||
self.bookSeparator1 = self.addSeparator()
|
||||
self.addAction(self.searchButton)
|
||||
self.bookSeparator2 = self.addSeparator()
|
||||
self.addAction(self.annotationButton)
|
||||
self.bookSeparator3 = self.addSeparator()
|
||||
self.bookSeparator2 = self.addSeparator()
|
||||
self.addAction(self.addBookmarkButton)
|
||||
self.addAction(self.bookmarkButton)
|
||||
self.bookSeparator3 = self.addSeparator()
|
||||
self.addAction(self.searchButton)
|
||||
self.bookSeparator4 = self.addSeparator()
|
||||
self.addAction(self.distractionFreeButton)
|
||||
self.addAction(self.fullscreenButton)
|
||||
@@ -307,9 +307,11 @@ class BookToolBar(QtWidgets.QToolBar):
|
||||
self.annotationButton,
|
||||
self.addBookmarkButton,
|
||||
self.bookmarkButton,
|
||||
self.searchButton,
|
||||
self.distractionFreeButton,
|
||||
self.fullscreenButton,
|
||||
self.tocBoxAction,
|
||||
self.bookSeparator1,
|
||||
self.bookSeparator2,
|
||||
self.bookSeparator3,
|
||||
self.bookSeparator4]
|
||||
|
@@ -130,18 +130,18 @@ class Tab(QtWidgets.QWidget):
|
||||
self.sideDock.setWidget(self.sideDockTabWidget)
|
||||
|
||||
# Annotation list view and model
|
||||
self.annotationListView = QtWidgets.QListView(self.sideDockTabWidget)
|
||||
# self.annotationListView.setResizeMode(QtWidgets.QListWidget.Adjust)
|
||||
self.annotationListView = QtWidgets.QListView()
|
||||
self.annotationListView.setEditTriggers(QtWidgets.QListView.NoEditTriggers)
|
||||
self.annotationListView.doubleClicked.connect(self.contentView.toggle_annotation_mode)
|
||||
annotations_string = self._translate('Tab', 'Annotations')
|
||||
if not self.are_we_doing_images_only:
|
||||
self.sideDockTabWidget.addTab(self.annotationListView, annotations_string)
|
||||
|
||||
self.annotationModel = QtGui.QStandardItemModel(self)
|
||||
self.generate_annotation_model()
|
||||
|
||||
# Bookmark tree view and model
|
||||
self.bookmarkTreeView = QtWidgets.QTreeView(self.sideDockTabWidget)
|
||||
self.bookmarkTreeView = QtWidgets.QTreeView()
|
||||
self.bookmarkTreeView.setHeaderHidden(True)
|
||||
self.bookmarkTreeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.bookmarkTreeView.customContextMenuRequested.connect(
|
||||
@@ -155,14 +155,14 @@ class Tab(QtWidgets.QWidget):
|
||||
self.generate_bookmark_model()
|
||||
|
||||
# Search view and model
|
||||
self.searchLineEdit = QtWidgets.QLineEdit(self.sideDockTabWidget)
|
||||
self.searchLineEdit = QtWidgets.QLineEdit()
|
||||
self.searchLineEdit.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.searchLineEdit.setClearButtonEnabled(True)
|
||||
search_string = self._translate('Tab', 'Search')
|
||||
self.searchLineEdit.setPlaceholderText(search_string)
|
||||
|
||||
search_book_string = self._translate('Tab', 'Search entire book')
|
||||
self.searchBookButton = QtWidgets.QToolButton(self.sideDockTabWidget)
|
||||
self.searchBookButton = QtWidgets.QToolButton()
|
||||
self.searchBookButton.setIcon(
|
||||
self.main_window.QImageFactory.get_image('view-readermode'))
|
||||
self.searchBookButton.setToolTip(search_book_string)
|
||||
@@ -170,7 +170,7 @@ class Tab(QtWidgets.QWidget):
|
||||
self.searchBookButton.setAutoRaise(True)
|
||||
|
||||
case_sensitive_string = self._translate('Tab', 'Match case')
|
||||
self.caseSensitiveSearchButton = QtWidgets.QToolButton(self.sideDockTabWidget)
|
||||
self.caseSensitiveSearchButton = QtWidgets.QToolButton()
|
||||
self.caseSensitiveSearchButton.setIcon(
|
||||
self.main_window.QImageFactory.get_image('search-case'))
|
||||
self.caseSensitiveSearchButton.setToolTip(case_sensitive_string)
|
||||
@@ -178,7 +178,7 @@ class Tab(QtWidgets.QWidget):
|
||||
self.caseSensitiveSearchButton.setAutoRaise(True)
|
||||
|
||||
match_word_string = self._translate('Tab', 'Match word')
|
||||
self.matchWholeWordButton = QtWidgets.QToolButton(self.sideDockTabWidget)
|
||||
self.matchWholeWordButton = QtWidgets.QToolButton()
|
||||
self.matchWholeWordButton.setIcon(
|
||||
self.main_window.QImageFactory.get_image('search-word'))
|
||||
self.matchWholeWordButton.setToolTip(match_word_string)
|
||||
@@ -192,18 +192,19 @@ class Tab(QtWidgets.QWidget):
|
||||
self.searchOptionsLayout.addWidget(self.caseSensitiveSearchButton)
|
||||
self.searchOptionsLayout.addWidget(self.matchWholeWordButton)
|
||||
|
||||
self.searchResultsTreeView = QtWidgets.QTreeView(self.sideDockTabWidget)
|
||||
self.searchResultsTreeView = QtWidgets.QTreeView()
|
||||
self.searchResultsTreeView.setHeaderHidden(True)
|
||||
self.searchResultsTreeView.setEditTriggers(QtWidgets.QTreeView.NoEditTriggers)
|
||||
self.searchResultsTreeView.clicked.connect(self.navigate_to_search_result)
|
||||
|
||||
self.searchTabLayout = QtWidgets.QVBoxLayout(self.sideDockTabWidget)
|
||||
self.searchTabLayout = QtWidgets.QVBoxLayout()
|
||||
self.searchTabLayout.addLayout(self.searchOptionsLayout)
|
||||
self.searchTabLayout.addWidget(self.searchResultsTreeView)
|
||||
self.searchTabLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.searchTabWidget = QtWidgets.QWidget(self.sideDockTabWidget)
|
||||
self.searchTabWidget = QtWidgets.QWidget()
|
||||
self.searchTabWidget.setLayout(self.searchTabLayout)
|
||||
|
||||
if not self.are_we_doing_images_only:
|
||||
self.sideDockTabWidget.addTab(self.searchTabWidget, search_string)
|
||||
|
||||
# Create the annotation notes dock
|
||||
@@ -241,6 +242,8 @@ class Tab(QtWidgets.QWidget):
|
||||
self.searchTimer.setSingleShot(True)
|
||||
self.searchTimer.timeout.connect(self.set_search_options)
|
||||
|
||||
self.searchLineEdit.textChanged.connect(
|
||||
lambda: self.searchLineEdit.setStyleSheet(QtWidgets.QLineEdit.styleSheet(self)))
|
||||
self.searchLineEdit.textChanged.connect(lambda: self.searchTimer.start(500))
|
||||
self.searchBookButton.clicked.connect(lambda: self.searchTimer.start(100))
|
||||
self.caseSensitiveSearchButton.clicked.connect(lambda: self.searchTimer.start(100))
|
||||
@@ -705,23 +708,46 @@ class Tab(QtWidgets.QWidget):
|
||||
search_results = self.searchThread.search_results
|
||||
for i in search_results:
|
||||
parentItem = QtGui.QStandardItem()
|
||||
parentItem.setText(i)
|
||||
parentItem.setData(True, QtCore.Qt.UserRole)
|
||||
parentItem.setData(True, QtCore.Qt.UserRole) # Is parent?
|
||||
parentItem.setData(i, QtCore.Qt.UserRole + 3) # Display text for label
|
||||
chapter_index = self.main_window.bookToolBar.tocBox.findText(
|
||||
i, QtCore.Qt.MatchExactly)
|
||||
|
||||
for j in search_results[i]:
|
||||
childItem = QtGui.QStandardItem()
|
||||
childItem.setText(j[1])
|
||||
childItem = QtGui.QStandardItem(parentItem)
|
||||
childItem.setData(False, QtCore.Qt.UserRole) # Is parent?
|
||||
childItem.setData(chapter_index, QtCore.Qt.UserRole + 1) # Chapter index
|
||||
childItem.setData(j[0], QtCore.Qt.UserRole + 2) # Cursor Position
|
||||
childItem.setData(j[1], QtCore.Qt.UserRole + 3) # Display text for label
|
||||
childItem.setData(j[2], QtCore.Qt.UserRole + 4) # Search term
|
||||
parentItem.appendRow(childItem)
|
||||
self.searchResultsModel.appendRow(parentItem)
|
||||
|
||||
self.searchResultsTreeView.setModel(self.searchResultsModel)
|
||||
self.searchResultsTreeView.expandToDepth(1)
|
||||
|
||||
if not search_results and len(self.searchLineEdit.text()) > 2:
|
||||
self.searchLineEdit.setStyleSheet("QLineEdit {color: red;}")
|
||||
|
||||
# We'll be putting in labels instead of making a delegate
|
||||
# QLabels can understand RTF, and they also have the somewhat
|
||||
# distinct advantage of being a lot less work than a delegate
|
||||
|
||||
def generate_label(index):
|
||||
label_text = self.searchResultsModel.data(index, QtCore.Qt.UserRole + 3)
|
||||
labelWidget = PliantLabelWidget(index, self.navigate_to_search_result)
|
||||
labelWidget.setText(label_text)
|
||||
self.searchResultsTreeView.setIndexWidget(index, labelWidget)
|
||||
|
||||
for parent_iter in range(self.searchResultsModel.rowCount()):
|
||||
parentItem = self.searchResultsModel.item(parent_iter)
|
||||
parentIndex = self.searchResultsModel.index(parent_iter, 0)
|
||||
generate_label(parentIndex)
|
||||
|
||||
for child_iter in range(parentItem.rowCount()):
|
||||
childIndex = self.searchResultsModel.index(child_iter, 0, parentIndex)
|
||||
generate_label(childIndex)
|
||||
|
||||
def navigate_to_search_result(self, index):
|
||||
if not index.isValid():
|
||||
return
|
||||
@@ -732,11 +758,12 @@ class Tab(QtWidgets.QWidget):
|
||||
|
||||
chapter_index = self.searchResultsModel.data(index, QtCore.Qt.UserRole + 1)
|
||||
cursor_position = self.searchResultsModel.data(index, QtCore.Qt.UserRole + 2)
|
||||
search_term = self.searchResultsModel.data(index, QtCore.Qt.UserRole + 4)
|
||||
|
||||
self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter_index)
|
||||
if not self.are_we_doing_images_only:
|
||||
self.set_cursor_position(
|
||||
cursor_position, len(self.searchLineEdit.text()))
|
||||
cursor_position, len(search_term))
|
||||
|
||||
def hide_mouse(self):
|
||||
self.contentView.viewport().setCursor(QtCore.Qt.BlankCursor)
|
||||
@@ -754,6 +781,19 @@ class Tab(QtWidgets.QWidget):
|
||||
self.main_window.closeEvent()
|
||||
|
||||
|
||||
class PliantLabelWidget(QtWidgets.QLabel):
|
||||
# This is a hack to get clickable / editable appearance
|
||||
# search results in the tree view.
|
||||
|
||||
def __init__(self, index, navigate_to_search_result):
|
||||
super(PliantLabelWidget, self).__init__()
|
||||
self.index = index
|
||||
self.navigate_to_search_result = navigate_to_search_result
|
||||
|
||||
def mousePressEvent(self, QMouseEvent):
|
||||
self.navigate_to_search_result(self.index)
|
||||
QtWidgets.QLabel.mousePressEvent(self, QMouseEvent)
|
||||
|
||||
class PliantDockWidget(QtWidgets.QDockWidget):
|
||||
def __init__(self, main_window, notes_only, contentView, parent=None):
|
||||
super(PliantDockWidget, self).__init__()
|
||||
|
Reference in New Issue
Block a user