From f312714a2c4f782c306ee991760975e93cc2058f Mon Sep 17 00:00:00 2001 From: BasioMeusPuga Date: Fri, 15 Feb 2019 00:17:47 +0530 Subject: [PATCH] Multiple fixes MuPDF import error Definition text color Database logging --- TODO | 5 +++++ lector/contentwidgets.py | 44 +++++++++++++++++++++++++++++++------ lector/database.py | 10 +++++---- lector/definitionsdialog.py | 21 +++++++++++++++--- lector/threaded.py | 6 ++++- lector/widgets.py | 2 ++ 6 files changed, 73 insertions(+), 15 deletions(-) diff --git a/TODO b/TODO index 8b94b7a..ccd6ffe 100644 --- a/TODO +++ b/TODO @@ -97,10 +97,15 @@ TODO Bookmark name for a page that's not on the TOC and has nothing before Screen position still keeps jumping when inside a paragraph Better recursion needed for fb2 toc + Search results should ignore punctuation + Keep text size for annotations Secondary: + Definitions dialog needs to respond to escape + Zoom slider for comics Tab tooltip Additional Settings: + Find definitions on Google Disable progressbar - 20% book addition speed improvement Disable cover loading when reading - Saves ~2M / book Special formatting for each chapter's title diff --git a/lector/contentwidgets.py b/lector/contentwidgets.py index 357d321..3eba29e 100644 --- a/lector/contentwidgets.py +++ b/lector/contentwidgets.py @@ -21,13 +21,13 @@ import webbrowser try: import fitz + from lector.parsers.pdf import render_pdf_page except ImportError: pass from PyQt5 import QtWidgets, QtGui, QtCore from lector.rarfile import rarfile -from lector.parsers.pdf import render_pdf_page from lector.threaded import BackGroundCacheRefill from lector.annotations import AnnotationPlacement @@ -501,13 +501,17 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): QtWidgets.QTextBrowser.mouseReleaseEvent(self, event) return + self.place_annotation(self.current_annotation) + self.toggle_annotation_mode() + + def place_annotation(self, annotation): current_chapter = self.parent.metadata['position']['current_chapter'] cursor = self.textCursor() cursor_start = cursor.selectionStart() cursor_end = cursor.selectionEnd() annotation_type = 'text_markup' applicable_to = 'text' - annotation_components = self.current_annotation['components'] + annotation_components = annotation['components'] self.annotator.set_current_annotation( annotation_type, annotation_components) @@ -520,7 +524,7 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): # Maybe use annotation name for a consolidated annotation list this_annotation = { - 'name': self.current_annotation['name'], + 'name': annotation['name'], 'applicable_to': applicable_to, 'type': annotation_type, 'cursor': (cursor_start, cursor_end), @@ -533,8 +537,6 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): self.annotation_dict[current_chapter] = [] self.annotation_dict[current_chapter].append(this_annotation) - self.toggle_annotation_mode() - def generate_textbrowser_context_menu(self, position): selection = self.textCursor().selection() selection = selection.toPlainText() @@ -552,6 +554,7 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): searchWikipediaAction = searchYoutubeAction = 'Does anyone know something funny in Latin?' searchAction = searchGoogleAction = bookmarksToggleAction = 'TODO Insert Latin Joke' deleteAnnotationAction = editAnnotationNoteAction = 'Latin quote 2. Electric Boogaloo.' + annotationActions = [] if self.parent.is_fullscreen: fsToggleAction = contextMenu.addAction( @@ -566,13 +569,18 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): if selection and selection != '': first_selected_word = selection.split()[0] + elided_selection = selection + if len(elided_selection) > 15: + elided_selection = elided_selection[:15] + '...' + define_string = self._translate('PliantQTextBrowser', 'Define') defineAction = contextMenu.addAction( self.main_window.QImageFactory.get_image('view-readermode'), f'{define_string} "{first_selected_word}"') search_submenu_string = self._translate('PliantQTextBrowser', 'Search for') - searchSubMenu = contextMenu.addMenu(search_submenu_string + f' "{selection}"') + searchSubMenu = contextMenu.addMenu( + search_submenu_string + f' "{elided_selection}"') searchSubMenu.setIcon(self.main_window.QImageFactory.get_image('search')) searchAction = searchSubMenu.addAction( @@ -588,6 +596,26 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): searchYoutubeAction = searchSubMenu.addAction( QtGui.QIcon(':/images/Youtube.png'), 'Youtube') + + # Allow adding new annotation from the context menu + if not annotation_is_present: + annotation_string = self._translate('PliantQTextBrowser', 'Annotate') + annotationSubmenu = contextMenu.addMenu(annotation_string) + annotationSubmenu.setIcon( + self.main_window.QImageFactory.get_image('annotate')) + + saved_annotations = self.parent.main_window.settings['annotations'] + if not saved_annotations: + nope = annotationSubmenu.addAction('') + nope.setEnabled(False) + + for i in saved_annotations: + this_action = QtWidgets.QAction(i['name']) + # Does not require / support a role + this_action.setData(i) + annotationActions.append(this_action) + annotationSubmenu.addAction(this_action) + else: searchAction = contextMenu.addAction( self.main_window.QImageFactory.get_image('search'), @@ -639,10 +667,12 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser): webbrowser.open_new_tab( f'https://www.youtube.com/results?search_query={selection}') + if action in annotationActions: + self.place_annotation(action.data()) + if action == editAnnotationNoteAction: self.common_functions.annotation_specific( 'note', 'text', current_chapter, cursor_at_mouse.position()) - if action == deleteAnnotationAction: self.common_functions.annotation_specific( 'delete', 'text', current_chapter, cursor_at_mouse.position()) diff --git a/lector/database.py b/lector/database.py index 27deaec..a0a9f8d 100644 --- a/lector/database.py +++ b/lector/database.py @@ -210,8 +210,9 @@ class DatabaseFunctions: else: return None - except (KeyError, sqlite3.OperationalError): - logger.critical('SQLite is in wretched rebellion @ data fetching handling') + except Exception as e: + error_string = 'SQLite is in wretched rebellion @ data fetching handling' + logger.critical(error_string + f' {type(e).__name__} Arguments: {e.args}') def fetch_covers_only(self, hash_list): parameter_marks = ','.join(['?' for i in hash_list]) @@ -243,8 +244,9 @@ class DatabaseFunctions: try: self.database.execute( sql_command, update_data) - except sqlite3.OperationalError: - logger.critical('SQLite is in wretched rebellion @ metadata handling') + except sqlite3.OperationalError as e: + error_string = 'SQLite is in wretched rebellion @ metadata handling' + logger.critical(error_string + f' {type(e).__name__} Arguments: {e.args}') self.database.commit() self.database.close() diff --git a/lector/definitionsdialog.py b/lector/definitionsdialog.py index 7f5ef86..7c308ad 100644 --- a/lector/definitionsdialog.py +++ b/lector/definitionsdialog.py @@ -86,12 +86,15 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog): if response.getcode() == 200: return_json = json.loads(response.read()) return return_json - except (urllib.error.HTTPError, urllib.error.URLError): + except Exception as e: + this_error = f'API access error' + logger.exception(this_error + f' {type(e).__name__} Arguments: {e.args}') return None def find_definition(self, word): word_root_json = self.api_call(self.root_url, word) if not word_root_json: + logger.error('Word root json noped out: ' + word) self.set_text(word, None, None, True) return @@ -100,6 +103,7 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog): definition_json = self.api_call(self.define_url, word_root) if not definition_json: + logger.error('Definition json noped out: ' + word_root) self.set_text(word, None, None, True) return @@ -118,7 +122,7 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog): this_definition = j['definitions'][0].capitalize() except KeyError: # The API also reports crossReferenceMarkers here - pass + this_definition = '' try: definitions[category].add(this_definition) @@ -163,10 +167,21 @@ class DefinitionsUI(QtWidgets.QDialog, definitions.Ui_Dialog): self.parent.get_color() background = self.parent.settings['dialog_background'] + # Calculate inverse color for the background so that + # the text doesn't look blank + r, g, b, alpha = background.getRgb() + inv_average = 255 - (r + g + b) // 3 + if 100 < inv_average < 150: + inv_average = 255 + + foreground = QtGui.QColor( + inv_average, inv_average, inv_average, alpha) + self.setStyleSheet( "QDialog {{background-color: {0}}}".format(background.name())) self.definitionView.setStyleSheet( - "QTextBrowser {{background-color: {0}}}".format(background.name())) + "QTextBrowser {{color:{0}; background-color: {1}}}".format( + foreground.name(), background.name())) if not set_initial: self.show() diff --git a/lector/threaded.py b/lector/threaded.py index 4702881..79ea6d8 100644 --- a/lector/threaded.py +++ b/lector/threaded.py @@ -24,7 +24,11 @@ from PyQt5 import QtCore, QtGui from lector import sorter from lector import database -from lector.parsers.pdf import render_pdf_page + +try: + from lector.parsers.pdf import render_pdf_page +except ImportError: + pass logger = logging.getLogger(__name__) diff --git a/lector/widgets.py b/lector/widgets.py index ec16acd..9c2eb3c 100644 --- a/lector/widgets.py +++ b/lector/widgets.py @@ -450,6 +450,8 @@ class Tab(QtWidgets.QWidget): if tocBox_readjust: self.set_tocBox_index(required_position, None) + self.contentView.setFocus() + def set_tocBox_index(self, current_position=None, tocBox=None): # Get current position from the metadata dictionary # in case it isn't specified