Shift to tree view for bookmarks
Cleanup
This commit is contained in:
8
TODO
8
TODO
@@ -78,7 +78,8 @@ TODO
|
|||||||
Limit the extra files produced by KindleUnpack
|
Limit the extra files produced by KindleUnpack
|
||||||
Have them save to memory
|
Have them save to memory
|
||||||
✓ fb2 support
|
✓ fb2 support
|
||||||
Images need to show up in their placeholders
|
✓ Images need to show up in their placeholders
|
||||||
|
djvu support
|
||||||
Other:
|
Other:
|
||||||
✓ Define every widget in code
|
✓ Define every widget in code
|
||||||
Bugs:
|
Bugs:
|
||||||
@@ -86,6 +87,9 @@ TODO
|
|||||||
Clean up 'switch' page layout
|
Clean up 'switch' page layout
|
||||||
Colors aren't loaded properly for annotation previews
|
Colors aren't loaded properly for annotation previews
|
||||||
Cover page shouldn't be scolled midway
|
Cover page shouldn't be scolled midway
|
||||||
|
Docks
|
||||||
|
Fullscreening should keep dock visible
|
||||||
|
Closing a book keeps dock show button clicked
|
||||||
|
|
||||||
Secondary:
|
Secondary:
|
||||||
Graphical themes
|
Graphical themes
|
||||||
@@ -99,7 +103,7 @@ TODO
|
|||||||
Use embedded fonts + CSS
|
Use embedded fonts + CSS
|
||||||
Scrolling: Smooth / By Line
|
Scrolling: Smooth / By Line
|
||||||
Shift to logging instead of print statements
|
Shift to logging instead of print statements
|
||||||
txt, doc, chm, djvu support
|
txt, doc, chm support
|
||||||
Include icons for filetype emblems
|
Include icons for filetype emblems
|
||||||
Comic view modes
|
Comic view modes
|
||||||
Continuous paging
|
Continuous paging
|
||||||
|
@@ -66,31 +66,3 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
|
|||||||
x_draw = option.rect.bottomRight().x() - 30
|
x_draw = option.rect.bottomRight().x() - 30
|
||||||
y_draw = option.rect.bottomRight().y() - 35
|
y_draw = option.rect.bottomRight().y() - 35
|
||||||
painter.drawPixmap(x_draw, y_draw, read_icon)
|
painter.drawPixmap(x_draw, y_draw, read_icon)
|
||||||
|
|
||||||
|
|
||||||
class BookmarkDelegate(QtWidgets.QStyledItemDelegate):
|
|
||||||
def __init__(self, main_window, parent=None):
|
|
||||||
super(BookmarkDelegate, self).__init__()
|
|
||||||
self.main_window = main_window
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
def sizeHint(self, *args):
|
|
||||||
dockwidget_width = self.parent.width() - 20
|
|
||||||
return QtCore.QSize(dockwidget_width, 50)
|
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
|
||||||
# TODO
|
|
||||||
# Alignment of the painted item
|
|
||||||
|
|
||||||
option = option.__class__(option)
|
|
||||||
|
|
||||||
chapter_index = index.data(QtCore.Qt.UserRole)
|
|
||||||
chapter_name = self.main_window.bookToolBar.tocBox.itemText(chapter_index - 1)
|
|
||||||
if len(chapter_name) > 25:
|
|
||||||
chapter_name = chapter_name[:25] + '...'
|
|
||||||
|
|
||||||
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
|
|
||||||
painter.drawText(
|
|
||||||
option.rect,
|
|
||||||
QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight | QtCore.Qt.TextWordWrap,
|
|
||||||
' ' + chapter_name)
|
|
||||||
|
@@ -31,7 +31,8 @@ class FB2:
|
|||||||
def read_fb2(self):
|
def read_fb2(self):
|
||||||
try:
|
try:
|
||||||
if self.filename.endswith('.fb2.zip'):
|
if self.filename.endswith('.fb2.zip'):
|
||||||
this_book = zipfile.ZipFile(self.filename, mode='r', allowZip64=True)
|
this_book = zipfile.ZipFile(
|
||||||
|
self.filename, mode='r', allowZip64=True)
|
||||||
for i in this_book.filelist:
|
for i in this_book.filelist:
|
||||||
if os.path.splitext(i.filename)[1] == '.fb2':
|
if os.path.splitext(i.filename)[1] == '.fb2':
|
||||||
book_text = this_book.read(i.filename)
|
book_text = this_book.read(i.filename)
|
||||||
@@ -42,7 +43,7 @@ class FB2:
|
|||||||
|
|
||||||
self.xml = BeautifulSoup(book_text, 'lxml')
|
self.xml = BeautifulSoup(book_text, 'lxml')
|
||||||
self.generate_book_metadata()
|
self.generate_book_metadata()
|
||||||
except ValueError: # Not specifying an exception type here may be justified
|
except: # Not specifying an exception type here may be justified
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -60,7 +61,8 @@ class FB2:
|
|||||||
self.book['title'] = os.path.splitext(
|
self.book['title'] = os.path.splitext(
|
||||||
os.path.basename(self.filename))[0]
|
os.path.basename(self.filename))[0]
|
||||||
|
|
||||||
self.book['author'] = all_tags.find('author').getText(separator=' ').replace('\n', ' ')
|
self.book['author'] = all_tags.find(
|
||||||
|
'author').getText(separator=' ').replace('\n', ' ')
|
||||||
if self.book['author'] == '' or self.book['author'] is None:
|
if self.book['author'] == '' or self.book['author'] is None:
|
||||||
self.book['author'] = 'Unknown'
|
self.book['author'] = 'Unknown'
|
||||||
|
|
||||||
@@ -104,7 +106,8 @@ class FB2:
|
|||||||
replacement_string = f'<img src=\"{image_path}\"'
|
replacement_string = f'<img src=\"{image_path}\"'
|
||||||
|
|
||||||
for j in self.book['book_list']:
|
for j in self.book['book_list']:
|
||||||
j[1] = j[1].replace(image_string, replacement_string)
|
j[1] = j[1].replace(
|
||||||
|
image_string, replacement_string)
|
||||||
try:
|
try:
|
||||||
image_data = base64.decodebytes(i.text.encode())
|
image_data = base64.decodebytes(i.text.encode())
|
||||||
with open(image_path, 'wb') as outimage:
|
with open(image_path, 'wb') as outimage:
|
||||||
|
@@ -163,7 +163,7 @@ class BookSorter:
|
|||||||
self.queue.put(filename)
|
self.queue.put(filename)
|
||||||
|
|
||||||
# This should not get triggered in reading mode
|
# This should not get triggered in reading mode
|
||||||
# IF the file is NOT being loaded into the reader,
|
# IF the file is NOT being loaded into the reader
|
||||||
|
|
||||||
# Do not allow addition in case the file
|
# Do not allow addition in case the file
|
||||||
# is already in the database and it remains at its original path
|
# is already in the database and it remains at its original path
|
||||||
|
@@ -25,7 +25,6 @@ import uuid
|
|||||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
|
|
||||||
from lector.models import BookmarkProxyModel
|
from lector.models import BookmarkProxyModel
|
||||||
from lector.delegates import BookmarkDelegate
|
|
||||||
from lector.sorter import resize_image
|
from lector.sorter import resize_image
|
||||||
from lector.contentwidgets import PliantQGraphicsView, PliantQTextBrowser
|
from lector.contentwidgets import PliantQGraphicsView, PliantQTextBrowser
|
||||||
|
|
||||||
@@ -155,17 +154,14 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.bookmarkDock.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
|
self.bookmarkDock.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
|
||||||
self.bookmarkDock.hide()
|
self.bookmarkDock.hide()
|
||||||
|
|
||||||
self.bookmarkListView = QtWidgets.QListView(self.bookmarkDock)
|
self.bookmarkTreeView = QtWidgets.QTreeView(self.bookmarkDock)
|
||||||
self.bookmarkListView.setResizeMode(QtWidgets.QListWidget.Adjust)
|
self.bookmarkTreeView.setHeaderHidden(True)
|
||||||
self.bookmarkListView.setMaximumWidth(350)
|
self.bookmarkTreeView.setMaximumWidth(350)
|
||||||
self.bookmarkListView.setItemDelegate(
|
self.bookmarkTreeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
BookmarkDelegate(self.main_window, self.bookmarkListView))
|
self.bookmarkTreeView.customContextMenuRequested.connect(
|
||||||
self.bookmarkListView.setUniformItemSizes(True)
|
|
||||||
self.bookmarkListView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
|
||||||
self.bookmarkListView.customContextMenuRequested.connect(
|
|
||||||
self.generate_bookmark_context_menu)
|
self.generate_bookmark_context_menu)
|
||||||
self.bookmarkListView.clicked.connect(self.navigate_to_bookmark)
|
self.bookmarkTreeView.clicked.connect(self.navigate_to_bookmark)
|
||||||
self.bookmarkDock.setWidget(self.bookmarkListView)
|
self.bookmarkDock.setWidget(self.bookmarkTreeView)
|
||||||
|
|
||||||
self.bookmarkModel = QtGui.QStandardItemModel(self)
|
self.bookmarkModel = QtGui.QStandardItemModel(self)
|
||||||
self.bookmarkProxyModel = BookmarkProxyModel(self)
|
self.bookmarkProxyModel = BookmarkProxyModel(self)
|
||||||
@@ -451,9 +447,6 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.bookmarkDock.show()
|
self.bookmarkDock.show()
|
||||||
|
|
||||||
def add_bookmark(self):
|
def add_bookmark(self):
|
||||||
# TODO
|
|
||||||
# Start dockListView.edit(index) when something new is added
|
|
||||||
|
|
||||||
identifier = uuid.uuid4().hex[:10]
|
identifier = uuid.uuid4().hex[:10]
|
||||||
description = self._translate('Tab', 'New bookmark')
|
description = self._translate('Tab', 'New bookmark')
|
||||||
|
|
||||||
@@ -468,25 +461,55 @@ class Tab(QtWidgets.QWidget):
|
|||||||
'cursor_position': cursor_position,
|
'cursor_position': cursor_position,
|
||||||
'description': description}
|
'description': description}
|
||||||
|
|
||||||
self.add_bookmark_to_model(
|
|
||||||
description, chapter, cursor_position, identifier)
|
|
||||||
self.bookmarkDock.setVisible(True)
|
self.bookmarkDock.setVisible(True)
|
||||||
|
self.add_bookmark_to_model(
|
||||||
|
description, chapter, cursor_position, identifier, True)
|
||||||
|
|
||||||
|
def add_bookmark_to_model(
|
||||||
|
self, description, chapter, cursor_position,
|
||||||
|
identifier, new_bookmark=False):
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
# Start treeview.edit(index) when a new bookmark is added
|
||||||
|
# Expand parent item of newly added bookmark
|
||||||
|
|
||||||
def add_bookmark_to_model(self, description, chapter, cursor_position, identifier):
|
|
||||||
bookmark = QtGui.QStandardItem()
|
bookmark = QtGui.QStandardItem()
|
||||||
bookmark.setData(description, QtCore.Qt.DisplayRole)
|
|
||||||
|
|
||||||
bookmark.setData(chapter, QtCore.Qt.UserRole)
|
bookmark.setData(False, QtCore.Qt.UserRole + 10) # Is Parent
|
||||||
bookmark.setData(cursor_position, QtCore.Qt.UserRole + 1)
|
bookmark.setData(chapter, QtCore.Qt.UserRole) # Chapter name
|
||||||
bookmark.setData(identifier, QtCore.Qt.UserRole + 2)
|
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
|
||||||
|
|
||||||
self.bookmarkModel.appendRow(bookmark)
|
for i in range(self.bookmarkModel.rowCount()):
|
||||||
self.update_bookmark_proxy_model()
|
parentIndex = self.bookmarkModel.index(i, 0)
|
||||||
|
parent_chapter = parentIndex.data(QtCore.Qt.UserRole)
|
||||||
|
if parent_chapter == chapter:
|
||||||
|
parentItem = self.bookmarkModel.itemFromIndex(parentIndex)
|
||||||
|
parentItem.appendRow(bookmark)
|
||||||
|
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)
|
||||||
|
chapter_name = self.metadata['content'][chapter - 1][0]
|
||||||
|
bookmarkParent.setData(chapter_name, QtCore.Qt.DisplayRole)
|
||||||
|
bookmarkParent.setData(chapter, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
bookmarkParent.appendRow(bookmark)
|
||||||
|
self.bookmarkModel.appendRow(bookmarkParent)
|
||||||
|
# self.update_bookmark_proxy_model()
|
||||||
|
|
||||||
def navigate_to_bookmark(self, index):
|
def navigate_to_bookmark(self, index):
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
is_parent = self.bookmarkProxyModel.data(
|
||||||
|
index, QtCore.Qt.UserRole + 10)
|
||||||
|
if is_parent:
|
||||||
|
return
|
||||||
|
|
||||||
chapter = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole)
|
chapter = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole)
|
||||||
cursor_position = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole + 1)
|
cursor_position = self.bookmarkProxyModel.data(index, QtCore.Qt.UserRole + 1)
|
||||||
|
|
||||||
@@ -495,23 +518,14 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.set_cursor_position(cursor_position)
|
self.set_cursor_position(cursor_position)
|
||||||
|
|
||||||
def generate_bookmark_model(self):
|
def generate_bookmark_model(self):
|
||||||
# TODO
|
self.bookmarkModel = QtGui.QStandardItemModel(self)
|
||||||
# Sorting is not working correctly
|
|
||||||
|
|
||||||
try:
|
|
||||||
for i in self.metadata['bookmarks'].items():
|
for i in self.metadata['bookmarks'].items():
|
||||||
|
description = i[1]['description']
|
||||||
|
chapter = i[1]['chapter']
|
||||||
|
cursor_position = i[1]['cursor_position']
|
||||||
|
identifier = i[0]
|
||||||
self.add_bookmark_to_model(
|
self.add_bookmark_to_model(
|
||||||
i[1]['description'],
|
description, chapter, cursor_position, identifier)
|
||||||
i[1]['chapter'],
|
|
||||||
i[1]['cursor_position'],
|
|
||||||
i[0])
|
|
||||||
except KeyError:
|
|
||||||
title = self.metadata['title']
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
# Delete the bookmarks entry for this file
|
|
||||||
print(f'Database: Bookmark error for {title}. Recommend delete entry.')
|
|
||||||
return
|
|
||||||
|
|
||||||
self.generate_bookmark_proxy_model()
|
self.generate_bookmark_proxy_model()
|
||||||
|
|
||||||
@@ -519,9 +533,14 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.bookmarkProxyModel.setSourceModel(self.bookmarkModel)
|
self.bookmarkProxyModel.setSourceModel(self.bookmarkModel)
|
||||||
self.bookmarkProxyModel.setSortCaseSensitivity(False)
|
self.bookmarkProxyModel.setSortCaseSensitivity(False)
|
||||||
self.bookmarkProxyModel.setSortRole(QtCore.Qt.UserRole)
|
self.bookmarkProxyModel.setSortRole(QtCore.Qt.UserRole)
|
||||||
self.bookmarkListView.setModel(self.bookmarkProxyModel)
|
self.bookmarkProxyModel.sort(0)
|
||||||
|
self.bookmarkTreeView.setModel(self.bookmarkProxyModel)
|
||||||
|
|
||||||
def update_bookmark_proxy_model(self):
|
def update_bookmark_proxy_model(self):
|
||||||
|
# TODO
|
||||||
|
# This isn't being called currently
|
||||||
|
# See if there's any rationale for keeping it / removing it
|
||||||
|
|
||||||
self.bookmarkProxyModel.invalidateFilter()
|
self.bookmarkProxyModel.invalidateFilter()
|
||||||
self.bookmarkProxyModel.setFilterParams(
|
self.bookmarkProxyModel.setFilterParams(
|
||||||
self.main_window.bookToolBar.searchBar.text())
|
self.main_window.bookToolBar.searchBar.text())
|
||||||
@@ -529,10 +548,15 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.main_window.bookToolBar.searchBar.text())
|
self.main_window.bookToolBar.searchBar.text())
|
||||||
|
|
||||||
def generate_bookmark_context_menu(self, position):
|
def generate_bookmark_context_menu(self, position):
|
||||||
index = self.bookmarkListView.indexAt(position)
|
index = self.bookmarkTreeView.indexAt(position)
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
is_parent = self.bookmarkProxyModel.data(
|
||||||
|
index, QtCore.Qt.UserRole + 10)
|
||||||
|
if is_parent:
|
||||||
|
return
|
||||||
|
|
||||||
bookmarkMenu = QtWidgets.QMenu()
|
bookmarkMenu = QtWidgets.QMenu()
|
||||||
editAction = bookmarkMenu.addAction(
|
editAction = bookmarkMenu.addAction(
|
||||||
self.main_window.QImageFactory.get_image('edit-rename'),
|
self.main_window.QImageFactory.get_image('edit-rename'),
|
||||||
@@ -542,17 +566,21 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self._translate('Tab', 'Delete'))
|
self._translate('Tab', 'Delete'))
|
||||||
|
|
||||||
action = bookmarkMenu.exec_(
|
action = bookmarkMenu.exec_(
|
||||||
self.bookmarkListView.mapToGlobal(position))
|
self.bookmarkTreeView.mapToGlobal(position))
|
||||||
|
|
||||||
if action == editAction:
|
if action == editAction:
|
||||||
self.bookmarkListView.edit(index)
|
self.bookmarkTreeView.edit(index)
|
||||||
|
|
||||||
if action == deleteAction:
|
if action == deleteAction:
|
||||||
row = index.row()
|
# TODO
|
||||||
delete_uuid = self.bookmarkModel.item(row).data(QtCore.Qt.UserRole + 2)
|
# Deletion that doesn't need to generate the whole model again
|
||||||
|
|
||||||
|
source_index = self.bookmarkProxyModel.mapToSource(index)
|
||||||
|
delete_uuid = self.bookmarkModel.data(
|
||||||
|
source_index, QtCore.Qt.UserRole + 2)
|
||||||
|
|
||||||
self.metadata['bookmarks'].pop(delete_uuid)
|
self.metadata['bookmarks'].pop(delete_uuid)
|
||||||
self.bookmarkModel.removeRow(index.row())
|
self.generate_bookmark_model()
|
||||||
|
|
||||||
def hide_mouse(self):
|
def hide_mouse(self):
|
||||||
self.contentView.viewport().setCursor(QtCore.Qt.BlankCursor)
|
self.contentView.viewport().setCursor(QtCore.Qt.BlankCursor)
|
||||||
|
Reference in New Issue
Block a user