Overhaul TOC generation and navigation
This commit is contained in:
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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']
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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):
|
||||
|
@@ -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
|
||||
|
@@ -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(
|
||||
|
@@ -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)
|
||||
|
@@ -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))
|
||||
|
Reference in New Issue
Block a user