Implement sorting by last read
This commit is contained in:
1
TODO
1
TODO
@@ -45,6 +45,7 @@ TODO
|
|||||||
✓ Record progress
|
✓ Record progress
|
||||||
Search document using QTextCursor?
|
Search document using QTextCursor?
|
||||||
Use embedded fonts
|
Use embedded fonts
|
||||||
|
Cache multiple images
|
||||||
Graphical themes
|
Graphical themes
|
||||||
Comic view keyboard shortcuts
|
Comic view keyboard shortcuts
|
||||||
Comic view modes
|
Comic view modes
|
||||||
|
16
__main__.py
16
__main__.py
@@ -16,9 +16,6 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# TODO
|
|
||||||
# Consider using sender().text() instead of sender().objectName()
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -159,6 +156,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.addToolBar(self.bookToolBar)
|
self.addToolBar(self.bookToolBar)
|
||||||
|
|
||||||
# Make the correct toolbar visible
|
# Make the correct toolbar visible
|
||||||
|
self.current_tab = self.tabWidget.currentIndex()
|
||||||
self.tab_switch()
|
self.tab_switch()
|
||||||
self.tabWidget.currentChanged.connect(self.tab_switch)
|
self.tabWidget.currentChanged.connect(self.tab_switch)
|
||||||
|
|
||||||
@@ -481,6 +479,15 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.resizeEvent()
|
self.resizeEvent()
|
||||||
|
|
||||||
def tab_switch(self):
|
def tab_switch(self):
|
||||||
|
try:
|
||||||
|
if self.current_tab != 0:
|
||||||
|
self.tabWidget.widget(
|
||||||
|
self.current_tab).update_last_accessed_time()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.current_tab = self.tabWidget.currentIndex()
|
||||||
|
|
||||||
if self.tabWidget.currentIndex() == 0:
|
if self.tabWidget.currentIndex() == 0:
|
||||||
|
|
||||||
self.resizeEvent()
|
self.resizeEvent()
|
||||||
@@ -539,6 +546,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.database_path, [tab_metadata])
|
self.database_path, [tab_metadata])
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
|
self.tabWidget.widget(tab_index).update_last_accessed_time()
|
||||||
self.tabWidget.removeTab(tab_index)
|
self.tabWidget.removeTab(tab_index)
|
||||||
|
|
||||||
def set_toc_position(self, event=None):
|
def set_toc_position(self, event=None):
|
||||||
@@ -892,7 +900,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
checked = [i for i in directory_list if i[3] == QtCore.Qt.Checked]
|
checked = [i for i in directory_list if i[3] == QtCore.Qt.Checked]
|
||||||
filter_list = list(map(generate_name, checked))
|
filter_list = list(map(generate_name, checked))
|
||||||
filter_list.sort()
|
filter_list.sort()
|
||||||
filter_list.append('Manually added')
|
filter_list.append('Manually Added')
|
||||||
filter_actions = [QtWidgets.QAction(i, self.library_filter_menu) for i in filter_list]
|
filter_actions = [QtWidgets.QAction(i, self.library_filter_menu) for i in filter_list]
|
||||||
|
|
||||||
filter_all = QtWidgets.QAction('All', self.library_filter_menu)
|
filter_all = QtWidgets.QAction('All', self.library_filter_menu)
|
||||||
|
18
database.py
18
database.py
@@ -38,8 +38,8 @@ class DatabaseInit:
|
|||||||
# addition mode
|
# addition mode
|
||||||
self.database.execute(
|
self.database.execute(
|
||||||
"CREATE TABLE books \
|
"CREATE TABLE books \
|
||||||
(id INTEGER PRIMARY KEY, Title TEXT, Author TEXT, Year INTEGER, DateAdded TEXT, \
|
(id INTEGER PRIMARY KEY, Title TEXT, Author TEXT, Year INTEGER, DateAdded BLOB, \
|
||||||
Path TEXT, Position BLOB, ISBN TEXT, Tags TEXT, Hash TEXT, \
|
Path TEXT, Position BLOB, ISBN TEXT, Tags TEXT, Hash TEXT, LastAccessed BLOB,\
|
||||||
Bookmarks BLOB, CoverImage BLOB)")
|
Bookmarks BLOB, CoverImage BLOB)")
|
||||||
|
|
||||||
# CheckState is the standard QtCore.Qt.Checked / Unchecked
|
# CheckState is the standard QtCore.Qt.Checked / Unchecked
|
||||||
@@ -167,18 +167,22 @@ class DatabaseFunctions:
|
|||||||
|
|
||||||
self.close_database()
|
self.close_database()
|
||||||
|
|
||||||
def modify_position(self, hash_position_pairs):
|
def modify_position(self, hash_position_last_accessed):
|
||||||
for i in hash_position_pairs:
|
for i in hash_position_last_accessed:
|
||||||
file_hash = i[0]
|
file_hash = i[0]
|
||||||
position = i[1]
|
position = i[1]
|
||||||
|
last_accessed = i[2]
|
||||||
|
|
||||||
pickled_position = pickle.dumps(position)
|
position_bin = sqlite3.Binary(pickle.dumps(position))
|
||||||
|
last_accessed_bin = sqlite3.Binary(pickle.dumps(last_accessed))
|
||||||
|
|
||||||
|
sql_command = (
|
||||||
|
"UPDATE books SET Position = ?, LastAccessed = ? WHERE Hash = ?")
|
||||||
|
|
||||||
sql_command = "UPDATE books SET Position = ? WHERE Hash = ?"
|
|
||||||
try:
|
try:
|
||||||
self.database.execute(
|
self.database.execute(
|
||||||
sql_command,
|
sql_command,
|
||||||
[sqlite3.Binary(pickled_position), file_hash])
|
[position_bin, last_accessed_bin, file_hash])
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
print('SQLite is in rebellion, Commander')
|
print('SQLite is in rebellion, Commander')
|
||||||
return
|
return
|
||||||
|
16
library.py
16
library.py
@@ -42,7 +42,7 @@ class Library:
|
|||||||
books = database.DatabaseFunctions(
|
books = database.DatabaseFunctions(
|
||||||
self.parent.database_path).fetch_data(
|
self.parent.database_path).fetch_data(
|
||||||
('Title', 'Author', 'Year', 'DateAdded', 'Path',
|
('Title', 'Author', 'Year', 'DateAdded', 'Path',
|
||||||
'Position', 'ISBN', 'Tags', 'Hash',),
|
'Position', 'ISBN', 'Tags', 'Hash', 'LastAccessed'),
|
||||||
'books',
|
'books',
|
||||||
{'Title': ''},
|
{'Title': ''},
|
||||||
'LIKE')
|
'LIKE')
|
||||||
@@ -65,7 +65,7 @@ class Library:
|
|||||||
|
|
||||||
books.append([
|
books.append([
|
||||||
i[1]['title'], i[1]['author'], i[1]['year'], current_qdatetime,
|
i[1]['title'], i[1]['author'], i[1]['year'], current_qdatetime,
|
||||||
i[1]['path'], None, i[1]['isbn'], _tags, i[0]])
|
i[1]['path'], None, i[1]['isbn'], _tags, i[0], None])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
@@ -73,12 +73,12 @@ class Library:
|
|||||||
for i in books:
|
for i in books:
|
||||||
# The database query returns (or the extension data is)
|
# The database query returns (or the extension data is)
|
||||||
# an iterable with the following indices:
|
# an iterable with the following indices:
|
||||||
# Index 0 is the key ID is ignored
|
|
||||||
title = i[0]
|
title = i[0]
|
||||||
author = i[1]
|
author = i[1]
|
||||||
year = i[2]
|
year = i[2]
|
||||||
path = i[4]
|
path = i[4]
|
||||||
tags = i[7]
|
tags = i[7]
|
||||||
|
last_accessed = i[9]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
date_added = pickle.loads(i[3])
|
date_added = pickle.loads(i[3])
|
||||||
@@ -101,6 +101,7 @@ class Library:
|
|||||||
'isbn': i[6],
|
'isbn': i[6],
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'hash': i[8],
|
'hash': i[8],
|
||||||
|
'last_accessed': last_accessed,
|
||||||
'file_exists': file_exists}
|
'file_exists': file_exists}
|
||||||
|
|
||||||
tooltip_string = title + '\nAuthor: ' + author + '\nYear: ' + str(year)
|
tooltip_string = title + '\nAuthor: ' + author + '\nYear: ' + str(year)
|
||||||
@@ -129,6 +130,7 @@ class Library:
|
|||||||
item.setData(position, QtCore.Qt.UserRole + 7)
|
item.setData(position, QtCore.Qt.UserRole + 7)
|
||||||
item.setData(False, QtCore.Qt.UserRole + 8) # Is the cover being displayed?
|
item.setData(False, QtCore.Qt.UserRole + 8) # Is the cover being displayed?
|
||||||
item.setData(date_added, QtCore.Qt.UserRole + 9)
|
item.setData(date_added, QtCore.Qt.UserRole + 9)
|
||||||
|
item.setData(last_accessed, QtCore.Qt.UserRole + 12)
|
||||||
item.setIcon(QtGui.QIcon(img_pixmap))
|
item.setIcon(QtGui.QIcon(img_pixmap))
|
||||||
self.view_model.appendRow(item)
|
self.view_model.appendRow(item)
|
||||||
|
|
||||||
@@ -182,7 +184,8 @@ class Library:
|
|||||||
self.proxy_model.invalidateFilter()
|
self.proxy_model.invalidateFilter()
|
||||||
self.proxy_model.setFilterParams(
|
self.proxy_model.setFilterParams(
|
||||||
self.parent.libraryToolBar.searchBar.text(),
|
self.parent.libraryToolBar.searchBar.text(),
|
||||||
self.parent.active_library_filters)
|
self.parent.active_library_filters,
|
||||||
|
self.parent.libraryToolBar.sortingBox.currentIndex())
|
||||||
self.proxy_model.setFilterFixedString(
|
self.proxy_model.setFilterFixedString(
|
||||||
self.parent.libraryToolBar.searchBar.text())
|
self.parent.libraryToolBar.searchBar.text())
|
||||||
|
|
||||||
@@ -200,7 +203,8 @@ class Library:
|
|||||||
0: 0,
|
0: 0,
|
||||||
1: 1,
|
1: 1,
|
||||||
2: 2,
|
2: 2,
|
||||||
3: 9}
|
3: 9,
|
||||||
|
4: 12}
|
||||||
|
|
||||||
# Sorting according to roles and the drop down in the library toolbar
|
# Sorting according to roles and the drop down in the library toolbar
|
||||||
self.proxy_model.setSortRole(
|
self.proxy_model.setSortRole(
|
||||||
@@ -208,7 +212,7 @@ class Library:
|
|||||||
|
|
||||||
# This can be expanded to other fields by appending to the list
|
# This can be expanded to other fields by appending to the list
|
||||||
sort_order = QtCore.Qt.AscendingOrder
|
sort_order = QtCore.Qt.AscendingOrder
|
||||||
if self.parent.libraryToolBar.sortingBox.currentIndex() in [3]:
|
if self.parent.libraryToolBar.sortingBox.currentIndex() in [3, 4]:
|
||||||
sort_order = QtCore.Qt.DescendingOrder
|
sort_order = QtCore.Qt.DescendingOrder
|
||||||
|
|
||||||
self.proxy_model.sort(0, sort_order)
|
self.proxy_model.sort(0, sort_order)
|
||||||
|
@@ -27,10 +27,12 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
|
|||||||
super(ItemProxyModel, self).__init__(parent)
|
super(ItemProxyModel, self).__init__(parent)
|
||||||
self.filter_text = None
|
self.filter_text = None
|
||||||
self.active_library_filters = None
|
self.active_library_filters = None
|
||||||
|
self.sorting_position = None
|
||||||
|
|
||||||
def setFilterParams(self, filter_text, active_library_filters):
|
def setFilterParams(self, filter_text, active_library_filters, sorting_position):
|
||||||
self.filter_text = filter_text
|
self.filter_text = filter_text
|
||||||
self.active_library_filters = [i.lower() for i in active_library_filters]
|
self.active_library_filters = [i.lower() for i in active_library_filters]
|
||||||
|
self.sorting_position = sorting_position
|
||||||
|
|
||||||
def filterAcceptsRow(self, row, parent):
|
def filterAcceptsRow(self, row, parent):
|
||||||
model = self.sourceModel()
|
model = self.sourceModel()
|
||||||
@@ -42,6 +44,10 @@ class ItemProxyModel(QtCore.QSortFilterProxyModel):
|
|||||||
tags = model.data(this_index, QtCore.Qt.UserRole + 4)
|
tags = model.data(this_index, QtCore.Qt.UserRole + 4)
|
||||||
directory_name = model.data(this_index, QtCore.Qt.UserRole + 10)
|
directory_name = model.data(this_index, QtCore.Qt.UserRole + 10)
|
||||||
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
|
directory_tags = model.data(this_index, QtCore.Qt.UserRole + 11)
|
||||||
|
last_accessed = model.data(this_index, QtCore.Qt.UserRole + 12)
|
||||||
|
|
||||||
|
if self.sorting_position == 4 and not last_accessed:
|
||||||
|
return False
|
||||||
|
|
||||||
if self.active_library_filters:
|
if self.active_library_filters:
|
||||||
if directory_name not in self.active_library_filters:
|
if directory_name not in self.active_library_filters:
|
||||||
|
@@ -36,7 +36,9 @@ class BackGroundTabUpdate(QtCore.QThread):
|
|||||||
for i in self.all_metadata:
|
for i in self.all_metadata:
|
||||||
file_hash = i['hash']
|
file_hash = i['hash']
|
||||||
position = i['position']
|
position = i['position']
|
||||||
hash_position_pairs.append([file_hash, position])
|
last_accessed = i['last_accessed']
|
||||||
|
|
||||||
|
hash_position_pairs.append([file_hash, position, last_accessed])
|
||||||
|
|
||||||
database.DatabaseFunctions(
|
database.DatabaseFunctions(
|
||||||
self.database_path).modify_position(hash_position_pairs)
|
self.database_path).modify_position(hash_position_pairs)
|
||||||
|
31
widgets.py
31
widgets.py
@@ -333,7 +333,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
|
|||||||
self.searchBar.setObjectName('searchBar')
|
self.searchBar.setObjectName('searchBar')
|
||||||
|
|
||||||
# Sorter
|
# Sorter
|
||||||
sorting_choices = ['Title', 'Author', 'Year', 'Newest']
|
sorting_choices = ['Title', 'Author', 'Year', 'Newest', 'Last read']
|
||||||
self.sortingBox = FixedComboBox(self)
|
self.sortingBox = FixedComboBox(self)
|
||||||
self.sortingBox.addItems(sorting_choices)
|
self.sortingBox.addItems(sorting_choices)
|
||||||
self.sortingBox.setObjectName('sortingBox')
|
self.sortingBox.setObjectName('sortingBox')
|
||||||
@@ -374,10 +374,6 @@ class FixedPushButton(QtWidgets.QPushButton):
|
|||||||
|
|
||||||
class Tab(QtWidgets.QWidget):
|
class Tab(QtWidgets.QWidget):
|
||||||
def __init__(self, metadata, parent=None):
|
def __init__(self, metadata, parent=None):
|
||||||
# TODO
|
|
||||||
# Take hint from a position function argument to open the book
|
|
||||||
# at a specific page
|
|
||||||
|
|
||||||
super(Tab, self).__init__(parent)
|
super(Tab, self).__init__(parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.metadata = metadata # Save progress data into this dictionary
|
self.metadata = metadata # Save progress data into this dictionary
|
||||||
@@ -387,10 +383,10 @@ class Tab(QtWidgets.QWidget):
|
|||||||
self.horzLayout.setOrientation(QtCore.Qt.Horizontal)
|
self.horzLayout.setOrientation(QtCore.Qt.Horizontal)
|
||||||
self.masterLayout.addWidget(self.horzLayout)
|
self.masterLayout.addWidget(self.horzLayout)
|
||||||
|
|
||||||
|
self.metadata['last_accessed'] = QtCore.QDateTime().currentDateTime()
|
||||||
|
|
||||||
position = self.metadata['position']
|
position = self.metadata['position']
|
||||||
|
|
||||||
# TODO
|
|
||||||
# Chapter position and vertical scrollbar position
|
|
||||||
if position:
|
if position:
|
||||||
current_chapter = position['current_chapter']
|
current_chapter = position['current_chapter']
|
||||||
else:
|
else:
|
||||||
@@ -461,6 +457,19 @@ class Tab(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.contentView.setFocus()
|
self.contentView.setFocus()
|
||||||
|
|
||||||
|
def update_last_accessed_time(self):
|
||||||
|
self.metadata['last_accessed'] = QtCore.QDateTime().currentDateTime()
|
||||||
|
|
||||||
|
start_index = self.window().lib_ref.view_model.index(0, 0)
|
||||||
|
matching_item = self.window().lib_ref.view_model.match(
|
||||||
|
start_index,
|
||||||
|
QtCore.Qt.UserRole + 6,
|
||||||
|
self.metadata['hash'],
|
||||||
|
1, QtCore.Qt.MatchExactly)
|
||||||
|
|
||||||
|
self.window().lib_ref.view_model.setData(
|
||||||
|
matching_item[0], self.metadata['last_accessed'], QtCore.Qt.UserRole + 12)
|
||||||
|
|
||||||
def set_scroll_value(self, switch_widgets=True):
|
def set_scroll_value(self, switch_widgets=True):
|
||||||
if switch_widgets:
|
if switch_widgets:
|
||||||
previous_widget = self.window().tabWidget.currentWidget()
|
previous_widget = self.window().tabWidget.currentWidget()
|
||||||
@@ -489,7 +498,7 @@ class Tab(QtWidgets.QWidget):
|
|||||||
def generate_position(self):
|
def generate_position(self):
|
||||||
total_chapters = len(self.metadata['content'].keys())
|
total_chapters = len(self.metadata['content'].keys())
|
||||||
# TODO
|
# TODO
|
||||||
# Calculate lines
|
# Calculate lines to incorporate into progress
|
||||||
self.metadata['position'] = {
|
self.metadata['position'] = {
|
||||||
'current_chapter': 1,
|
'current_chapter': 1,
|
||||||
'current_line': 0,
|
'current_line': 0,
|
||||||
@@ -754,9 +763,13 @@ class PliantWidgetsCommonFunctions():
|
|||||||
self.main_window = main_window
|
self.main_window = main_window
|
||||||
|
|
||||||
def wheelEvent(self, event, are_we_doing_images_only):
|
def wheelEvent(self, event, are_we_doing_images_only):
|
||||||
|
ignore_events = 20
|
||||||
|
if are_we_doing_images_only:
|
||||||
|
ignore_events = 10
|
||||||
|
|
||||||
if self.pw.ignore_wheel_event:
|
if self.pw.ignore_wheel_event:
|
||||||
self.pw.ignore_wheel_event_number += 1
|
self.pw.ignore_wheel_event_number += 1
|
||||||
if self.pw.ignore_wheel_event_number > 20:
|
if self.pw.ignore_wheel_event_number > ignore_events:
|
||||||
self.pw.ignore_wheel_event = False
|
self.pw.ignore_wheel_event = False
|
||||||
self.pw.ignore_wheel_event_number = 0
|
self.pw.ignore_wheel_event_number = 0
|
||||||
return
|
return
|
||||||
|
Reference in New Issue
Block a user