Overhaul TOC generation and navigation

This commit is contained in:
BasioMeusPuga
2019-01-26 19:03:30 +05:30
parent 66746b4eaa
commit 739b84e9f4
11 changed files with 335 additions and 200 deletions

View File

@@ -637,14 +637,15 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.current_tab = self.tabWidget.currentIndex()
# Hide bookmark and annotation widgets
# Hide all side docks whenever a tab is switched
for i in range(1, self.tabWidget.count()):
self.tabWidget.widget(i).sideDock.setVisible(False)
# If library
if self.tabWidget.currentIndex() == 0:
self.resizeEvent()
self.start_culling_timer()
if self.settings['show_bars']:
self.bookToolBar.hide()
self.libraryToolBar.show()
@@ -660,45 +661,34 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.statusBar.setVisible(True)
else:
if self.settings['show_bars']:
self.bookToolBar.show()
self.libraryToolBar.hide()
current_tab = self.tabWidget.currentWidget()
current_metadata = current_tab.metadata
self.bookToolBar.tocBox.setModel(current_tab.tocModel)
self.bookToolBar.tocTreeView.expandAll()
current_tab.set_tocBox_index(None, None)
# Needed to set the contentView widget background
# on first run. Subsequent runs might be redundant,
# but it doesn't seem to visibly affect performance
self.profile_functions.format_contentView()
self.statusBar.setVisible(False)
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.setVisible(False)
self.bookToolBar.annotationButton.setVisible(False)
self.bookToolBar.bookSeparator2.setVisible(False)
self.bookToolBar.bookSeparator3.setVisible(False)
else:
self.bookToolBar.searchButton.setVisible(True)
self.bookToolBar.annotationButton.setVisible(True)
self.bookToolBar.bookSeparator2.setVisible(True)
self.bookToolBar.bookSeparator3.setVisible(True)
current_position = current_metadata['position']
current_toc = [i[0] for i in current_metadata['content']]
self.bookToolBar.tocBox.blockSignals(True)
self.bookToolBar.tocBox.clear()
self.bookToolBar.tocBox.addItems(current_toc)
if current_position:
self.bookToolBar.tocBox.setCurrentIndex(
current_position['current_chapter'] - 1)
if not current_metadata['images_only']:
current_tab.hiddenButton.animateClick(25)
self.bookToolBar.tocBox.blockSignals(False)
self.profile_functions.format_contentView()
self.statusBar.setVisible(False)
if current_tab.are_we_doing_images_only:
self.bookToolBar.searchButton.setVisible(False)
self.bookToolBar.annotationButton.setVisible(False)
self.bookToolBar.bookSeparator2.setVisible(False)
self.bookToolBar.bookSeparator3.setVisible(False)
else:
self.bookToolBar.searchButton.setVisible(True)
self.bookToolBar.annotationButton.setVisible(True)
self.bookToolBar.bookSeparator2.setVisible(True)
self.bookToolBar.bookSeparator3.setVisible(True)
def tab_close(self, tab_index=None):
if not tab_index:
@@ -726,18 +716,15 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.tabWidget.setMovable(True)
def set_toc_position(self, event=None):
currentIndex = self.bookToolBar.tocTreeView.currentIndex()
required_position = currentIndex.data(QtCore.Qt.UserRole)
if not required_position:
return # Initial startup might return a None
# The set_content method is universal
# It's going to do position tracking
current_tab = self.tabWidget.currentWidget()
current_tab.metadata[
'position']['current_chapter'] = event + 1
current_tab.metadata[
'position']['is_read'] = False
# Go on to change the value of the Table of Contents box
current_tab.change_chapter_tocBox()
current_tab.contentView.record_position()
self.profile_functions.format_contentView()
current_tab.set_content(required_position)
def set_fullscreen(self):
self.tabWidget.currentWidget().go_fullscreen()
@@ -808,12 +795,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# current state of each of the toolbar buttons
self.settings['double_page_mode'] = self.bookToolBar.doublePageButton.isChecked()
self.settings['manga_mode'] = self.bookToolBar.mangaModeButton.isChecked()
chapter_number = self.bookToolBar.tocBox.currentIndex()
# Switch page to whatever index is selected in the tocBox
current_tab = self.tabWidget.currentWidget()
required_content = current_tab.metadata['content'][chapter_number][1]
current_tab.contentView.loadImage(required_content)
chapter_number = current_tab.metadata['position']['current_chapter']
current_tab.set_content(chapter_number, False)
def generate_library_context_menu(self, position):
index = self.sender().indexAt(position)

