From 406ca0485f830b70b1e7c91421f5ed01fece17d4 Mon Sep 17 00:00:00 2001 From: BasioMeusPuga Date: Thu, 29 Mar 2018 01:45:58 +0530 Subject: [PATCH] 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 --- TODO | 5 ++- lector/__main__.py | 15 +++----- lector/database.py | 5 ++- lector/sorter.py | 4 +- lector/toolbars.py | 6 +++ lector/widgets.py | 95 +++++++++++++++++++++++----------------------- 6 files changed, 69 insertions(+), 61 deletions(-) diff --git a/TODO b/TODO index b27dfb3..491f43c 100644 --- a/TODO +++ b/TODO @@ -58,6 +58,8 @@ TODO ✓ Comic view keyboard shortcuts ✓ Comic view context menu ✓ 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 Search document using QTextCursor Filetypes: @@ -74,6 +76,8 @@ TODO ✓ Define every widget in code Bugs: 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: Annotations @@ -86,7 +90,6 @@ TODO Pagination Use embedded fonts + CSS Scrolling: Smooth / By Line - Spacebar should not cut off lines at the top Shift to logging instead of print statements txt, doc, chm, djvu, fb2 support Include icons for filetype emblems diff --git a/lector/__main__.py b/lector/__main__.py index dbe5325..f03d6c5 100755 --- a/lector/__main__.py +++ b/lector/__main__.py @@ -155,6 +155,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.libraryToolBar.deleteButton.triggered.connect(self.delete_books) self.libraryToolBar.coverViewButton.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.settingsButton.triggered.connect(self.show_settings) 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) print('Available parsers: ' + self.available_parsers) - # The library refresh button on the Library tab - 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) - + # The Library tab gets no button self.tabWidget.tabBar().setTabButton( - 0, QtWidgets.QTabBar.RightSide, self.reloadLibrary) + 0, QtWidgets.QTabBar.RightSide, None) self.tabWidget.tabCloseRequested.connect(self.tab_close) + self.tabWidget.setTabBarAutoHide(True) # Init display models self.lib_ref.generate_model('build') @@ -556,7 +553,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.bookToolBar.tocBox.setCurrentIndex( current_position['current_chapter'] - 1) if not current_metadata['images_only']: - current_tab.set_scroll_value(True) + current_tab.set_cursor_position() self.bookToolBar.tocBox.blockSignals(False) self.profile_functions.format_contentView() diff --git a/lector/database.py b/lector/database.py index 4e49aa7..b49fb62 100644 --- a/lector/database.py +++ b/lector/database.py @@ -42,7 +42,8 @@ class DatabaseInit: 'LastAccessed': 'BLOB', 'Bookmarks': 'BLOB', 'CoverImage': 'BLOB', - 'Addition': 'TEXT'} + 'Addition': 'TEXT', + 'Annotations': 'BLOB'} self.directories_table_columns = { 'id': 'INTEGER PRIMARY KEY', @@ -82,7 +83,7 @@ class DatabaseInit: for i in self.books_table_columns.items(): if i[0] not in database_columns: 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]}" self.database.execute(sql_command) diff --git a/lector/sorter.py b/lector/sorter.py index aeed23c..ee4b75c 100644 --- a/lector/sorter.py +++ b/lector/sorter.py @@ -118,7 +118,7 @@ class BookSorter: def database_entry_for_book(self, file_hash): database_return = database.DatabaseFunctions( self.database_path).fetch_data( - ('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks'), + ('Title', 'Author', 'Year', 'ISBN', 'Tags', 'Position', 'Bookmarks', 'CoverImage'), 'books', {'Hash': file_hash}, 'EQUALS')[0] @@ -231,11 +231,13 @@ class BookSorter: tags = book_data[4] position = book_data[5] bookmarks = book_data[6] + cover = book_data[7] this_book[file_md5]['position'] = position this_book[file_md5]['bookmarks'] = bookmarks this_book[file_md5]['content'] = content this_book[file_md5]['images_only'] = images_only + this_book[file_md5]['cover'] = cover this_book[file_md5]['title'] = title this_book[file_md5]['author'] = author diff --git a/lector/toolbars.py b/lector/toolbars.py index 37b66ae..17a8bfc 100644 --- a/lector/toolbars.py +++ b/lector/toolbars.py @@ -376,6 +376,11 @@ class LibraryToolBar(QtWidgets.QToolBar): self) 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.setIcon(image_factory.get_image('view-readermode')) self.libraryFilterButton.setText( @@ -396,6 +401,7 @@ class LibraryToolBar(QtWidgets.QToolBar): self.addAction(self.coverViewButton) self.addAction(self.tableViewButton) self.addSeparator() + self.addAction(self.reloadLibraryButton) self.addWidget(self.libraryFilterButton) self.addSeparator() self.addAction(self.colorButton) diff --git a/lector/widgets.py b/lector/widgets.py index 02042be..ba63d90 100644 --- a/lector/widgets.py +++ b/lector/widgets.py @@ -105,7 +105,7 @@ class Tab(QtWidgets.QWidget): self.hiddenButton = QtWidgets.QToolButton(self) self.hiddenButton.setVisible(False) - self.hiddenButton.clicked.connect(self.set_scroll_value) + self.hiddenButton.clicked.connect(self.set_cursor_position) self.hiddenButton.animateClick(50) # 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.setResizeMode(QtWidgets.QListWidget.Adjust) 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.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.dockListView.customContextMenuRequested.connect( @@ -157,6 +158,14 @@ class Tab(QtWidgets.QWidget): title = self.metadata['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 self.mouse_hide_timer = QtCore.QTimer() self.mouse_hide_timer.setSingleShot(True) @@ -180,38 +189,38 @@ class Tab(QtWidgets.QWidget): except IndexError: # The file has been deleted pass - def set_scroll_value(self, switch_widgets=True, search_data=None): - if self.sender().objectName() == 'tabWidget' and self.first_run: - return - self.first_run = False - # ^^^ I have NO IDEA why this is needed or how it works - # but scroll positioning does NOT work without the return - # Enabling it somehow makes document formatting not work either + def set_cursor_position(self, switch_widgets=True, search_data=None): + # if self.sender().objectName() == 'tabWidget' and self.first_run: + # return + # self.first_run = False + # ^^^ I have NO IDEA why this might be needed or how it works if switch_widgets: previous_widget = self.main_window.tabWidget.currentWidget() self.main_window.tabWidget.setCurrentWidget(self) try: - search_text = self.metadata['position']['last_visible_text'] + required_position = self.metadata['position']['cursor_position'] if search_data: - search_text = search_data[1] + required_position = search_data[1] - # textCursor() RETURNS a copy of the textcursor - cursor = self.contentView.textCursor() - cursor.movePosition(QtGui.QTextCursor.Start, QtGui.QTextCursor.KeepAnchor) - self.contentView.setTextCursor(cursor) + # TODO + # Remove this at the time when a library rebuild is + # finally required + # 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 - # of the window + # This is needed so that the line we want is + # always at the top of the window self.contentView.verticalScrollBar().setValue( self.contentView.verticalScrollBar().maximum()) - # find_forward is a new cursor object that must replace - # the existing text cursor - find_forward = self.contentView.document().find(search_text) - find_forward.clearSelection() - self.contentView.setTextCursor(find_forward) + # textCursor() RETURNS a copy of the textcursor + cursor = self.contentView.textCursor() + cursor.setPosition( + required_position, QtGui.QTextCursor.MoveAnchor) + self.contentView.setTextCursor(cursor) self.contentView.ensureCursorVisible() except KeyError: @@ -254,8 +263,8 @@ class Tab(QtWidgets.QWidget): 'blocks_per_chapter': blocks_per_chapter, 'total_blocks': total_blocks, 'scroll_value': scroll_value, - 'last_visible_text': None, - 'is_read': is_read} + 'is_read': is_read, + 'cursor_position': 0} def generate_keyboard_shortcuts(self): self.ksNextChapter = QtWidgets.QShortcut( @@ -323,6 +332,8 @@ class Tab(QtWidgets.QWidget): if not self.main_window.settings['show_bars']: self.main_window.toggle_distraction_free() + self.contentView.setFocus() + def change_chapter_tocBox(self): chapter_number = self.main_window.bookToolBar.tocBox.currentIndex() required_content = self.metadata['content'][chapter_number][1] @@ -440,7 +451,7 @@ class Tab(QtWidgets.QWidget): self.main_window.bookToolBar.tocBox.setCurrentIndex(chapter - 1) 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): # TODO @@ -811,7 +822,8 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): self.setMouseTracking(True) 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_number = 0 @@ -828,19 +840,12 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): self.set_top_line_cleanly() def set_top_line_cleanly(self): - # TODO - # This can't find the next line sometimes despite having - # a valid search text to look up - # It could have something to do with textCursor position - - 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() + # Find the cursor position of the top line and move to it + find_cursor = self.cursorForPosition(QtCore.QPoint(0, 0)) + find_cursor.movePosition( + find_cursor.position(), QtGui.QTextCursor.KeepAnchor) + self.setTextCursor(find_cursor) + self.ensureCursorVisible() def record_scroll_position(self, return_as_bookmark=False): self.parent.metadata['position']['is_read'] = False @@ -853,20 +858,14 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): self.parent.metadata['position']['scroll_value'] = (vertical / maximum) cursor = self.cursorForPosition(QtCore.QPoint(0, 0)) - bottom_right = QtCore.QPoint(self.viewport().width() - 1, self.viewport().height()) - 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] + cursor_position = cursor.position() if return_as_bookmark: return (self.parent.metadata['position']['current_chapter'], self.parent.metadata['position']['scroll_value'], - visible_text) + cursor_position) 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): selected_word = self.textCursor().selection()