Annotation placement

This commit is contained in:
BasioMeusPuga
2018-04-16 13:00:49 +05:30
parent 98ca118a60
commit cbf01c6d16
10 changed files with 6681 additions and 6420 deletions

3
TODO
View File

@@ -62,6 +62,8 @@ TODO
✓ Track open bookmark windows so they can be closed quickly at exit
Annotations
Text
Overlapping - Will involve passing current charformat
Annotation preview upon application
Image
Adjust key navigation according to viewport dimensions
Search document using QTextCursor
@@ -80,6 +82,7 @@ TODO
Bugs:
Deselecting all directories in the settings dialog also filters out manually added books
Clean up 'switch' page layout
Colors aren't loaded properly for annotation previews
Secondary:
Graphical themes

View File

@@ -164,9 +164,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.libraryToolBar.tableViewButton.trigger()
# Book toolbar
self.bookToolBar.annotationButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.addBookmarkButton.triggered.connect(self.add_bookmark)
self.bookToolBar.bookmarkButton.triggered.connect(self.toggle_dock_widget)
self.bookToolBar.distractionFreeButton.triggered.connect(self.toggle_distraction_free)
self.bookToolBar.bookmarkButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.distractionFreeButton.triggered.connect(self.toggle_dock_widgets)
self.bookToolBar.fullscreenButton.triggered.connect(self.set_fullscreen)
for count, i in enumerate(self.display_profiles):
@@ -510,9 +511,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.current_tab = self.tabWidget.currentIndex()
# Hide bookmark widgets
# Hide bookmark and annotation widgets
for i in range(1, self.tabWidget.count()):
self.tabWidget.widget(i).dockWidget.setVisible(False)
self.tabWidget.widget(i).bookmarkDock.setVisible(False)
self.tabWidget.widget(i).annotationDock.setVisible(False)
if self.tabWidget.currentIndex() == 0:
@@ -598,14 +600,17 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
current_tab_widget = self.tabWidget.widget(current_tab)
current_tab_widget.go_fullscreen()
def toggle_dock_widget(self):
sender = self.sender().objectName()
def toggle_dock_widgets(self):
sender = self.sender()
current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab)
if sender == 'bookmarkButton':
if sender == self.bookToolBar.bookmarkButton:
current_tab_widget.toggle_bookmarks()
if sender == self.bookToolBar.annotationButton:
current_tab_widget.toggle_annotations()
def library_doubleclick(self, index):
sender = self.sender().objectName()

View File

