Bookmark creation and navigation, Cleanup

This commit is contained in:
BasioMeusPuga
2018-02-25 22:05:37 +05:30
parent 0b64fc3e8d
commit 7874838550
7 changed files with 112 additions and 42 deletions

7
TODO
View File

@@ -43,17 +43,17 @@ TODO
✓ View and hide toolbar actions in a list ✓ View and hide toolbar actions in a list
✓ Line spacing ✓ Line spacing
✓ Record progress ✓ Record progress
Bookmarks
Set context menu for definitions and the like
Search document using QTextCursor? Search document using QTextCursor?
Use embedded fonts
Cache multiple images Cache multiple images
Graphical themes Graphical themes
Comic view keyboard shortcuts Comic view keyboard shortcuts
Comic view modes Comic view modes
Continuous paging Continuous paging
Double pages Double pages
Bookmarks
Pagination Pagination
Set context menu for definitions and the like Use embedded fonts
Scrolling: Smooth / By Line Scrolling: Smooth / By Line
Filetypes: Filetypes:
✓ cbz, cbr support ✓ cbz, cbr support
@@ -73,3 +73,4 @@ TODO
Shift to logging instead of print statements Shift to logging instead of print statements
Bugs: Bugs:
If there are files open and the database is deleted, TypeErrors result If there are files open and the database is deleted, TypeErrors result
Closing a fullscreened contentView does not save settings

View File

@@ -334,7 +334,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
item.setData(True, QtCore.Qt.UserRole + 8) item.setData(True, QtCore.Qt.UserRole + 8)
def test_function(self): def test_function(self):
print('Caesar si viveret, ad remum dareris') # print('Caesar si viveret, ad remum dareris')
if self.tabWidget.currentIndex() != 0:
self.tabWidget.widget(self.tabWidget.currentIndex()).add_bookmark()
def resizeEvent(self, event=None): def resizeEvent(self, event=None):
if event: if event:
@@ -376,7 +378,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Remember file addition modality # Remember file addition modality
# If a file is added from here, it should not be removed # If a file is added from here, it should not be removed
# from the libary in case of a database refresh # from the libary in case of a database refresh
# Individually added files are not subject to library filtering
opened_files = QtWidgets.QFileDialog.getOpenFileNames( opened_files = QtWidgets.QFileDialog.getOpenFileNames(
self, 'Open file', self.settings['last_open_path'], self, 'Open file', self.settings['last_open_path'],

View File

@@ -19,7 +19,6 @@
import os import os
import pickle import pickle
import sqlite3 import sqlite3
from PyQt5 import QtCore from PyQt5 import QtCore
@@ -163,28 +162,30 @@ class DatabaseFunctions:
return None return None
except (KeyError, sqlite3.OperationalError): except (KeyError, sqlite3.OperationalError):
print('SQLite is in rebellion, Commander') print('Commander, SQLite is in rebellion @ data fetching handling')
self.close_database() self.close_database()
def modify_position(self, hash_position_last_accessed): def modify_positional_data(self, positional_data):
for i in hash_position_last_accessed: for i in positional_data:
file_hash = i[0] file_hash = i[0]
position = i[1] position = i[1]
last_accessed = i[2] last_accessed = i[2]
bookmarks = i[3]
position_bin = sqlite3.Binary(pickle.dumps(position)) position_bin = sqlite3.Binary(pickle.dumps(position))
last_accessed_bin = sqlite3.Binary(pickle.dumps(last_accessed)) last_accessed_bin = sqlite3.Binary(pickle.dumps(last_accessed))
bookmarks_bin = sqlite3.Binary(pickle.dumps(bookmarks))
sql_command = ( sql_command = (
"UPDATE books SET Position = ?, LastAccessed = ? WHERE Hash = ?") "UPDATE books SET Position = ?, LastAccessed = ?, Bookmarks = ? WHERE Hash = ?")
try: try:
self.database.execute( self.database.execute(
sql_command, sql_command,
[position_bin, last_accessed_bin, file_hash]) [position_bin, last_accessed_bin, bookmarks_bin, file_hash])
except sqlite3.OperationalError: except sqlite3.OperationalError:
print('SQLite is in rebellion, Commander') print('Commander, SQLite is in rebellion @ positional data handling')
return return
self.database.commit() self.database.commit()

View File

@@ -27,12 +27,12 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
super(ItemProxyModel, self).__init__(parent) super(ItemProxyModel, self).__init__(parent)
self.filter_text = None self.filter_text = None
self.active_library_filters = None self.active_library_filters = None
self.sorting_position = None self.sorting_box_position = None
def setFilterParams(self, filter_text, active_library_filters, sorting_position): def setFilterParams(self, filter_text, active_library_filters, sorting_box_position):
self.filter_text = filter_text self.filter_text = filter_text
self.active_library_filters = [i.lower() for i in active_library_filters] self.active_library_filters = [i.lower() for i in active_library_filters]
self.sorting_position = sorting_position self.sorting_box_position = sorting_box_position
def filterAcceptsRow(self, row, parent): def filterAcceptsRow(self, row, parent):
model = self.sourceModel() model = self.sourceModel()
@@ -46,7 +46,8 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11) directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12) last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12)
if self.sorting_position == 4 and not last_accessed: # Hide untouched files when sorting by last accessed
if self.sorting_box_position == 4 and not last_accessed:
return False return False
if self.active_library_filters: if self.active_library_filters:

View File

@@ -110,13 +110,14 @@ class BookSorter:
def database_entry_for_book(self, file_hash): def database_entry_for_book(self, file_hash):
database_return = database.DatabaseFunctions( database_return = database.DatabaseFunctions(
self.database_path).fetch_data( self.database_path).fetch_data(
('DateAdded', 'Position', 'Bookmarks'), ('Position', 'Bookmarks'),
'books', 'books',
{'Hash': file_hash}, {'Hash': file_hash},
'EQUALS')[0] 'EQUALS')[0]
book_data = [] book_data = []
for i in database_return: for i in database_return:
# All of these values are pickled and stored
if i: if i:
book_data.append(pickle.loads(i)) book_data.append(pickle.loads(i))
else: else:
@@ -214,12 +215,9 @@ class BookSorter:
content['Invalid'] = 'Possible Parse Error' content['Invalid'] = 'Possible Parse Error'
book_data = self.database_entry_for_book(file_md5) book_data = self.database_entry_for_book(file_md5)
position = book_data[0]
bookmarks = book_data[1]
date_added = book_data[0]
position = book_data[1]
bookmarks = book_data[2]
this_book[file_md5]['date_added'] = date_added
this_book[file_md5]['position'] = position this_book[file_md5]['position'] = position
this_book[file_md5]['bookmarks'] = bookmarks this_book[file_md5]['bookmarks'] = bookmarks
this_book[file_md5]['content'] = content this_book[file_md5]['content'] = content

View File

@@ -37,11 +37,13 @@ class BackGroundTabUpdate(QtCore.QThread):
file_hash = i['hash'] file_hash = i['hash']
position = i['position'] position = i['position']
last_accessed = i['last_accessed'] last_accessed = i['last_accessed']
bookmarks = i['bookmarks']
hash_position_pairs.append([file_hash, position, last_accessed]) hash_position_pairs.append(
[file_hash, position, last_accessed, bookmarks])
database.DatabaseFunctions( database.DatabaseFunctions(
self.database_path).modify_position(hash_position_pairs) self.database_path).modify_positional_data(hash_position_pairs)
class BackGroundBookAddition(QtCore.QThread): class BackGroundBookAddition(QtCore.QThread):

View File