View File

@@ -73,12 +73,12 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
self.generate_graphicsview_context_menu)
def loadImage(self, current_page):
all_pages = [i[1] for i in self.parent.metadata['content']]
all_pages = self.parent.metadata['content']
current_page_index = all_pages.index(current_page)
double_page_mode = False
if (self.main_window.settings['double_page_mode']
and (current_page_index != 0 and current_page_index != len(all_pages) - 1)):
and (current_page_index not in (0, len(all_pages) - 1))):
double_page_mode = True
def load_page(current_page):
@@ -492,7 +492,7 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
selected_index = self.parent.annotationListView.currentIndex()
self.current_annotation = self.parent.annotationModel.data(
selected_index, QtCore.Qt.UserRole)
logger.info('Selected annotation: ' + + self.current_annotation['name'])
logger.info('Selected annotation: ' + self.current_annotation['name'])
def mouseReleaseEvent(self, event):
# This takes care of annotation placement
@@ -716,37 +716,34 @@ class PliantWidgetsCommonFunctions:
self.change_chapter(-1)
def change_chapter(self, direction, was_button_pressed=None):
current_toc_index = self.main_window.bookToolBar.tocBox.currentIndex()
max_toc_index = self.main_window.bookToolBar.tocBox.count() - 1
current_tab = self.pw.parent
current_position = current_tab.metadata['position']['current_chapter']
if (current_toc_index < max_toc_index and direction == 1) or (
current_toc_index > 0 and direction == -1):
# Special cases for double page view
# Page limits are taken care of by the set_content method
def get_modifier():
if (not self.main_window.settings['double_page_mode']
or not self.are_we_doing_images_only):
return 0
# Special cases for double page view
def get_modifier():
if (not self.main_window.settings['double_page_mode']
or not self.are_we_doing_images_only):
return 0
if (current_position == 0 or current_position % 2 == 0):
return 0
if (current_toc_index == 0
or current_toc_index % 2 == 0
or current_toc_index == max_toc_index):
return 0
if current_toc_index % 2 == 1:
return direction
if current_position % 2 == 1:
return direction
self.main_window.bookToolBar.tocBox.setCurrentIndex(
current_toc_index + direction + get_modifier())
current_tab.set_content(
current_position + direction + get_modifier(), True)
# Set page position depending on if the chapter number is increasing or decreasing
if direction == 1 or was_button_pressed:
self.pw.verticalScrollBar().setValue(0)
else:
self.pw.verticalScrollBar().setValue(
self.pw.verticalScrollBar().maximum())
# Set page position depending on if the chapter number is increasing or decreasing
if direction == 1 or was_button_pressed:
self.pw.verticalScrollBar().setValue(0)
else:
self.pw.verticalScrollBar().setValue(
self.pw.verticalScrollBar().maximum())
if not was_button_pressed:
self.pw.ignore_wheel_event = True
if not was_button_pressed:
self.pw.ignore_wheel_event = True
def load_annotations(self, chapter):
try:
@@ -849,14 +846,27 @@ class PliantWidgetsCommonFunctions:
def generate_combo_box_action(self, contextMenu):
contextMenu.addSeparator()
tocCombobox = QtWidgets.QComboBox()
toc_data = [i[0] for i in self.pw.parent.metadata['content']]
tocCombobox.addItems(toc_data)
tocCombobox.setCurrentIndex(
self.pw.main_window.bookToolBar.tocBox.currentIndex())
tocCombobox.currentIndexChanged.connect(
self.pw.main_window.bookToolBar.tocBox.setCurrentIndex)
def set_toc_position(tocTree):
currentIndex = tocTree.currentIndex()
required_position = currentIndex.data(QtCore.Qt.UserRole)
self.pw.parent.set_content(required_position, True)
# Create the Combobox / Treeview combination
tocComboBox = QtWidgets.QComboBox()
tocTree = QtWidgets.QTreeView()
tocComboBox.setView(tocTree)
tocComboBox.setModel(self.pw.parent.tocModel)
tocTree.setRootIsDecorated(False)
tocTree.setItemsExpandable(False)
tocTree.expandAll()
# Set the position of the QComboBox
self.pw.parent.set_tocBox_index(None, tocComboBox)
# Make clicking do something
tocComboBox.currentIndexChanged.connect(
lambda: set_toc_position(tocTree))
comboboxAction = QtWidgets.QWidgetAction(self.pw)
comboboxAction.setDefaultWidget(tocCombobox)
comboboxAction.setDefaultWidget(tocComboBox)
contextMenu.addAction(comboboxAction)