@@ -69,6 +69,10 @@ class AnnotationsUI(QtWidgets.QDialog, annotationswindow.Ui_Dialog):
self.underlineCheck.clicked.connect(self.modify_annotation)
def show_dialog(self, mode, index=None):
# TODO
# Account for annotation type here
# and point to a relevant set of widgets accordingly
if mode == 'edit' or mode == 'preview':
self.modelIndex = index
this_annotation = self.parent.annotationModel.data(
@@ -244,3 +248,62 @@ class AnnotationsUI(QtWidgets.QDialog, annotationswindow.Ui_Dialog):
self.parent.annotationModel.appendRow(new_annotation_item)
self.hide()
class AnnotationPlacement:
def __init__(self):
self.annotation_type = None
self.annotation_components = None
self.underline_styles = {
'Solid': QtGui.QTextCharFormat.SingleUnderline,
'Dashes': QtGui.QTextCharFormat.DashUnderline,
'Dots': QtGui.QTextCharFormat.DotLine,
'Wavy': QtGui.QTextCharFormat.WaveUnderline}
def set_current_annotation(self, annotation_type, annotation_components):
# Components expected to be a dictionary
self.annotation_type = annotation_type # This is currently unused
self.annotation_components = annotation_components
def format_text(self, cursor, start_here, end_here):
# This is applicable only to the PliantQTextBrowser
# for the text_markup style of annotation
# The cursor is the textCursor of the QTextEdit
# containing the text that has to be modified
if not self.annotation_components:
return
cursor.setPosition(start_here)
cursor.setPosition(end_here, QtGui.QTextCursor.KeepAnchor)
newCharFormat = QtGui.QTextCharFormat()
if 'foregroundColor' in self.annotation_components:
newCharFormat.setForeground(
self.annotation_components['foregroundColor'])
if 'highlightColor' in self.annotation_components:
newCharFormat.setBackground(
self.annotation_components['highlightColor'])
if 'bold' in self.annotation_components:
newCharFormat.setFontWeight(QtGui.QFont.Bold)
if 'italic' in self.annotation_components:
newCharFormat.setFontItalic(True)
if 'underline' in self.annotation_components:
newCharFormat.setFontUnderline(True)
newCharFormat.setUnderlineStyle(
self.underline_styles[self.annotation_components['underline'][0]])
newCharFormat.setUnderlineColor(
self.annotation_components['underline'][1])
newCharFormat.setFontStyleStrategy(
QtGui.QFont.PreferAntialias)
cursor.setCharFormat(newCharFormat)
cursor.clearSelection()
return cursor

View File

@@ -27,6 +27,7 @@ from PyQt5 import QtWidgets, QtGui, QtCore
from lector.rarfile import rarfile
from lector.threaded import BackGroundCacheRefill
from lector.annotations import AnnotationPlacement
class PliantQGraphicsView(QtWidgets.QGraphicsView):
@@ -326,6 +327,9 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
self.parent = parent
self.main_window = main_window
self.annotator = AnnotationPlacement()
self.current_annotation = None
self.common_functions = PliantWidgetsCommonFunctions(
self, self.main_window)
@@ -334,7 +338,6 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
self.generate_textbrowser_context_menu)
self.setMouseTracking(True)
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
self.verticalScrollBar().sliderMoved.connect(
self.record_position)
self.ignore_wheel_event = False
@@ -391,6 +394,36 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
else:
self.parent.metadata['position']['cursor_position'] = cursor_position
def toggle_annotation_mode(self):
self.annotation_mode = True
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
self.parent.annotationDock.setWindowOpacity(.40)
selected_index = self.parent.annotationListView.currentIndex()
self.current_annotation = self.parent.annotationModel.data(
selected_index, QtCore.Qt.UserRole)
print('Current annotation: ' + self.current_annotation['name'])
def mouseReleaseEvent(self, event):
# This takes care of annotation placement
if not self.current_annotation:
QtWidgets.QTextBrowser.mouseReleaseEvent(self, event)
return
self.annotator.set_current_annotation(
'text_markup', self.current_annotation['components'])
cursor = self.textCursor()
new_cursor = self.annotator.format_text(
cursor, cursor.selectionStart(), cursor.selectionEnd())
self.setTextCursor(new_cursor)
self.annotation_mode = False
self.viewport().setCursor(QtCore.Qt.ArrowCursor)
self.current_annotation = None
self.parent.annotationListView.clearSelection()
self.parent.annotationDock.setWindowOpacity(.95)
def generate_textbrowser_context_menu(self, position):
selection = self.textCursor().selection()
selection = selection.toPlainText()
@@ -479,7 +512,7 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
self.main_window.closeEvent()
def mouseMoveEvent(self, event):
self.viewport().setCursor(QtCore.Qt.IBeamCursor)
self.viewport().setCursor(QtCore.Qt.ArrowCursor)
self.parent.mouse_hide_timer.start(3000)
QtWidgets.QTextBrowser.mouseMoveEvent(self, event)

View File

@@ -1,5 +1,7 @@
<RCC>
<qresource prefix="images">
<file>LightIcons/annotate.svg</file>
<file>DarkIcons/annotate.svg</file>
<file>Google.png</file>
<file>Wikipedia.png</file>
<file>Youtube.png</file>

File diff suppressed because it is too large Load Diff

View File

