diff --git a/TODO b/TODO
index d5836a8..297da8a 100644
--- a/TODO
+++ b/TODO
@@ -79,7 +79,6 @@ TODO
✓ Define every widget in code
Bugs:
Deselecting all directories in the settings dialog also filters out manually added books
- PDF year
Secondary:
Graphical themes
diff --git a/lector/__main__.py b/lector/__main__.py
index 35fcea7..bcdddb5 100755
--- a/lector/__main__.py
+++ b/lector/__main__.py
@@ -262,8 +262,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
if self.settings['main_window_headers']:
for count, i in enumerate(self.settings['main_window_headers']):
self.tableView.horizontalHeader().resizeSection(count, int(i))
- self.tableView.horizontalHeader().resizeSection(5, 1)
- self.tableView.horizontalHeader().setStretchLastSection(True)
+ self.tableView.horizontalHeader().resizeSection(5, 30)
+ self.tableView.horizontalHeader().setStretchLastSection(False)
self.tableView.horizontalHeader().sectionClicked.connect(
self.lib_ref.table_proxy_model.sort_table_columns)
self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
@@ -822,7 +822,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
last_accessed_time = None
if action == readAction:
last_accessed_time = QtCore.QDateTime().currentDateTime()
- position_perc = 100
+ position_perc = 1
self.lib_ref.view_model.setData(i, metadata, QtCore.Qt.UserRole + 3)
self.lib_ref.view_model.setData(i, position_perc, QtCore.Qt.UserRole + 7)
@@ -916,8 +916,11 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.settingsDialog.hide()
self.definitionDialog.hide()
self.temp_dir.remove()
- for i in self.active_bookmark_docks:
- i.setVisible(False)
+ for this_dock in self.active_bookmark_docks:
+ try:
+ this_dock.setVisible(False)
+ except RuntimeError:
+ pass
self.settings['last_open_books'] = []
if self.tabWidget.count() > 1:
diff --git a/lector/delegates.py b/lector/delegates.py
index 7738470..0ebbdf2 100644
--- a/lector/delegates.py
+++ b/lector/delegates.py
@@ -33,13 +33,8 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
# painter.fillRect(option.rect, QtGui.QColor().fromRgb(255, 0, 0, 20))
option = option.__class__(option)
- title = index.data(QtCore.Qt.UserRole)
file_exists = index.data(QtCore.Qt.UserRole + 5)
- metadata = index.data(QtCore.Qt.UserRole + 3)
-
- position = metadata['position']
- if position:
- is_read = position['is_read']
+ position_percent = index.data(QtCore.Qt.UserRole + 7)
# The shadow pixmap currently is set to 420 x 600
# Only draw the cover shadow in case the setting is enabled
@@ -64,26 +59,10 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
return
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
- if position:
- if is_read:
- progress = total = -1
- else:
- try:
- progress = position['current_block']
- total = position['total_blocks']
- if progress == total == 0:
- raise KeyError
- except KeyError:
- # For comics and older database entries
- # It looks ugly but leave it like this
- try:
- progress = position['current_chapter']
- total = position['total_chapters']
- except KeyError:
- return
+ if position_percent:
read_icon = pie_chart.pixmapper(
- progress, total, self.temp_dir, 36)
+ position_percent, self.temp_dir, self.parent.settings['consider_read_at'], 36)
x_draw = option.rect.bottomRight().x() - 30
y_draw = option.rect.bottomRight().y() - 35
diff --git a/lector/library.py b/lector/library.py
index cc155b7..5d9ad02 100644
--- a/lector/library.py
+++ b/lector/library.py
@@ -101,18 +101,22 @@ class Library:
if position:
position = pickle.loads(position)
if position['is_read']:
- position_perc = 100
+ position_perc = 1
else:
try:
position_perc = (
- position['current_chapter'] * 100 / position['total_chapters'])
- except KeyError:
- position_perc = None
+ position['current_block'] / position['total_blocks'])
+ except (KeyError, ZeroDivisionError):
+ try:
+ position_perc = (
+ position['current_chapter'] / position['total_chapters'])
+ except KeyError:
+ position_perc = None
try:
file_exists = os.path.exists(path)
except UnicodeEncodeError:
- print('Error with unicode encoding in the library module')
+ print('Library: Unicode encoding error')
all_metadata = {
'title': title,
@@ -176,7 +180,9 @@ class Library:
self.parent.listView.setModel(self.item_proxy_model)
self.table_proxy_model = TableProxyModel(
- self.parent.temp_dir.path(), self.parent.tableView.horizontalHeader())
+ self.parent.temp_dir.path(),
+ self.parent.tableView.horizontalHeader(),
+ self.parent.settings['consider_read_at'])
self.table_proxy_model.setSourceModel(self.view_model)
self.table_proxy_model.setSortCaseSensitivity(False)
self.parent.tableView.setModel(self.table_proxy_model)
@@ -223,7 +229,8 @@ class Library:
1: 1,
2: 2,
3: 9,
- 4: 12}
+ 4: 12,
+ 5: 7}
# Sorting according to roles and the drop down in the library toolbar
self.item_proxy_model.setSortRole(
@@ -231,7 +238,7 @@ class Library:
# This can be expanded to other fields by appending to the list
sort_order = QtCore.Qt.AscendingOrder
- if self.parent.libraryToolBar.sortingBox.currentIndex() in [3, 4]:
+ if self.parent.libraryToolBar.sortingBox.currentIndex() in [3, 4, 5]:
sort_order = QtCore.Qt.DescendingOrder
self.item_proxy_model.sort(0, sort_order)
diff --git a/lector/models.py b/lector/models.py
index aa2d2cd..c87d31a 100644
--- a/lector/models.py
+++ b/lector/models.py
@@ -65,9 +65,10 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
class TableProxyModel(QtCore.QSortFilterProxyModel):
- def __init__(self, temp_dir, tableViewHeader, parent=None):
+ def __init__(self, temp_dir, tableViewHeader, consider_read_at, parent=None):
super(TableProxyModel, self).__init__(parent)
self.tableViewHeader = tableViewHeader
+ self.consider_read_at = consider_read_at
self._translate = QtCore.QCoreApplication.translate
title_string = self._translate('TableProxyModel', 'Title')
@@ -101,6 +102,7 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return self.header_data[column]
except IndexError:
print('Table proxy model: Can\'t find header for column', column)
+ # The column will be called IndexError. Not a typo.
return 'IndexError'
def flags(self, index):
@@ -121,36 +123,16 @@ class TableProxyModel(QtCore.QSortFilterProxyModel):
return_pixmap = None
file_exists = item.data(QtCore.Qt.UserRole + 5)
- metadata = item.data(QtCore.Qt.UserRole + 3)
- progress_perc = item.data(QtCore.Qt.UserRole + 7)
-
- position = metadata['position']
- if position:
- is_read = position['is_read']
+ position_percent = item.data(QtCore.Qt.UserRole + 7)
if not file_exists:
return pie_chart.pixmapper(
-1, None, None, QtCore.Qt.SizeHintRole + 10)
- if position:
- if is_read:
- progress = total = -2
- else:
- try:
- progress = position['current_block']
- total = position['total_blocks']
-
- if progress == total == 0:
- raise KeyError
- except KeyError:
- try:
- progress = position['current_chapter']
- total = position['total_chapters']
- except KeyError:
- return
-
+ if position_percent:
return_pixmap = pie_chart.pixmapper(
- progress, total, self.temp_dir,
+ position_percent, self.temp_dir,
+ self.consider_read_at,
QtCore.Qt.SizeHintRole + 10)
return return_pixmap
@@ -218,6 +200,7 @@ class ProxyModelsCommonFunctions:
title = model.data(this_index, QtCore.Qt.UserRole)
author = model.data(this_index, QtCore.Qt.UserRole + 1)
tags = model.data(this_index, QtCore.Qt.UserRole + 4)
+ progress = model.data(this_index, QtCore.Qt.UserRole + 7)
directory_name = model.data(this_index, QtCore.Qt.UserRole + 10)
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12)
@@ -226,6 +209,10 @@ class ProxyModelsCommonFunctions:
if self.parent_model.sorting_box_position == 4 and not last_accessed:
return False
+ # Hide untouched files when sorting by progress
+ if self.parent_model.sorting_box_position == 5 and not progress:
+ return False
+
if self.parent_model.active_library_filters:
if directory_name not in self.parent_model.active_library_filters:
return False
diff --git a/lector/resources/pie_chart.py b/lector/resources/pie_chart.py
index ec93c10..5a2cb2d 100644
--- a/lector/resources/pie_chart.py
+++ b/lector/resources/pie_chart.py
@@ -94,16 +94,18 @@ def generate_pie(progress_percent, temp_dir=None):
return lSvg
-def pixmapper(progress, total, temp_dir, size):
+def pixmapper(position_percent, temp_dir, consider_read_at, size):
# A current_chapter of -1 implies the files does not exist
- # A chapter number == Total chapters implies the file is unread
- return_pixmap = None
+ # position_percent and consider_read_at are expected as a <1 decimal value
- if progress == -1:
+ return_pixmap = None
+ consider_read_at = consider_read_at / 100
+
+ if position_percent == -1:
return_pixmap = QtGui.QIcon(':/images/error.svg').pixmap(size)
return return_pixmap
- if progress >= .95 * total: # Consider book read @ 95% progress
+ if position_percent >= consider_read_at: # Consider book read @ 95% progress
return_pixmap = QtGui.QIcon(':/images/checkmark.svg').pixmap(size)
else:
@@ -111,8 +113,7 @@ def pixmapper(progress, total, temp_dir, size):
# See if saving the svg to disk can be avoided
# Maybe make the alignment a little more uniform across emblems
- progress_percent = int(progress * 100 / total)
- generate_pie(progress_percent, temp_dir)
+ generate_pie(int(position_percent * 100), temp_dir)
svg_path = os.path.join(temp_dir, 'lector_progress.svg')
return_pixmap = QtGui.QIcon(svg_path).pixmap(size - 4) ## The -4 looks more proportional
diff --git a/lector/resources/raw/settings.ui b/lector/resources/raw/settings.ui
index a79a80b..7a09e7c 100644
--- a/lector/resources/raw/settings.ui
+++ b/lector/resources/raw/settings.ui
@@ -6,7 +6,7 @@
0
0
- 1088
+ 1119
612
@@ -47,6 +47,74 @@
-
+
-
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Consider book read at percent
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 90
+
+
+ 95
+
+
+
+
+
+ -
+
+
-
+
+
+ Restart application to see changes
+
+
+ Icon theme:
+
+
+
+ -
+
+
+ Restart application to see changes
+
+
+ &Dark
+
+
+
+ -
+
+
+ Restart application to see changes
+
+
+ L&ight
+
+
+
+
+
+
+
-
-
@@ -88,40 +156,6 @@
-
-
-
-
-
-
-
-
- Restart application to see changes
-
-
- Icon theme:
-
-
-
- -
-
-
- Restart application to see changes
-
-
- &Dark
-
-
-
- -
-
-
- Restart application to see changes
-
-
- L&ight
-
-
-
-
-
-
diff --git a/lector/resources/settingswindow.py b/lector/resources/settingswindow.py
index 947f670..f2d5ff6 100644
--- a/lector/resources/settingswindow.py
+++ b/lector/resources/settingswindow.py
@@ -11,7 +11,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
- Dialog.resize(1088, 612)
+ Dialog.resize(1119, 612)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.listView = QtWidgets.QListView(Dialog)
@@ -46,6 +46,38 @@ class Ui_Dialog(object):
self.gridLayout_4.setObjectName("gridLayout_4")
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_13.setObjectName("horizontalLayout_13")
+ self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_14.setObjectName("horizontalLayout_14")
+ self.readAtLabel = QtWidgets.QLabel(self.groupBox)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.readAtLabel.sizePolicy().hasHeightForWidth())
+ self.readAtLabel.setSizePolicy(sizePolicy)
+ self.readAtLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
+ self.readAtLabel.setObjectName("readAtLabel")
+ self.horizontalLayout_14.addWidget(self.readAtLabel)
+ self.readAtPercent = QtWidgets.QSpinBox(self.groupBox)
+ self.readAtPercent.setMinimum(90)
+ self.readAtPercent.setProperty("value", 95)
+ self.readAtPercent.setObjectName("readAtPercent")
+ self.horizontalLayout_14.addWidget(self.readAtPercent)
+ self.horizontalLayout_13.addLayout(self.horizontalLayout_14)
+ self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_7.setObjectName("horizontalLayout_7")
+ self.label = QtWidgets.QLabel(self.groupBox)
+ self.label.setObjectName("label")
+ self.horizontalLayout_7.addWidget(self.label)
+ self.darkIconsRadio = QtWidgets.QRadioButton(self.groupBox)
+ self.darkIconsRadio.setObjectName("darkIconsRadio")
+ self.horizontalLayout_7.addWidget(self.darkIconsRadio)
+ self.lightIconsRadio = QtWidgets.QRadioButton(self.groupBox)
+ self.lightIconsRadio.setObjectName("lightIconsRadio")
+ self.horizontalLayout_7.addWidget(self.lightIconsRadio)
+ self.horizontalLayout_13.addLayout(self.horizontalLayout_7)
+ self.verticalLayout_2.addLayout(self.horizontalLayout_13)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.refreshLibrary = QtWidgets.QCheckBox(self.groupBox)
@@ -66,18 +98,6 @@ class Ui_Dialog(object):
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
- self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_7.setObjectName("horizontalLayout_7")
- self.label = QtWidgets.QLabel(self.groupBox)
- self.label.setObjectName("label")
- self.horizontalLayout_7.addWidget(self.label)
- self.darkIconsRadio = QtWidgets.QRadioButton(self.groupBox)
- self.darkIconsRadio.setObjectName("darkIconsRadio")
- self.horizontalLayout_7.addWidget(self.darkIconsRadio)
- self.lightIconsRadio = QtWidgets.QRadioButton(self.groupBox)
- self.lightIconsRadio.setObjectName("lightIconsRadio")
- self.horizontalLayout_7.addWidget(self.lightIconsRadio)
- self.horizontalLayout_9.addLayout(self.horizontalLayout_7)
self.autoTags = QtWidgets.QCheckBox(self.groupBox)
self.autoTags.setObjectName("autoTags")
self.horizontalLayout_9.addWidget(self.autoTags)
@@ -283,17 +303,18 @@ class Ui_Dialog(object):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Settings"))
self.groupBox.setTitle(_translate("Dialog", "Library"))
- self.refreshLibrary.setText(_translate("Dialog", "Startup: Refresh library"))
- self.fileRemember.setText(_translate("Dialog", "Remember open files"))
- self.coverShadows.setText(_translate("Dialog", "Cover shadows"))
- self.performCulling.setToolTip(_translate("Dialog", "Enabling reduces startup time and memory usage"))
- self.performCulling.setText(_translate("Dialog", "Load covers only when needed"))
+ self.readAtLabel.setText(_translate("Dialog", "Consider book read at percent"))
self.label.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.label.setText(_translate("Dialog", "Icon theme: "))
self.darkIconsRadio.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.darkIconsRadio.setText(_translate("Dialog", "&Dark"))
self.lightIconsRadio.setToolTip(_translate("Dialog", "Restart application to see changes"))
self.lightIconsRadio.setText(_translate("Dialog", "L&ight"))
+ self.refreshLibrary.setText(_translate("Dialog", "Startup: Refresh library"))
+ self.fileRemember.setText(_translate("Dialog", "Remember open files"))
+ self.coverShadows.setText(_translate("Dialog", "Cover shadows"))
+ self.performCulling.setToolTip(_translate("Dialog", "Enabling reduces startup time and memory usage"))
+ self.performCulling.setText(_translate("Dialog", "Load covers only when needed"))
self.autoTags.setText(_translate("Dialog", "Generate tags from files"))
self.groupBox_2.setTitle(_translate("Dialog", "Reading"))
self.hideScrollBars.setToolTip(_translate("Dialog", "Horizontal scrolling with Alt + Scroll\n"
diff --git a/lector/settings.py b/lector/settings.py
index 537f15e..fee4442 100644
--- a/lector/settings.py
+++ b/lector/settings.py
@@ -105,6 +105,7 @@ class Settings:
self.parent.settings['hide_scrollbars'] = literal_eval(self.settings.value(
'hideScrollBars', 'False').capitalize())
self.parent.settings['scroll_speed'] = int(self.settings.value('scrollSpeed', 7))
+ self.parent.settings['consider_read_at'] = int(self.settings.value('considerReadAt', 95))
self.settings.endGroup()
self.settings.beginGroup('dialogSettings')
@@ -176,6 +177,7 @@ class Settings:
self.settings.setValue('cachingEnabled', current_settings['caching_enabled'])
self.settings.setValue('hideScrollBars', current_settings['hide_scrollbars'])
self.settings.setValue('scrollSpeed', current_settings['scroll_speed'])
+ self.settings.setValue('considerReadAt', current_settings['consider_read_at'])
self.settings.endGroup()
self.settings.beginGroup('dialogSettings')
diff --git a/lector/settingsdialog.py b/lector/settingsdialog.py
index 15b9293..dedfcf1 100644
--- a/lector/settingsdialog.py
+++ b/lector/settingsdialog.py
@@ -92,6 +92,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.cachingEnabled.setChecked(self.parent.settings['caching_enabled'])
self.hideScrollBars.setChecked(self.parent.settings['hide_scrollbars'])
self.scrollSpeedSlider.setValue(self.parent.settings['scroll_speed'])
+ self.readAtPercent.setValue(self.parent.settings['consider_read_at'])
self.autoTags.clicked.connect(self.manage_checkboxes)
self.coverShadows.clicked.connect(self.manage_checkboxes)
@@ -101,6 +102,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
self.cachingEnabled.clicked.connect(self.manage_checkboxes)
self.hideScrollBars.clicked.connect(self.manage_checkboxes)
self.scrollSpeedSlider.valueChanged.connect(self.change_scroll_speed)
+ self.readAtPercent.valueChanged.connect(self.change_read_at)
# Generate the QStandardItemModel for the listView
self.listModel = QtGui.QStandardItemModel()
@@ -318,9 +320,12 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
2: 'hi'}
self.parent.settings['dictionary_language'] = language_dict[self.languageBox.currentIndex()]
- def change_scroll_speed(self, event):
+ def change_scroll_speed(self, event=None):
self.parent.settings['scroll_speed'] = self.scrollSpeedSlider.value()
+ def change_read_at(self, event=None):
+ self.parent.settings['consider_read_at'] = self.readAtPercent.value()
+
def manage_checkboxes(self, event=None):
sender = self.sender().objectName()
diff --git a/lector/threaded.py b/lector/threaded.py
index 4ec566c..b88d8db 100644
--- a/lector/threaded.py
+++ b/lector/threaded.py
@@ -130,6 +130,10 @@ class BackGroundCacheRefill(QtCore.QThread):
def __init__(self, image_cache, remove_value, filetype, book, all_pages, parent=None):
super(BackGroundCacheRefill, self).__init__(parent)
+ # TODO
+ # Return with only the first image in case of a cache miss
+ # Rebuilding the entire n image cache takes considerably longer
+
self.image_cache = image_cache
self.remove_value = remove_value
self.filetype = filetype
diff --git a/lector/toolbars.py b/lector/toolbars.py
index 8b73186..b404d10 100644
--- a/lector/toolbars.py
+++ b/lector/toolbars.py
@@ -426,13 +426,15 @@ class LibraryToolBar(QtWidgets.QToolBar):
self.searchBar.setObjectName('searchBar')
# Sorter
- title_string = self._translate('TableProxyModel', 'Title')
- author_string = self._translate('TableProxyModel', 'Author')
- year_string = self._translate('TableProxyModel', 'Year')
- newest_string = self._translate('TableProxyModel', 'Newest')
- lastread_string = self._translate('TableProxyModel', 'Last Read')
+ title_string = self._translate('LibraryToolBar', 'Title')
+ author_string = self._translate('LibraryToolBar', 'Author')
+ year_string = self._translate('LibraryToolBar', 'Year')
+ newest_string = self._translate('LibraryToolBar', 'Newest')
+ lastread_string = self._translate('LibraryToolBar', 'Last Read')
+ progress_string = self._translate('LibraryToolBar', 'Progress')
sorting_choices = [
- title_string, author_string, year_string, newest_string, lastread_string]
+ title_string, author_string, year_string,
+ newest_string, lastread_string, progress_string]
self.sortingBox = FixedComboBox(self)
self.sortingBox.addItems(sorting_choices)
diff --git a/lector/widgets.py b/lector/widgets.py
index a7002ae..9b5ab16 100644
--- a/lector/widgets.py
+++ b/lector/widgets.py
@@ -1022,11 +1022,8 @@ class PliantWidgetsCommonFunctions:
position_percentage = (self.pw.parent.metadata['position']['current_block'] /
self.pw.parent.metadata['position']['total_blocks'])
- # Update book metadata and position percentage
+ # Update position percentage
if model_index:
- self.main_window.lib_ref.view_model.setData(
- model_index[0], self.pw.parent.metadata, QtCore.Qt.UserRole + 3)
-
self.main_window.lib_ref.view_model.setData(
model_index[0], position_percentage, QtCore.Qt.UserRole + 7)