View File

@@ -83,11 +83,11 @@ class ParseCOMIC:
return None
def get_contents(self):
file_settings = {'images_only': True}
contents = [(f'Page {count + 1}', i) for count, i in enumerate(self.image_list)]
return contents, file_settings
image_number = len(self.image_list)
toc = [(1, f'Page {i + 1}', i + 1) for i in range(image_number)]
# Return toc, content, images_only
return toc, self.image_list, True
def is_image(filename):
valid_image_extensions = ['.png', '.jpg', '.bmp']

View File

@@ -63,6 +63,12 @@ class ParseEPUB:
self.book_ref.parse_toc()
self.book_ref.parse_chapters(temp_dir=self.extract_path)
file_settings = {
'images_only': False}
return self.book['book_list'], file_settings
toc = []
content = []
for count, i in enumerate(self.book['book_list']):
toc.append((1, i[0], count + 1))
content.append(i[1])
# Return toc, content, images_only
return toc, content, False

View File

@@ -60,6 +60,12 @@ class ParseFB2:
def get_contents(self):
os.makedirs(self.extract_path, exist_ok=True) # Manual creation is required here
self.book_ref.parse_chapters(temp_dir=self.extract_path)
file_settings = {
'images_only': False}
return self.book['book_list'], file_settings
toc = []
content = []
for count, i in enumerate(self.book['book_list']):
toc.append((1, i[0], count + 1))
content.append(i[1])
# Return toc, content, images_only
return toc, content, False

View File

@@ -73,24 +73,13 @@ class ParsePDF:
return tags # Fine if it returns None
def get_contents(self):
# Contents are to be returned as:
# Level, Title, Page Number
# Increasing the level number means the
# title is one level up in the tree
content = list(range(self.book.pageCount))
toc = self.book.getToC()
if not toc:
toc = [(1, f'Page {i + 1}', i + 1) for i in range(self.book.pageCount)]
# TODO
# Better parsing of TOC
# file_settings = {'images_only': True}
# contents = self.book.getToC()
# if not contents:
# contents = [
# (1, f'Page {i + 1}', i) for i in range(self.book.pageCount)]
# return contents, file_settings
file_settings = {'images_only': True}
contents = [(f'Page {i + 1}', i) for i in range(self.book.pageCount)]
return contents, file_settings
# Return toc, content, images_only
return toc, content, True
def render_pdf_page(page_data, for_cover=False):

View File