@@ -190,14 +190,14 @@ class Settings:
self.settings.endGroup()
self.settings.beginGroup('settingsSwitches')
self.settings.setValue('rememberFiles', current_settings['remember_files'])
self.settings.setValue('coverShadows', current_settings['cover_shadows'])
self.settings.setValue('autoTags', current_settings['auto_tags'])
self.settings.setValue('scanLibraryAtStart', current_settings['scan_library'])
self.settings.setValue('performCulling', current_settings['perform_culling'])
self.settings.setValue('dictionaryLanguage', current_settings['dictionary_language'])
self.settings.setValue('cachingEnabled', current_settings['caching_enabled'])
self.settings.setValue('hideScrollBars', current_settings['hide_scrollbars'])
self.settings.setValue('rememberFiles', str(current_settings['remember_files']))
self.settings.setValue('coverShadows', str(current_settings['cover_shadows']))
self.settings.setValue('autoTags', str(current_settings['auto_tags']))
self.settings.setValue('scanLibraryAtStart', str(current_settings['scan_library']))
self.settings.setValue('performCulling', str(current_settings['perform_culling']))
self.settings.setValue('dictionaryLanguage', str(current_settings['dictionary_language']))
self.settings.setValue('cachingEnabled', str(current_settings['caching_enabled']))
self.settings.setValue('hideScrollBars', str(current_settings['hide_scrollbars']))
self.settings.setValue('scrollSpeed', current_settings['scroll_speed'])
self.settings.setValue('considerReadAt', current_settings['consider_read_at'])
self.settings.endGroup()

View File

@@ -314,6 +314,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.main_window.libraryToolBar.settingsButton.setChecked(False)
self.gather_annotations()
Settings(self.main_window).save_settings()
Settings(self.main_window).read_settings()
self.resizeEvent()
def resizeEvent(self, event=None):

View File