@@ -386,7 +386,6 @@ class Tab(QtWidgets.QWidget):
self.metadata['last_accessed'] = QtCore.QDateTime().currentDateTime() self.metadata['last_accessed'] = QtCore.QDateTime().currentDateTime()
position = self.metadata['position'] position = self.metadata['position']
if position: if position:
current_chapter = position['current_chapter'] current_chapter = position['current_chapter']
else: else:
@@ -420,10 +419,10 @@ class Tab(QtWidgets.QWidget):
self.contentView.setHtml(chapter_content) self.contentView.setHtml(chapter_content)
self.contentView.setReadOnly(True) self.contentView.setReadOnly(True)
temp_hidden_button = QtWidgets.QToolButton(self) tempHiddenButton = QtWidgets.QToolButton(self)
temp_hidden_button.setVisible(False) tempHiddenButton.setVisible(False)
temp_hidden_button.clicked.connect(self.set_scroll_value) tempHiddenButton.clicked.connect(self.set_scroll_value)
temp_hidden_button.animateClick(100) tempHiddenButton.animateClick(100)
# The following are common to both the text browser and # The following are common to both the text browser and
# the graphics view # the graphics view
@@ -437,12 +436,18 @@ class Tab(QtWidgets.QWidget):
self.dockWidget = QtWidgets.QDockWidget(self) self.dockWidget = QtWidgets.QDockWidget(self)
self.dockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable) self.dockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
self.dockWidget.setFloating(False) self.dockWidget.setFloating(False)
self.dockListWidget = QtWidgets.QListWidget()
self.dockListWidget.setResizeMode(QtWidgets.QListWidget.Adjust)
self.dockListWidget.setMaximumWidth(350)
self.dockWidget.setWidget(self.dockListWidget)
self.dockWidget.hide() self.dockWidget.hide()
self.dockListView = QtWidgets.QListView(self.dockWidget)
self.dockListView.setResizeMode(QtWidgets.QListWidget.Adjust)
self.dockListView.setMaximumWidth(350)
self.dockListView.clicked.connect(self.navigate_to_bookmark)
self.dockWidget.setWidget(self.dockListView)
self.bookmark_model = QtGui.QStandardItemModel()
self.generate_bookmark_model()
self.dockListView.setModel(self.bookmark_model)
self.generate_keyboard_shortcuts() self.generate_keyboard_shortcuts()
self.horzLayout.addWidget(self.contentView) self.horzLayout.addWidget(self.contentView)
@@ -470,21 +475,25 @@ class Tab(QtWidgets.QWidget):
self.window().lib_ref.view_model.setData( self.window().lib_ref.view_model.setData(
matching_item[0], self.metadata['last_accessed'], QtCore.Qt.UserRole + 12) matching_item[0], self.metadata['last_accessed'], QtCore.Qt.UserRole + 12)
def set_scroll_value(self, switch_widgets=True): def set_scroll_value(self, switch_widgets=True, search_data=None):
if switch_widgets: if switch_widgets:
previous_widget = self.window().tabWidget.currentWidget() previous_widget = self.window().tabWidget.currentWidget()
self.window().tabWidget.setCurrentWidget(self) self.window().tabWidget.setCurrentWidget(self)
scroll_position = ( scroll_value = self.metadata['position']['scroll_value']
self.metadata['position']['scroll_value'] * if search_data:
self.contentView.verticalScrollBar().maximum()) scroll_value = search_data[0]
# Scroll a little ahead # Scroll a little ahead
# This avoids confusion with potentially duplicate phrases # This avoids confusion with potentially duplicate phrases
# And the found result is at the top of the window # And the found result is at the top of the window
self.contentView.verticalScrollBar().setValue(scroll_position * 1.1) scroll_position = scroll_value * self.contentView.verticalScrollBar().maximum() * 1.1
self.contentView.verticalScrollBar().setValue(scroll_position)
last_visible_text = self.metadata['position']['last_visible_text'] last_visible_text = self.metadata['position']['last_visible_text']
if search_data:
last_visible_text = search_data[1]
if last_visible_text: if last_visible_text:
self.contentView.find(last_visible_text) self.contentView.find(last_visible_text)
@@ -501,7 +510,6 @@ class Tab(QtWidgets.QWidget):
# Calculate lines to incorporate into progress # Calculate lines to incorporate into progress
self.metadata['position'] = { self.metadata['position'] = {
'current_chapter': 1, 'current_chapter': 1,
'current_line': 0,
'total_chapters': total_chapters, 'total_chapters': total_chapters,
'scroll_value': 0, 'scroll_value': 0,
'last_visible_text': None} 'last_visible_text': None}
@@ -579,6 +587,10 @@ class Tab(QtWidgets.QWidget):
block_format.setLineHeight( block_format.setLineHeight(
line_spacing, QtGui.QTextBlockFormat.ProportionalHeight) line_spacing, QtGui.QTextBlockFormat.ProportionalHeight)
# TODO
# Give options for alignment
# block_format.setAlignment(QtCore.Qt.AlignJustify)
# Also for padding # Also for padding
# Using setViewPortMargins for this disables scrolling in the margins # Using setViewPortMargins for this disables scrolling in the margins
block_format.setLeftMargin(padding) block_format.setLeftMargin(padding)
@@ -605,6 +617,47 @@ class Tab(QtWidgets.QWidget):
else: else:
self.dockWidget.show() self.dockWidget.show()
def add_bookmark(self):
chapter, scroll_position, visible_text = self.contentView.record_scroll_position(True)
description = 'New bookmark'
search_data = (scroll_position, visible_text)
self.metadata['bookmarks'].append([
chapter, search_data, description])
self.add_bookmark_to_model(description, chapter, search_data)
def generate_bookmark_model(self):
bookmarks = self.metadata['bookmarks']
if not bookmarks:
self.metadata['bookmarks'] = []
return
# TODO
# Replace this with proxy model sorting
bookmarks.sort(key=lambda x: x[0])
for i in bookmarks:
self.add_bookmark_to_model(i[2], i[0], i[1])
def add_bookmark_to_model(self, description, chapter, search_data):
bookmark = QtGui.QStandardItem()
bookmark.setData(description, QtCore.Qt.DisplayRole)
bookmark.setData(chapter, QtCore.Qt.UserRole)
bookmark.setData(search_data, QtCore.Qt.UserRole + 1)
self.bookmark_model.appendRow(bookmark)
def navigate_to_bookmark(self, index):
if not index.isValid():
return
chapter = self.bookmark_model.data(index, QtCore.Qt.UserRole)
search_data = self.bookmark_model.data(index, QtCore.Qt.UserRole + 1)
self.window().bookToolBar.tocBox.setCurrentIndex(chapter - 1)
self.set_scroll_value(False, search_data)
def hide_mouse(self): def hide_mouse(self):
self.contentView.setCursor(QtCore.Qt.BlankCursor) self.contentView.setCursor(QtCore.Qt.BlankCursor)
@@ -629,11 +682,18 @@ class PliantQGraphicsView(QtWidgets.QGraphicsView):
self.image_pixmap = None self.image_pixmap = None
self.ignore_wheel_event = False self.ignore_wheel_event = False
self.ignore_wheel_event_number = 0 self.ignore_wheel_event_number = 0
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self.common_functions = PliantWidgetsCommonFunctions( self.common_functions = PliantWidgetsCommonFunctions(
self, self.main_window) self, self.main_window)
self.setMouseTracking(True) self.setMouseTracking(True)
def loadImage(self, image_path): def loadImage(self, image_path):
# TODO
# Cache 4 images
# For single page view: 1 before, 2 after
# For double page view: 1 before, 1 after
# Image panning with mouse
self.image_pixmap = QtGui.QPixmap() self.image_pixmap = QtGui.QPixmap()
self.image_pixmap.load(image_path) self.image_pixmap.load(image_path)
self.resizeEvent() self.resizeEvent()
@@ -731,7 +791,7 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
else: else:
QtWidgets.QTextEdit.keyPressEvent(self, event) QtWidgets.QTextEdit.keyPressEvent(self, event)
def record_scroll_position(self): def record_scroll_position(self, return_as_bookmark=False):
vertical = self.verticalScrollBar().value() vertical = self.verticalScrollBar().value()
maximum = self.verticalScrollBar().maximum() maximum = self.verticalScrollBar().maximum()
@@ -747,7 +807,13 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
if len(visible_text) > 50: if len(visible_text) > 50:
visible_text = visible_text[:51] visible_text = visible_text[:51]
self.parent.metadata['position']['last_visible_text'] = visible_text
if return_as_bookmark:
return (self.parent.metadata['position']['current_chapter'],
self.parent.metadata['position']['scroll_value'],
visible_text)
else:
self.parent.metadata['position']['last_visible_text'] = visible_text
# def mouseMoveEvent(self, event): # def mouseMoveEvent(self, event):
# TODO # TODO