@@ -217,6 +217,8 @@ class BookSorter:
return
if book_ref.book:
# TODO
# For the love of God clean this up. It's junk.
this_book = {}
this_book[file_md5] = {
@@ -246,18 +248,13 @@ class BookSorter:
this_book[file_md5]['addition_mode'] = self.addition_mode
if self.work_mode == 'reading':
all_content = book_ref.get_contents()
# All books must return the following list
# Indices are as described below
book_breakdown = book_ref.get_contents()
# get_contents() returns a tuple. Index 1 is a collection of
# special settings that depend on the kind of data being parsed.
# Currently, this includes:
# Only images included images_only BOOL Book contains only images
content = all_content[0]
images_only = all_content[1]['images_only']
if not content:
content = [('Invalid', 'Something went horribly wrong')]
toc = book_breakdown[0]
content = book_breakdown[1]
images_only = book_breakdown[2]
book_data = self.database_entry_for_book(file_md5)
title = book_data[0]
@@ -272,6 +269,7 @@ class BookSorter:
this_book[file_md5]['position'] = position
this_book[file_md5]['bookmarks'] = bookmarks
this_book[file_md5]['toc'] = toc
this_book[file_md5]['content'] = content
this_book[file_md5]['images_only'] = images_only
this_book[file_md5]['cover'] = cover

View File

@@ -222,15 +222,16 @@ class BackGroundTextSearch(QtCore.QThread):
# through it looking for hits
for i in self.search_content:
chapter = i[0]
chapter_title = i[0]
chapterDocument = QtGui.QTextDocument()
chapterDocument.setHtml(i[1])
chapter_number = i[2]
findFlags = QtGui.QTextDocument.FindFlags(0)
if self.case_sensitive:
findFlags = findFlags | QtGui.QTextDocument.FindCaseSensitively
if self.match_words:
findFlags = findFlags | QtGui.QTextDocument.FindWholeWords
if self.case_sensitive:
findFlags = findFlags | QtGui.QTextDocument.FindCaseSensitively
findResultCursor = chapterDocument.find(self.search_text, 0, findFlags)
while not findResultCursor.isNull():
@@ -252,12 +253,13 @@ class BackGroundTextSearch(QtCore.QThread):
surrounding_text = replace_pattern.sub(
f'<b>{self.search_text}</b>', surrounding_text)
result_tuple = (
result_position, surrounding_text, self.search_text, chapter_number)
try:
self.search_results[chapter].append(
(result_position, surrounding_text, self.search_text))
self.search_results[chapter_title].append(result_tuple)
except KeyError:
self.search_results[chapter] = [
(result_position, surrounding_text, self.search_text)]
self.search_results[chapter_title] = [result_tuple]
new_position = result_position + len(self.search_text)
findResultCursor = chapterDocument.find(

View File

@@ -289,11 +289,15 @@ class BookToolBar(QtWidgets.QToolBar):
for i in self.comicActions:
i.setVisible(False)
# Sorter
# Table of contents Combo Box
# Has to have a QTreeview associated with it
self.tocBox = FixedComboBox(self)
self.tocBox.setObjectName('sortingBox')
self.tocBox.setToolTip(
self._translate('BookToolBar', 'Table of Contents'))
self.tocTreeView = QtWidgets.QTreeView(self.tocBox)
self.tocBox.setView(self.tocTreeView)
self.tocTreeView.setItemsExpandable(False)
self.tocTreeView.setRootIsDecorated(False)
# All of these will be put after the spacer
# This means that the buttons in the left side of
@@ -326,17 +330,16 @@ class BookToolBar(QtWidgets.QToolBar):
self.customize_view_off()
def customize_view_on(self):
if self.parent().tabWidget.widget(
self.parent().tabWidget.currentIndex()).metadata['images_only']:
# The following might seem redundant,
# but it's necessary for tab switching
images_only = self.parent().tabWidget.currentWidget().are_we_doing_images_only
# The following might seem redundant,
# but it's necessary for tab switching
if images_only:
for i in self.comicActions:
i.setVisible(True)
for i in self.fontActions:
i.setVisible(False)
else:
for i in self.fontActions:
i.setVisible(True)
@@ -368,7 +371,6 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.setIconSize(QtCore.QSize(22, 22))
self.setFloatable(False)
self.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)
self.setObjectName("LibraryToolBar")
image_factory = self.window().QImageFactory
@@ -443,7 +445,6 @@ class LibraryToolBar(QtWidgets.QToolBar):
self._translate('LibraryToolBar', 'Search for Title, Author, Tags...'))
self.searchBar.setSizePolicy(sizePolicy)
self.searchBar.setContentsMargins(0, 0, 10, 0)
self.searchBar.setObjectName('searchBar')
# Sorter
title_string = self._translate('LibraryToolBar', 'Title')
@@ -458,8 +459,6 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.sortingBox = FixedComboBox(self)
self.sortingBox.addItems(sorting_choices)
self.sortingBox.setObjectName('sortingBox')
self.sortingBox.setSizePolicy(sizePolicy)
self.sortingBox.setMinimumContentsLength(10)
self.sortingBox.setToolTip(self._translate('LibraryToolBar', 'Sort by'))
@@ -479,7 +478,7 @@ class FixedComboBox(QtWidgets.QComboBox):
def __init__(self, parent=None):
super(FixedComboBox, self).__init__(parent)
screen_width = QtWidgets.QDesktopWidget().screenGeometry().width()
self.adjusted_size = screen_width // 4.8
self.adjusted_size = screen_width // 4.5
def sizeHint(self):
# This and the one below should adjust to screen size
@@ -490,7 +489,7 @@ class FixedLineEdit(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(FixedLineEdit, self).__init__(parent)
screen_width = QtWidgets.QDesktopWidget().screenGeometry().width()
self.adjusted_size = screen_width // 4.8
self.adjusted_size = screen_width // 4.5
def sizeHint(self):
return QtCore.QSize(self.adjusted_size, 22)

View File

@@ -39,7 +39,6 @@ class Tab(QtWidgets.QWidget):
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.first_run = True
self.main_window = main_window
self.metadata = metadata # Save progress data into this dictionary
self.are_we_doing_images_only = self.metadata['images_only']
@@ -51,7 +50,20 @@ class Tab(QtWidgets.QWidget):
self.metadata['last_accessed'] = QtCore.QDateTime().currentDateTime()
# Create relevant containers
if not self.metadata['annotations']:
self.metadata['annotations'] = {}
if not self.metadata['bookmarks']:
self.metadata['bookmarks'] = {}
# Generate toc Model
self.tocModel = QtGui.QStandardItemModel()
self.tocModel.setHorizontalHeaderLabels(('Table of Contents',))
self.generate_toc_model()
# Get the current position of the book
if self.metadata['position']:
# A book might have been marked read without being opened
if self.metadata['position']['is_read']:
self.generate_position(True)
current_chapter = self.metadata['position']['current_chapter']
@@ -59,53 +71,49 @@ class Tab(QtWidgets.QWidget):
self.generate_position()
current_chapter = 1
chapter_content = self.metadata['content'][current_chapter - 1][1]
# Create relevant containers
if not self.metadata['annotations']:
self.metadata['annotations'] = {}
# See bookmark availability
if not self.metadata['bookmarks']:
self.metadata['bookmarks'] = {}
# The content display widget is, by default a QTextBrowser.
# In case the incoming data is only images
# such as in the case of comic book files,
# we want a QGraphicsView widget doing all the heavy lifting
# instead of a QTextBrowser
if self.are_we_doing_images_only: # Boolean
if self.are_we_doing_images_only:
self.contentView = PliantQGraphicsView(
self.metadata['path'], self.main_window, self)
self.contentView.loadImage(chapter_content)
else:
self.contentView = PliantQTextBrowser(self.main_window, self)
else:
self.contentView = PliantQTextBrowser(
self.main_window, self)
self.contentView.setReadOnly(True)
# TODO
# Change this when HTML navigation works
self.contentView.setOpenLinks(False)
# TODO
# Rename the .css files to something else here and keep
# a record of them .Currently, I'm just removing them
# for the sake of simplicity
relative_path_root = os.path.join(
self.main_window.temp_dir.path(), self.metadata['hash'])
relative_paths = []
for i in os.walk(relative_path_root):
# TODO
# Rename the .css files to something else here and keep
# a record of them
# Currently, I'm just removing them for the sake of simplicity
for j in i[2]:
file_extension = os.path.splitext(j)[1]
if file_extension == '.css':
file_path = os.path.join(i[0], j)
os.remove(file_path)
relative_paths.append(os.path.join(relative_path_root, i[0]))
self.contentView.setSearchPaths(relative_paths)
self.contentView.setOpenLinks(False) # TODO Change this when HTML navigation works
self.contentView.setHtml(chapter_content)
self.contentView.setReadOnly(True)
self.hiddenButton = QtWidgets.QToolButton(self)
self.hiddenButton.setVisible(False)
self.hiddenButton.clicked.connect(self.set_cursor_position)
# All content must be set through this function
self.set_content(current_chapter, True)
if not self.are_we_doing_images_only:
# Setting this later breaks cursor positioning for search results
self.hiddenButton.animateClick(50)
# Load annotations for current content
@@ -414,6 +422,45 @@ class Tab(QtWidgets.QWidget):
QtGui.QKeySequence('Ctrl+F'), self.contentView)
ksToggleSearch.activated.connect(lambda: self.toggle_side_dock(2))
def generate_toc_model(self):
# The toc list is:
# 0: Level
# 1: Title
# 2: Chapter content / page number
# pprint it out to get a better idea of structure
toc = self.metadata['toc']
parent_list = []
for i in toc:
item = QtGui.QStandardItem()
item.setText(i[1])
item.setData(i[2], QtCore.Qt.UserRole)
item.setData(i[1], QtCore.Qt.UserRole + 1)
current_level = i[0]
if current_level == 1:
self.tocModel.appendRow(item)
parent_list.clear()
parent_list.append(item)
else:
parent_list[current_level - 2].appendRow(item)
try:
next_level = toc[toc.index(i) + 1][0]
if next_level > current_level:
parent_list.append(item)
if next_level < current_level:
level_difference = current_level - next_level
parent_list = parent_list[:-level_difference]
except IndexError:
pass
# This is needed to be able to have the toc Combobox
# jump to the correct position in the book when it is
# first opened
self.main_window.bookToolBar.tocBox.setModel(self.tocModel)
self.main_window.bookToolBar.tocTreeView.expandAll()
def go_fullscreen(self):
# To allow toggles to function
# properly after the fullscreening
@@ -434,7 +481,7 @@ class Tab(QtWidgets.QWidget):
self.main_window.hide()
if not self.are_we_doing_images_only:
self.hiddenButton.animateClick(100)
self.hiddenButton.animateClick(50)
self.mouse_hide_timer.start(2000)
self.is_fullscreen = True
@@ -472,9 +519,27 @@ class Tab(QtWidgets.QWidget):
self.mouse_hide_timer.start(2000)
self.contentView.setFocus()
def change_chapter_tocBox(self):
chapter_number = self.main_window.bookToolBar.tocBox.currentIndex()
required_content = self.metadata['content'][chapter_number][1]
def set_content(self, required_position, tocBox_readjust=False):
# All content changes must come through here
# This function will decide how to relate
# entries in the toc to the actual content
# Do not allow cycling below page 1
# Required position goes to -1 in double page view
if required_position <= 0:
return
# Set the required page to the corresponding index
# For images this is simply a page number
# For text based books, this is the entire text of the chapter
try:
required_content = self.metadata['content'][required_position - 1]
except IndexError:
return # Do not allow cycling beyond last page
# Update the metadata dictionary to save position
self.metadata['position']['current_chapter'] = required_position
self.metadata['position']['is_read'] = False
if self.are_we_doing_images_only:
self.contentView.loadImage(required_content)
@@ -482,11 +547,68 @@ class Tab(QtWidgets.QWidget):
self.contentView.clear()
self.contentView.setHtml(required_content)
self.contentView.common_functions.load_annotations(chapter_number + 1)
# Set the contentview to look the way God intended
self.main_window.profile_functions.format_contentView()
self.contentView.common_functions.load_annotations(required_position)
def format_view(self, font, font_size, foreground,
background, padding, line_spacing,
text_alignment):
# Change the index of the tocBox. This is manual and each function
# that calls set_position must specify if it needs this adjustment
if tocBox_readjust:
self.set_tocBox_index(required_position, None)
def set_tocBox_index(self, current_position=None, tocBox=None):
# Get current position from the metadata dictionary
# in case it isn't specified
if not current_position:
current_position = self.metadata['position']['current_chapter']
# Just look at the variable names. They're practically sentences.
positions_available_in_toc = [i[2] for i in self.metadata['toc']]
try:
position_reference_index = positions_available_in_toc.index(
current_position)
position_reference = positions_available_in_toc[
position_reference_index]
except ValueError: # No specific corresponding value was found
# Going for nearest preceding neighbor
for count, i in enumerate(positions_available_in_toc):
try:
if (positions_available_in_toc[count] <
current_position <
positions_available_in_toc[count + 1]):
position_reference = i
break
except IndexError: # Set to the last chapter
position_reference = positions_available_in_toc[-1]
# Match the position reference to the corresponding
# index in the QTreeView / QCombobox
try:
matchingIndex = self.tocModel.match(
self.tocModel.index(0, 0),
QtCore.Qt.UserRole,
position_reference,
2, QtCore.Qt.MatchRecursive)[0]
except IndexError:
return
if not tocBox:
tocBox = self.main_window.bookToolBar.tocBox
# The following sets the QCombobox index according
# to the index found above.
tocBox.blockSignals(True)
currentRootModelIndex = tocBox.rootModelIndex()
tocBox.setRootModelIndex(matchingIndex.parent())
tocBox.setCurrentIndex(matchingIndex.row())
tocBox.setRootModelIndex(currentRootModelIndex)
tocBox.blockSignals(False)
def format_view(
self, font, font_size, foreground,
background, padding, line_spacing,
text_alignment):
if self.are_we_doing_images_only:
# Tab color does not need to be set separately in case
@@ -543,14 +665,15 @@ class Tab(QtWidgets.QWidget):
break
def generate_annotation_model(self):
# TODO
# Annotation previews will require creation of a
# QStyledItemDelegate
saved_annotations = self.main_window.settings['annotations']
if not saved_annotations:
return
# Create annotation model
# TODO
# Annotation previews will require creation of a
# QStyledItemDelegate
for i in saved_annotations:
item = QtGui.QStandardItem()
item.setText(i['name'])
@@ -581,7 +704,7 @@ class Tab(QtWidgets.QWidget):
description, chapter, cursor_position, identifier, True)
def add_bookmark_to_model(
self, description, chapter, cursor_position,
self, description, chapter_number, cursor_position,
identifier, new_bookmark=False):
def edit_new_bookmark(parent_item):
@@ -596,7 +719,7 @@ class Tab(QtWidgets.QWidget):
bookmark = QtGui.QStandardItem()
bookmark.setData(False, QtCore.Qt.UserRole + 10) # Is Parent
bookmark.setData(chapter, QtCore.Qt.UserRole) # Chapter name
bookmark.setData(chapter_number, QtCore.Qt.UserRole) # Chapter number
bookmark.setData(cursor_position, QtCore.Qt.UserRole + 1) # Cursor Position
bookmark.setData(identifier, QtCore.Qt.UserRole + 2) # Identifier
bookmark.setData(description, QtCore.Qt.DisplayRole) # Description
@@ -604,21 +727,20 @@ class Tab(QtWidgets.QWidget):
for i in range(self.bookmarkModel.rowCount()):
parentIndex = self.bookmarkModel.index(i, 0)
parent_chapter = parentIndex.data(QtCore.Qt.UserRole)
if parent_chapter == chapter:
if parent_chapter == chapter_number:
bookmarkParent = self.bookmarkModel.itemFromIndex(parentIndex)
bookmarkParent.appendRow(bookmark)
if new_bookmark:
edit_new_bookmark(bookmarkParent)
return
# In case no parent item exists
bookmarkParent = QtGui.QStandardItem()
bookmarkParent.setData(True, QtCore.Qt.UserRole + 10) # Is Parent
bookmarkParent.setFlags(bookmarkParent.flags() & ~QtCore.Qt.ItemIsEditable) # Is Editable
chapter_name = self.metadata['content'][chapter - 1][0] # Chapter Name
chapter_name = [i[1] for i in self.metadata['toc'] if i[2] == chapter_number][0]
bookmarkParent.setData(chapter_name, QtCore.Qt.DisplayRole)
bookmarkParent.setData(chapter, QtCore.Qt.UserRole) # Chapter Number
bookmarkParent.setData(chapter_number, QtCore.Qt.UserRole)
bookmarkParent.appendRow(bookmark)
self.bookmarkModel.appendRow(bookmarkParent)
@@ -632,13 +754,13 @@ class Tab(QtWidgets.QWidget):
is_parent = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole + 10)
if is_parent:
chapter_number = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole)
self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter_number - 1)
self.set_content(chapter_number, True)
return
chapter = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole)
cursor_position = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole + 1)
self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter - 1)
self.set_content(chapter, True)
if not self.are_we_doing_images_only:
self.set_cursor_position(cursor_position)
@@ -646,13 +768,14 @@ class Tab(QtWidgets.QWidget):
self.bookmarkModel = QtGui.QStandardItemModel(self)
if self.main_window.settings['toc_with_bookmarks']:
for chapter_number, i in enumerate(self.metadata['content']):
chapterItem = QtGui.QStandardItem()
chapterItem.setData(i[0], QtCore.Qt.DisplayRole) # Display name
chapterItem.setData(chapter_number + 1, QtCore.Qt.UserRole) # Chapter Number
chapterItem.setData(True, QtCore.Qt.UserRole + 10) # Is Parent
chapterItem.setFlags(chapterItem.flags() & ~QtCore.Qt.ItemIsEditable) # Is Editable
self.bookmarkModel.appendRow(chapterItem)
pass
# for chapter_number, i in enumerate(self.metadata['content']):
# chapterItem = QtGui.QStandardItem()
# chapterItem.setData(i[0], QtCore.Qt.DisplayRole) # Display name
# chapterItem.setData(chapter_number + 1, QtCore.Qt.UserRole) # Chapter Number
# chapterItem.setData(True, QtCore.Qt.UserRole + 10) # Is Parent
# chapterItem.setFlags(chapterItem.flags() & ~QtCore.Qt.ItemIsEditable) # Is Editable
# self.bookmarkModel.appendRow(chapterItem)
for i in self.metadata['bookmarks'].items():
description = i[1]['description']
@@ -708,10 +831,20 @@ class Tab(QtWidgets.QWidget):
self.bookmarkModel.removeRow(parent_index.row())
def set_search_options(self):
search_content = (
self.metadata['content'][self.main_window.bookToolBar.tocBox.currentIndex()],)
def generate_title_content_pair(required_chapters):
title_content_list = []
for i in self.metadata['toc']:
if i[2] in required_chapters:
title_content_list.append(
(i[1], self.metadata['content'][i[2] - 1], i[2]))
return title_content_list
# Select either the current chapter or all chapters
# Function name is descriptive
chapter_numbers = (self.metadata['position']['current_chapter'],)
if self.searchBookButton.isChecked():
search_content = self.metadata['content']
chapter_numbers = [i + 1 for i in range(len(self.metadata['content']))]
search_content = generate_title_content_pair(chapter_numbers)
self.searchThread.set_search_options(
search_content,
@@ -727,13 +860,11 @@ class Tab(QtWidgets.QWidget):
parentItem = QtGui.QStandardItem()
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(parentItem)
childItem.setData(False, QtCore.Qt.UserRole) # Is parent?
childItem.setData(chapter_index, QtCore.Qt.UserRole + 1) # Chapter index
childItem.setData(j[3], 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
@@ -743,6 +874,12 @@ class Tab(QtWidgets.QWidget):
self.searchResultsTreeView.setModel(self.searchResultsModel)
self.searchResultsTreeView.expandToDepth(1)
# Reset stylesheet in case something is found
if search_results:
self.searchLineEdit.setStyleSheet(
QtWidgets.QLineEdit.styleSheet(self))
# Or set to Red in case nothing is found
if not search_results and len(self.searchLineEdit.text()) > 2:
self.searchLineEdit.setStyleSheet("QLineEdit {color: red;}")
@@ -773,11 +910,11 @@ class Tab(QtWidgets.QWidget):
if is_parent:
return
chapter_index = self.searchResultsModel.data(index, QtCore.Qt.UserRole + 1)
chapter_number = 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)
self.set_content(chapter_number, True)
if not self.are_we_doing_images_only:
self.set_cursor_position(
cursor_position, len(search_term))