@@ -43,6 +43,10 @@ class BookToolBar(QtWidgets.QToolBar):
image_factory.get_image('gtk-select-font'),
self._translate('BookToolBar', 'View settings'),
self)
self.annotationButton = QtWidgets.QAction(
image_factory.get_image('annotate'),
self._translate('BookToolBar', 'Annotations'),
self)
self.addBookmarkButton = QtWidgets.QAction(
image_factory.get_image('bookmark-new'),
self._translate('BookToolBar', 'Add bookmark'),
@@ -51,7 +55,6 @@ class BookToolBar(QtWidgets.QToolBar):
image_factory.get_image('bookmarks'),
self._translate('BookToolBar', 'Bookmarks (Ctrl + B)'),
self)
self.bookmarkButton.setObjectName('bookmarkButton')
self.distractionFreeButton = QtWidgets.QAction(
image_factory.get_image('visibility'),
self._translate('Main_BookToolBarUI', 'Toggle distraction free mode (Ctrl + D)'),
@@ -70,6 +73,9 @@ class BookToolBar(QtWidgets.QToolBar):
self.fontButton.setCheckable(True)
self.fontButton.triggered.connect(self.toggle_font_settings)
self.addSeparator()
self.addAction(self.annotationButton)
self.annotationButton.setCheckable(True)
self.addSeparator()
self.addAction(self.addBookmarkButton)
self.addAction(self.bookmarkButton)
self.bookmarkButton.setCheckable(True)
@@ -280,6 +286,7 @@ class BookToolBar(QtWidgets.QToolBar):
self.searchBarAction = self.addWidget(self.searchBar)
self.bookActions = [
self.annotationButton,
self.addBookmarkButton,
self.bookmarkButton,
self.distractionFreeButton,

View File

@@ -111,27 +111,43 @@ class Tab(QtWidgets.QWidget):
self.contentView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.contentView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
# Create the annotations dock
self.annotationDock = PliantDockWidget(self.main_window, 'annotations', self.contentView)
self.annotationDock.setWindowTitle(self._translate('Tab', 'Annotations'))
self.annotationDock.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
self.annotationDock.hide()
self.annotationListView = QtWidgets.QListView(self.annotationDock)
self.annotationListView.setResizeMode(QtWidgets.QListWidget.Adjust)
self.annotationListView.setMaximumWidth(350)
self.annotationListView.doubleClicked.connect(self.contentView.toggle_annotation_mode)
self.annotationListView.setEditTriggers(QtWidgets.QListView.NoEditTriggers)
self.annotationDock.setWidget(self.annotationListView)
self.annotationModel = QtGui.QStandardItemModel(self)
self.generate_annotation_model()
# See bookmark availability
if not self.metadata['bookmarks']:
self.metadata['bookmarks'] = {}
# Create the dock widget for context specific display
self.dockWidget = PliantDockWidget(self.main_window, self.contentView)
self.dockWidget.setWindowTitle(self._translate('Tab', 'Bookmarks'))
self.dockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
self.dockWidget.hide()
self.bookmarkDock = PliantDockWidget(self.main_window, 'bookmarks', self.contentView)
self.bookmarkDock.setWindowTitle(self._translate('Tab', 'Bookmarks'))
self.bookmarkDock.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
self.bookmarkDock.hide()
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.setUniformItemSizes(True)
self.dockListView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.dockListView.customContextMenuRequested.connect(
self.bookmarkListView = QtWidgets.QListView(self.bookmarkDock)
self.bookmarkListView.setResizeMode(QtWidgets.QListWidget.Adjust)
self.bookmarkListView.setMaximumWidth(350)
self.bookmarkListView.setItemDelegate(
BookmarkDelegate(self.main_window, self.bookmarkListView))
self.bookmarkListView.setUniformItemSizes(True)
self.bookmarkListView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.bookmarkListView.customContextMenuRequested.connect(
self.generate_bookmark_context_menu)
self.dockListView.clicked.connect(self.navigate_to_bookmark)
self.dockWidget.setWidget(self.dockListView)
self.bookmarkListView.clicked.connect(self.navigate_to_bookmark)
self.bookmarkDock.setWidget(self.bookmarkListView)
self.bookmarkModel = QtGui.QStandardItemModel(self)
self.bookmarkProxyModel = BookmarkProxyModel(self)
@@ -140,9 +156,14 @@ class Tab(QtWidgets.QWidget):
self.generate_keyboard_shortcuts()
self.masterLayout.addWidget(self.contentView)
self.masterLayout.addWidget(self.dockWidget)
self.dockWidget.setFloating(True)
self.dockWidget.setWindowOpacity(.95)
self.masterLayout.addWidget(self.annotationDock)
self.masterLayout.addWidget(self.bookmarkDock)
# The following has to be after the docks are added to the layout
self.annotationDock.setFloating(True)
self.annotationDock.setWindowOpacity(.95)
self.bookmarkDock.setFloating(True)
self.bookmarkDock.setWindowOpacity(.95)
title = self.metadata['title']
self.main_window.tabWidget.addTab(self, title)
@@ -277,8 +298,8 @@ class Tab(QtWidgets.QWidget):
self.is_fullscreen = True
def exit_fullscreen(self):
if self.dockWidget.isVisible():
self.dockWidget.setVisible(False)
if self.bookmarkDock.isVisible():
self.bookmarkDock.setVisible(False)
return
if not self.are_we_doing_images_only:
@@ -370,11 +391,31 @@ class Tab(QtWidgets.QWidget):
if old_position == new_position:
break
def toggle_bookmarks(self):
if self.dockWidget.isVisible():
self.dockWidget.hide()
def toggle_annotations(self):
if self.annotationDock.isVisible():
self.annotationDock.hide()
else:
self.dockWidget.show()
self.annotationDock.show()
def generate_annotation_model(self):
saved_annotations = self.main_window.settings['annotations']
if not saved_annotations:
return
for i in saved_annotations:
item = QtGui.QStandardItem()
item.setText(i['name'])
item.setData(i, QtCore.Qt.UserRole)
self.annotationModel.appendRow(item)
self.annotationListView.setModel(self.annotationModel)
def toggle_bookmarks(self):
if self.bookmarkDock.isVisible():
self.bookmarkDock.hide()
else:
self.bookmarkDock.show()
def add_bookmark(self):
# TODO
@@ -396,7 +437,7 @@ class Tab(QtWidgets.QWidget):
self.add_bookmark_to_model(
description, chapter, cursor_position, identifier)
self.dockWidget.setVisible(True)
self.bookmarkDock.setVisible(True)
def add_bookmark_to_model(self, description, chapter, cursor_position, identifier):
bookmark = QtGui.QStandardItem()
@@ -445,7 +486,7 @@ class Tab(QtWidgets.QWidget):
self.bookmarkProxyModel.setSourceModel(self.bookmarkModel)
self.bookmarkProxyModel.setSortCaseSensitivity(False)
self.bookmarkProxyModel.setSortRole(QtCore.Qt.UserRole)
self.dockListView.setModel(self.bookmarkProxyModel)
self.bookmarkListView.setModel(self.bookmarkProxyModel)
def update_bookmark_proxy_model(self):
self.bookmarkProxyModel.invalidateFilter()
@@ -455,7 +496,7 @@ class Tab(QtWidgets.QWidget):
self.main_window.bookToolBar.searchBar.text())
def generate_bookmark_context_menu(self, position):
index = self.dockListView.indexAt(position)
index = self.bookmarkListView.indexAt(position)
if not index.isValid():
return
@@ -468,10 +509,10 @@ class Tab(QtWidgets.QWidget):
self._translate('Tab', 'Delete'))
action = bookmarkMenu.exec_(
self.dockListView.mapToGlobal(position))
self.bookmarkListView.mapToGlobal(position))
if action == editAction:
self.dockListView.edit(index)
self.bookmarkListView.edit(index)
if action == deleteAction:
row = index.row()
@@ -497,29 +538,43 @@ class Tab(QtWidgets.QWidget):
class PliantDockWidget(QtWidgets.QDockWidget):
def __init__(self, main_window, contentView, parent=None):
def __init__(self, main_window, intended_for, contentView, parent=None):
super(PliantDockWidget, self).__init__()
self.main_window = main_window
self.intended_for = intended_for
self.contentView = contentView
def showEvent(self, event):
viewport_height = self.contentView.viewport().size().height()
viewport_topRight = self.contentView.mapToGlobal(
self.contentView.viewport().rect().topRight())
viewport_topLeft = self.contentView.mapToGlobal(
self.contentView.viewport().rect().topLeft())
desktop_size = QtWidgets.QDesktopWidget().screenGeometry()
dock_width = desktop_size.width() // 5.5
dock_x = viewport_topRight.x() - dock_width + 1
if self.intended_for == 'bookmarks':
dock_x = viewport_topRight.x() - dock_width + 1
dock_width = desktop_size.width() // 5.5
self.main_window.bookToolBar.bookmarkButton.setChecked(True)
elif self.intended_for == 'annotations':
dock_x = viewport_topLeft.x()
dock_width = desktop_size.width() // 10
self.main_window.bookToolBar.annotationButton.setChecked(True)
dock_y = viewport_topRight.y() + (viewport_height * .10)
dock_height = viewport_height * .80
self.setGeometry(dock_x, dock_y, dock_width, dock_height)
self.main_window.bookToolBar.bookmarkButton.setChecked(True)
self.main_window.active_bookmark_docks.append(self)
self.setGeometry(dock_x, dock_y, dock_width, dock_height)
def hideEvent(self, event=None):
self.main_window.bookToolBar.bookmarkButton.setChecked(False)
if self.intended_for == 'bookmarks':
self.main_window.bookToolBar.bookmarkButton.setChecked(False)
elif self.intended_for == 'annotations':
self.main_window.bookToolBar.annotationButton.setChecked(False)
try:
self.main_window.active_bookmark_docks.remove(self)
except ValueError: