Position setting should work all the time now
Learn not to swear so much at the screen Cover icons in the tab bar Shift Scan Library button from the Library tab to the Library toolbar
This commit is contained in:
5
TODO
5
TODO
@@ -58,6 +58,8 @@ TODO
|
|||||||
✓ Comic view keyboard shortcuts
|
✓ Comic view keyboard shortcuts
|
||||||
✓ Comic view context menu
|
✓ Comic view context menu
|
||||||
✓ Make the bookmark dock float over the reading area
|
✓ Make the bookmark dock float over the reading area
|
||||||
|
✓ Spacebar should not cut off lines at the top
|
||||||
|
Track open bookmark windows so they can be closed quickly at exit
|
||||||
Adjust key navigation according to viewport dimensions
|
Adjust key navigation according to viewport dimensions
|
||||||
Search document using QTextCursor
|
Search document using QTextCursor
|
||||||
Filetypes:
|
Filetypes:
|
||||||
@@ -74,6 +76,8 @@ TODO
|
|||||||
✓ Define every widget in code
|
✓ Define every widget in code
|
||||||
Bugs:
|
Bugs:
|
||||||
Deselecting all directories in the settings dialog also filters out manually added books
|
Deselecting all directories in the settings dialog also filters out manually added books
|
||||||
|
Only one tab has its scroll position set when opening multiple books @ startup
|
||||||
|
It's the one that has focus when application starts and ends
|
||||||
|
|
||||||
Secondary:
|
Secondary:
|
||||||
Annotations
|
Annotations
|
||||||
@@ -86,7 +90,6 @@ TODO
|
|||||||
Pagination
|
Pagination
|
||||||
Use embedded fonts + CSS
|
Use embedded fonts + CSS
|
||||||
Scrolling: Smooth / By Line
|
Scrolling: Smooth / By Line
|
||||||
Spacebar should not cut off lines at the top
|
|
||||||
Shift to logging instead of print statements
|
Shift to logging instead of print statements
|
||||||
txt, doc, chm, djvu, fb2 support
|
txt, doc, chm, djvu, fb2 support
|
||||||
Include icons for filetype emblems
|
Include icons for filetype emblems
|
||||||
|
@@ -155,6 +155,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.libraryToolBar.deleteButton.triggered.connect(self.delete_books)
|
self.libraryToolBar.deleteButton.triggered.connect(self.delete_books)
|
||||||
self.libraryToolBar.coverViewButton.triggered.connect(self.switch_library_view)
|
self.libraryToolBar.coverViewButton.triggered.connect(self.switch_library_view)
|
||||||
self.libraryToolBar.tableViewButton.triggered.connect(self.switch_library_view)
|
self.libraryToolBar.tableViewButton.triggered.connect(self.switch_library_view)
|
||||||
|
self.libraryToolBar.reloadLibraryButton.triggered.connect(
|
||||||
|
self.settingsDialog.start_library_scan)
|
||||||
self.libraryToolBar.colorButton.triggered.connect(self.get_color)
|
self.libraryToolBar.colorButton.triggered.connect(self.get_color)
|
||||||
self.libraryToolBar.settingsButton.triggered.connect(self.show_settings)
|
self.libraryToolBar.settingsButton.triggered.connect(self.show_settings)
|
||||||
self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels)
|
self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels)
|
||||||
@@ -218,16 +220,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
|
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
|
||||||
print('Available parsers: ' + self.available_parsers)
|
print('Available parsers: ' + self.available_parsers)
|
||||||
|
|
||||||
# The library refresh button on the Library tab
|
# The Library tab gets no button
|
||||||
self.reloadLibrary.setFlat(True)
|
|
||||||
self.reloadLibrary.setIcon(self.QImageFactory.get_image('reload'))
|
|
||||||
self.reloadLibrary.setObjectName('reloadLibrary')
|
|
||||||
self.reloadLibrary.setToolTip(self._translate('Main_UI', 'Scan library'))
|
|
||||||
self.reloadLibrary.clicked.connect(self.settingsDialog.start_library_scan)
|
|
||||||
|
|
||||||
self.tabWidget.tabBar().setTabButton(
|
self.tabWidget.tabBar().setTabButton(
|
||||||
0, QtWidgets.QTabBar.RightSide, self.reloadLibrary)
|
0, QtWidgets.QTabBar.RightSide, None)
|
||||||
self.tabWidget.tabCloseRequested.connect(self.tab_close)
|
self.tabWidget.tabCloseRequested.connect(self.tab_close)
|
||||||
|
self.tabWidget.setTabBarAutoHide(True)
|
||||||
|
|
||||||
# Init display models
|
# Init display models
|
||||||
self.lib_ref.generate_model('build')
|
self.lib_ref.generate_model('build')
|
||||||
@@ -556,7 +553,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.bookToolBar.tocBox.setCurrentIndex(
|
self.bookToolBar.tocBox.setCurrentIndex(
|
||||||
current_position['current_chapter'] - 1)
|
current_position['current_chapter'] - 1)
|
||||||
if not current_metadata['images_only']:
|
if not current_metadata['images_only']:
|
||||||
current_tab.set_scroll_value(True)
|
current_tab.set_cursor_position()
|
||||||
self.bookToolBar.tocBox.blockSignals(False)
|
self.bookToolBar.tocBox.blockSignals(False)
|
||||||
|
|
||||||
self.profile_functions.format_contentView()
|
self.profile_functions.format_contentView()
|
||||||
|
@@ -42,7 +42,8 @@ class DatabaseInit:
|
|||||||
'LastAccessed': 'BLOB',
|
'LastAccessed': 'BLOB',
|
||||||
'Bookmarks': 'BLOB',
|
'Bookmarks': 'BLOB',
|
||||||
'CoverImage': 'BLOB',
|
'CoverImage': 'BLOB',
|
||||||
'Addition': 'TEXT'}
|
'Addition': 'TEXT',
|
||||||
|
'Annotations': 'BLOB'}
|
||||||
|
|
||||||
self.directories_table_columns = {
|
self.directories_table_columns = {
|
||||||
'id': 'INTEGER PRIMARY KEY',
|
'id': 'INTEGER PRIMARY KEY',
|
||||||
@@ -82,7 +83,7 @@ class DatabaseInit:
|
|||||||
for i in self.books_table_columns.items():
|
for i in self.books_table_columns.items():
|
||||||
if i[0] not in database_columns:
|
if i[0] not in database_columns:
|
||||||
commit_required = True
|
commit_required = True
|
||||||
print(f'Database: Adding column {i[0]}')
|
print(f'Database: Adding column "{i[0]}"')
|
||||||
sql_command = f"ALTER TABLE books ADD COLUMN {i[0]} {i[1]}"
|
sql_command = f"ALTER TABLE books ADD COLUMN {i[0]} {i[1]}"
|
||||||
self.database.execute(sql_command)
|
self.database.execute(sql_command)
|
||||||
|
|
||||||
|
@@ -118,7 +118,7 @@ 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(
|
||||||
('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks'),
|
('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks', 'CoverImage'),
|
||||||
'books',
|
'books',
|
||||||
{'Hash': file_hash},
|
{'Hash': file_hash},
|
||||||
'EQUALS')[0]
|
'EQUALS')[0]
|
||||||
@@ -231,11 +231,13 @@ class BookSorter:
|
|||||||
tags = book_data[4]
|
tags = book_data[4]
|
||||||
position = book_data[5]
|
position = book_data[5]
|
||||||
bookmarks = book_data[6]
|
bookmarks = book_data[6]
|
||||||
|
cover = book_data[7]
|
||||||
|
|
||||||
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
|
||||||
this_book[file_md5]['images_only'] = images_only
|
this_book[file_md5]['images_only'] = images_only
|
||||||
|
this_book[file_md5]['cover'] = cover
|
||||||
|
|
||||||
this_book[file_md5]['title'] = title
|
this_book[file_md5]['title'] = title
|
||||||
this_book[file_md5]['author'] = author
|
this_book[file_md5]['author'] = author
|
||||||
|
@@ -376,6 +376,11 @@ class LibraryToolBar(QtWidgets.QToolBar):
|
|||||||
self)
|
self)
|
||||||
self.tableViewButton.setCheckable(True)
|
self.tableViewButton.setCheckable(True)
|
||||||
|
|
||||||
|
self.reloadLibraryButton = QtWidgets.QAction(
|
||||||
|
image_factory.get_image('reload'),
|
||||||
|
self._translate('LibraryToolBar', 'Scan Library'),
|
||||||
|
self)
|
||||||
|
|
||||||
self.libraryFilterButton = QtWidgets.QToolButton(self)
|
self.libraryFilterButton = QtWidgets.QToolButton(self)
|
||||||
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
|
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
|
||||||
self.libraryFilterButton.setText(
|
self.libraryFilterButton.setText(
|
||||||
@@ -396,6 +401,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
|
|||||||
self.addAction(self.coverViewButton)
|
self.addAction(self.coverViewButton)
|
||||||
self.addAction(self.tableViewButton)
|
self.addAction(self.tableViewButton)
|
||||||
self.addSeparator()
|
self.addSeparator()
|
||||||
|
self.addAction(self.reloadLibraryButton)
|
||||||
self.addWidget(self.libraryFilterButton)
|
self.addWidget(self.libraryFilterButton)
|
||||||
self.addSeparator()
|
self.addSeparator()
|
||||||
self.addAction(self.colorButton)
|
self.addAction(self.colorButton)
|
||||||
|
@@ -105,7 +105,7 @@ class Tab(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.hiddenButton = QtWidgets.QToolButton(self)
|
self.hiddenButton = QtWidgets.QToolButton(self)
|
||||||
self.hiddenButton.setVisible(False)
|
self.hiddenButton.setVisible(False)
|
||||||
self.hiddenButton.clicked.connect(self.set_scroll_value)
|
self.hiddenButton.clicked.connect(self.set_cursor_position)
|
||||||
self.hiddenButton.animateClick(50)
|
self.hiddenButton.animateClick(50)
|
||||||
|
|
||||||
# The following are common to both the text browser and
|
# The following are common to both the text browser and
|
||||||
@@ -135,7 +135,8 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.dockListView = QtWidgets.QListView(self.dockWidget)
|
self.dockListView = QtWidgets.QListView(self.dockWidget)
|
||||||
self.dockListView.setResizeMode(QtWidgets.QListWidget.Adjust)
|
self.dockListView.setResizeMode(QtWidgets.QListWidget.Adjust)
|
||||||
self.dockListView.setMaximumWidth(350)
|
self.dockListView.setMaximumWidth(350)
|
||||||
self.dockListView.setItemDelegate(BookmarkDelegate(self.main_window, self.dockListView))
|
self.dockListView.setItemDelegate(
|
||||||
|
BookmarkDelegate(self.main_window, self.dockListView))
|
||||||
self.dockListView.setUniformItemSizes(True)
|
self.dockListView.setUniformItemSizes(True)
|
||||||
self.dockListView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
self.dockListView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
self.dockListView.customContextMenuRequested.connect(
|
self.dockListView.customContextMenuRequested.connect(
|
||||||
@@ -157,6 +158,14 @@ class Tab(QtWidgets.QWidget):
|
|||||||
title = self.metadata['title']
|
title = self.metadata['title']
|
||||||
self.main_window.tabWidget.addTab(self, title)
|
self.main_window.tabWidget.addTab(self, title)
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
# Show cover image as tooltip text
|
||||||
|
this_tab_index = self.main_window.tabWidget.indexOf(self)
|
||||||
|
cover_icon = QtGui.QPixmap()
|
||||||
|
cover_icon.loadFromData(self.metadata['cover'])
|
||||||
|
self.main_window.tabWidget.setTabIcon(
|
||||||
|
this_tab_index, QtGui.QIcon(cover_icon))
|
||||||
|
|
||||||
# Hide mouse cursor timer
|
# Hide mouse cursor timer
|
||||||
self.mouse_hide_timer = QtCore.QTimer()
|
self.mouse_hide_timer = QtCore.QTimer()
|
||||||
self.mouse_hide_timer.setSingleShot(True)
|
self.mouse_hide_timer.setSingleShot(True)
|
||||||
@@ -180,38 +189,38 @@ class Tab(QtWidgets.QWidget):
|
|||||||
except IndexError: # The file has been deleted
|
except IndexError: # The file has been deleted
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_scroll_value(self, switch_widgets=True, search_data=None):
|
def set_cursor_position(self, switch_widgets=True, search_data=None):
|
||||||
if self.sender().objectName() == 'tabWidget' and self.first_run:
|
# if self.sender().objectName() == 'tabWidget' and self.first_run:
|
||||||
return
|
# return
|
||||||
self.first_run = False
|
# self.first_run = False
|
||||||
# ^^^ I have NO IDEA why this is needed or how it works
|
# ^^^ I have NO IDEA why this might be needed or how it works
|
||||||
# but scroll positioning does NOT work without the return
|
|
||||||
# Enabling it somehow makes document formatting not work either
|
|
||||||
|
|
||||||
if switch_widgets:
|
if switch_widgets:
|
||||||
previous_widget = self.main_window.tabWidget.currentWidget()
|
previous_widget = self.main_window.tabWidget.currentWidget()
|
||||||
self.main_window.tabWidget.setCurrentWidget(self)
|
self.main_window.tabWidget.setCurrentWidget(self)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
search_text = self.metadata['position']['last_visible_text']
|
required_position = self.metadata['position']['cursor_position']
|
||||||
if search_data:
|
if search_data:
|
||||||
search_text = search_data[1]
|
required_position = search_data[1]
|
||||||
|
|
||||||
# textCursor() RETURNS a copy of the textcursor
|
# TODO
|
||||||
cursor = self.contentView.textCursor()
|
# Remove this at the time when a library rebuild is
|
||||||
cursor.movePosition(QtGui.QTextCursor.Start, QtGui.QTextCursor.KeepAnchor)
|
# finally required
|
||||||
self.contentView.setTextCursor(cursor)
|
# Bookmarks will have to be regenerated in the meantime
|
||||||
|
if isinstance(required_position, str):
|
||||||
|
return
|
||||||
|
|
||||||
# This is needed so that search results are always at the top
|
# This is needed so that the line we want is
|
||||||
# of the window
|
# always at the top of the window
|
||||||
self.contentView.verticalScrollBar().setValue(
|
self.contentView.verticalScrollBar().setValue(
|
||||||
self.contentView.verticalScrollBar().maximum())
|
self.contentView.verticalScrollBar().maximum())
|
||||||
|
|
||||||
# find_forward is a new cursor object that must replace
|
# textCursor() RETURNS a copy of the textcursor
|
||||||
# the existing text cursor
|
cursor = self.contentView.textCursor()
|
||||||
find_forward = self.contentView.document().find(search_text)
|
cursor.setPosition(
|
||||||
find_forward.clearSelection()
|
required_position, QtGui.QTextCursor.MoveAnchor)
|
||||||
self.contentView.setTextCursor(find_forward)
|
self.contentView.setTextCursor(cursor)
|
||||||
self.contentView.ensureCursorVisible()
|
self.contentView.ensureCursorVisible()
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -254,8 +263,8 @@ class Tab(QtWidgets.QWidget):
|
|||||||
'blocks_per_chapter': blocks_per_chapter,
|
'blocks_per_chapter': blocks_per_chapter,
|
||||||
'total_blocks': total_blocks,
|
'total_blocks': total_blocks,
|
||||||
'scroll_value': scroll_value,
|
'scroll_value': scroll_value,
|
||||||
'last_visible_text': None,
|
'is_read': is_read,
|
||||||
'is_read': is_read}
|
'cursor_position': 0}
|
||||||
|
|
||||||
def generate_keyboard_shortcuts(self):
|
def generate_keyboard_shortcuts(self):
|
||||||
self.ksNextChapter = QtWidgets.QShortcut(
|
self.ksNextChapter = QtWidgets.QShortcut(
|
||||||
@@ -323,6 +332,8 @@ class Tab(QtWidgets.QWidget):
|
|||||||
if not self.main_window.settings['show_bars']:
|
if not self.main_window.settings['show_bars']:
|
||||||
self.main_window.toggle_distraction_free()
|
self.main_window.toggle_distraction_free()
|
||||||
|
|
||||||
|
self.contentView.setFocus()
|
||||||
|
|
||||||
def change_chapter_tocBox(self):
|
def change_chapter_tocBox(self):
|
||||||
chapter_number = self.main_window.bookToolBar.tocBox.currentIndex()
|
chapter_number = self.main_window.bookToolBar.tocBox.currentIndex()
|
||||||
required_content = self.metadata['content'][chapter_number][1]
|
required_content = self.metadata['content'][chapter_number][1]
|
||||||
@@ -440,7 +451,7 @@ class Tab(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter - 1)
|
self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter - 1)
|
||||||
if not self.are_we_doing_images_only:
|
if not self.are_we_doing_images_only:
|
||||||
self.set_scroll_value(False, search_data)
|
self.set_cursor_position(False, search_data)
|
||||||
|
|
||||||
def generate_bookmark_model(self):
|
def generate_bookmark_model(self):
|
||||||
# TODO
|
# TODO
|
||||||
@@ -811,7 +822,8 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
|
|||||||
|
|
||||||
self.setMouseTracking(True)
|
self.setMouseTracking(True)
|
||||||
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
|
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
|
||||||
self.verticalScrollBar().sliderMoved.connect(self.record_scroll_position)
|
self.verticalScrollBar().sliderMoved.connect(
|
||||||
|
self.record_scroll_position)
|
||||||
self.ignore_wheel_event = False
|
self.ignore_wheel_event = False
|
||||||
self.ignore_wheel_event_number = 0
|
self.ignore_wheel_event_number = 0
|
||||||
|
|
||||||
@@ -828,18 +840,11 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
|
|||||||
self.set_top_line_cleanly()
|
self.set_top_line_cleanly()
|
||||||
|
|
||||||
def set_top_line_cleanly(self):
|
def set_top_line_cleanly(self):
|
||||||
# TODO
|
# Find the cursor position of the top line and move to it
|
||||||
# This can't find the next line sometimes despite having
|
find_cursor = self.cursorForPosition(QtCore.QPoint(0, 0))
|
||||||
# a valid search text to look up
|
find_cursor.movePosition(
|
||||||
# It could have something to do with textCursor position
|
find_cursor.position(), QtGui.QTextCursor.KeepAnchor)
|
||||||
|
self.setTextCursor(find_cursor)
|
||||||
self.record_scroll_position()
|
|
||||||
|
|
||||||
search_text = self.parent.metadata['position']['last_visible_text']
|
|
||||||
new_cursor = self.document().find(search_text)
|
|
||||||
if not new_cursor.isNull():
|
|
||||||
new_cursor.clearSelection()
|
|
||||||
self.setTextCursor(new_cursor)
|
|
||||||
self.ensureCursorVisible()
|
self.ensureCursorVisible()
|
||||||
|
|
||||||
def record_scroll_position(self, return_as_bookmark=False):
|
def record_scroll_position(self, return_as_bookmark=False):
|
||||||
@@ -853,20 +858,14 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
|
|||||||
self.parent.metadata['position']['scroll_value'] = (vertical / maximum)
|
self.parent.metadata['position']['scroll_value'] = (vertical / maximum)
|
||||||
|
|
||||||
cursor = self.cursorForPosition(QtCore.QPoint(0, 0))
|
cursor = self.cursorForPosition(QtCore.QPoint(0, 0))
|
||||||
bottom_right = QtCore.QPoint(self.viewport().width() - 1, self.viewport().height())
|
cursor_position = cursor.position()
|
||||||
bottom_right_cursor = self.cursorForPosition(bottom_right).position()
|
|
||||||
cursor.setPosition(bottom_right_cursor, QtGui.QTextCursor.KeepAnchor)
|
|
||||||
visible_text = cursor.selectedText()
|
|
||||||
|
|
||||||
if len(visible_text) > 50:
|
|
||||||
visible_text = visible_text[:51]
|
|
||||||
|
|
||||||
if return_as_bookmark:
|
if return_as_bookmark:
|
||||||
return (self.parent.metadata['position']['current_chapter'],
|
return (self.parent.metadata['position']['current_chapter'],
|
||||||
self.parent.metadata['position']['scroll_value'],
|
self.parent.metadata['position']['scroll_value'],
|
||||||
visible_text)
|
cursor_position)
|
||||||
else:
|
else:
|
||||||
self.parent.metadata['position']['last_visible_text'] = visible_text
|
self.parent.metadata['position']['cursor_position'] = cursor_position
|
||||||
|
|
||||||
def generate_textbrowser_context_menu(self, position):
|
def generate_textbrowser_context_menu(self, position):
|
||||||
selected_word = self.textCursor().selection()
|
selected_word = self.textCursor().selection()
|
||||||
|
Reference in New Issue
Block a user