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

2
TODO
View File

@@ -94,6 +94,8 @@ TODO
Colors aren't loaded properly for annotation previews
Last line in QTextBrowser should never be cut off
Something is wrong with image alignment
Scrolling the toc Combobox does nothing
fb2 images need a newline preceding them
Secondary:
Graphical themes

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))