Read indicators, progress tracking, database closing
This commit is contained in:
		
							
								
								
									
										60
									
								
								__main__.py
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								__main__.py
									
									
									
									
									
								
							| @@ -87,6 +87,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|         self.viewModel = None |         self.viewModel = None | ||||||
|         self.lib_ref = Library(self) |         self.lib_ref = Library(self) | ||||||
|  |  | ||||||
|  |         # Application wide temporary directory | ||||||
|  |         self.temp_dir = QtCore.QTemporaryDir() | ||||||
|  |  | ||||||
|         # Library toolbar |         # Library toolbar | ||||||
|         self.libraryToolBar = LibraryToolBar(self) |         self.libraryToolBar = LibraryToolBar(self) | ||||||
|         self.libraryToolBar.addButton.triggered.connect(self.add_books) |         self.libraryToolBar.addButton.triggered.connect(self.add_books) | ||||||
| @@ -128,15 +131,14 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|         # TODO |         # TODO | ||||||
|         # It's possible to add a widget to the Library tab here |         # It's possible to add a widget to the Library tab here | ||||||
|         self.tabWidget.tabBar().setTabButton(0, QtWidgets.QTabBar.RightSide, None) |         self.tabWidget.tabBar().setTabButton(0, QtWidgets.QTabBar.RightSide, None) | ||||||
|         self.tabWidget.tabCloseRequested.connect(self.close_tab) |         self.tabWidget.tabCloseRequested.connect(self.tab_close) | ||||||
|  |  | ||||||
|         # ListView |         # ListView | ||||||
|         # self.listView.setSpacing(0) |  | ||||||
|         self.listView.setGridSize(QtCore.QSize(175, 240)) |         self.listView.setGridSize(QtCore.QSize(175, 240)) | ||||||
|         self.listView.setMouseTracking(True) |         self.listView.setMouseTracking(True) | ||||||
|         self.listView.verticalScrollBar().setSingleStep(7) |         self.listView.verticalScrollBar().setSingleStep(7) | ||||||
|         self.listView.doubleClicked.connect(self.list_doubleclick) |         self.listView.doubleClicked.connect(self.list_doubleclick) | ||||||
|         self.listView.setItemDelegate(LibraryDelegate()) |         self.listView.setItemDelegate(LibraryDelegate(self.temp_dir.path())) | ||||||
|         self.reload_listview() |         self.reload_listview() | ||||||
|  |  | ||||||
|         # Keyboard shortcuts |         # Keyboard shortcuts | ||||||
| @@ -262,7 +264,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|             self.bookToolBar.tocBox.clear() |             self.bookToolBar.tocBox.clear() | ||||||
|             self.bookToolBar.tocBox.addItems(current_toc) |             self.bookToolBar.tocBox.addItems(current_toc) | ||||||
|             if current_position: |             if current_position: | ||||||
|                 self.bookToolBar.tocBox.setCurrentIndex(current_position) |                 self.bookToolBar.tocBox.setCurrentIndex(current_position['current_chapter'] - 1) | ||||||
|             self.bookToolBar.tocBox.blockSignals(False) |             self.bookToolBar.tocBox.blockSignals(False) | ||||||
|  |  | ||||||
|             self.format_contentView() |             self.format_contentView() | ||||||
| @@ -270,18 +272,46 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|             self.statusMessage.setText( |             self.statusMessage.setText( | ||||||
|                 current_author + ' - ' + current_title) |                 current_author + ' - ' + current_title) | ||||||
|  |  | ||||||
|  |     def tab_close(self, tab_index): | ||||||
|  |         self.database_update_position(tab_index) | ||||||
|  |         temp_dir = self.tabWidget.widget(tab_index).metadata['temp_dir'] | ||||||
|  |         if temp_dir: | ||||||
|  |             shutil.rmtree(temp_dir) | ||||||
|  |         self.tabWidget.removeTab(tab_index) | ||||||
|  |  | ||||||
|     def set_toc_position(self, event=None): |     def set_toc_position(self, event=None): | ||||||
|         self.tabWidget.widget( |  | ||||||
|             self.tabWidget.currentIndex()).metadata[ |  | ||||||
|                 'position'] = event |  | ||||||
|  |  | ||||||
|         chapter_name = self.bookToolBar.tocBox.currentText() |         chapter_name = self.bookToolBar.tocBox.currentText() | ||||||
|  |  | ||||||
|         current_tab = self.tabWidget.widget(self.tabWidget.currentIndex()) |         current_tab = self.tabWidget.widget(self.tabWidget.currentIndex()) | ||||||
|         required_content = current_tab.metadata['content'][chapter_name] |         required_content = current_tab.metadata['content'][chapter_name] | ||||||
|  |  | ||||||
|  |         # We're also updating the underlying model to have real-time | ||||||
|  |         # updates on the read status | ||||||
|  |         # Find index of the model item that corresponds to the tab | ||||||
|  |         start_index = self.viewModel.index(0, 0) | ||||||
|  |         matching_item = self.viewModel.match( | ||||||
|  |             start_index, | ||||||
|  |             QtCore.Qt.UserRole + 6, | ||||||
|  |             current_tab.metadata['hash'], | ||||||
|  |             1, QtCore.Qt.MatchExactly) | ||||||
|  |         if matching_item: | ||||||
|  |             model_row = matching_item[0].row() | ||||||
|  |             model_index = self.viewModel.index(model_row, 0) | ||||||
|  |  | ||||||
|  |         current_tab.metadata[ | ||||||
|  |             'position']['current_chapter'] = self.bookToolBar.tocBox.currentIndex() + 1 | ||||||
|  |         self.viewModel.setData( | ||||||
|  |             model_index, current_tab.metadata['position'], QtCore.Qt.UserRole + 7) | ||||||
|  |  | ||||||
|         current_tab.contentView.verticalScrollBar().setValue(0) |         current_tab.contentView.verticalScrollBar().setValue(0) | ||||||
|         current_tab.contentView.setHtml(required_content) |         current_tab.contentView.setHtml(required_content) | ||||||
|  |  | ||||||
|  |     def database_update_position(self, tab_index): | ||||||
|  |         tab_metadata = self.tabWidget.widget(tab_index).metadata | ||||||
|  |         file_hash = tab_metadata['hash'] | ||||||
|  |         position = tab_metadata['position'] | ||||||
|  |         database.DatabaseFunctions( | ||||||
|  |             self.database_path).modify_position(file_hash, position) | ||||||
|  |  | ||||||
|     def set_fullscreen(self): |     def set_fullscreen(self): | ||||||
|         current_tab = self.tabWidget.currentIndex() |         current_tab = self.tabWidget.currentIndex() | ||||||
|         current_tab_widget = self.tabWidget.widget(current_tab) |         current_tab_widget = self.tabWidget.widget(current_tab) | ||||||
| @@ -294,9 +324,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|  |  | ||||||
|     def list_doubleclick(self, myindex): |     def list_doubleclick(self, myindex): | ||||||
|         index = self.listView.model().index(myindex.row(), 0) |         index = self.listView.model().index(myindex.row(), 0) | ||||||
|         state = self.listView.model().data(index, QtCore.Qt.UserRole + 5) |         file_exists = self.listView.model().data(index, QtCore.Qt.UserRole + 5) | ||||||
|  |  | ||||||
|         if state == 'deleted': |         if not file_exists: | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         metadata = self.listView.model().data(index, QtCore.Qt.UserRole + 3) |         metadata = self.listView.model().data(index, QtCore.Qt.UserRole + 3) | ||||||
| @@ -316,12 +346,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|         self.tabWidget.setCurrentWidget(tab_ref) |         self.tabWidget.setCurrentWidget(tab_ref) | ||||||
|         self.format_contentView() |         self.format_contentView() | ||||||
|  |  | ||||||
|     def close_tab(self, tab_index): |  | ||||||
|         temp_dir = self.tabWidget.widget(tab_index).metadata['temp_dir'] |  | ||||||
|         if temp_dir: |  | ||||||
|             shutil.rmtree(temp_dir) |  | ||||||
|         self.tabWidget.removeTab(tab_index) |  | ||||||
|  |  | ||||||
|     def get_color(self): |     def get_color(self): | ||||||
|         signal_sender = self.sender().objectName() |         signal_sender = self.sender().objectName() | ||||||
|         profile_index = self.bookToolBar.profileBox.currentIndex() |         profile_index = self.bookToolBar.profileBox.currentIndex() | ||||||
| @@ -427,10 +451,12 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): | |||||||
|     def closeEvent(self, event=None): |     def closeEvent(self, event=None): | ||||||
|         # All tabs must be iterated upon here |         # All tabs must be iterated upon here | ||||||
|         for i in range(1, self.tabWidget.count()): |         for i in range(1, self.tabWidget.count()): | ||||||
|  |             self.database_update_position(i) | ||||||
|             tab_metadata = self.tabWidget.widget(i).metadata |             tab_metadata = self.tabWidget.widget(i).metadata | ||||||
|             if tab_metadata['temp_dir']: |             if tab_metadata['temp_dir']: | ||||||
|                 shutil.rmtree(tab_metadata['temp_dir']) |                 shutil.rmtree(tab_metadata['temp_dir']) | ||||||
|  |  | ||||||
|  |         self.temp_dir.remove() | ||||||
|         Settings(self).save_settings() |         Settings(self).save_settings() | ||||||
|         QtWidgets.qApp.exit() |         QtWidgets.qApp.exit() | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								database.py
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								database.py
									
									
									
									
									
								
							| @@ -1,7 +1,8 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
|  |  | ||||||
| import sqlite3 |  | ||||||
| import os | import os | ||||||
|  | import pickle | ||||||
|  | import sqlite3 | ||||||
|  |  | ||||||
|  |  | ||||||
| class DatabaseInit: | class DatabaseInit: | ||||||
| @@ -17,7 +18,7 @@ class DatabaseInit: | |||||||
|         self.database.execute( |         self.database.execute( | ||||||
|             "CREATE TABLE books \ |             "CREATE TABLE books \ | ||||||
|             (id INTEGER PRIMARY KEY, Title TEXT, Author TEXT, Year INTEGER, \ |             (id INTEGER PRIMARY KEY, Title TEXT, Author TEXT, Year INTEGER, \ | ||||||
|             Path TEXT, Position TEXT, ISBN TEXT, Tags TEXT, Hash TEXT, CoverImage BLOB)") |             Path TEXT, Position BLOB, ISBN TEXT, Tags TEXT, Hash TEXT, CoverImage BLOB)") | ||||||
|         self.database.execute( |         self.database.execute( | ||||||
|             "CREATE TABLE cache \ |             "CREATE TABLE cache \ | ||||||
|             (id INTEGER PRIMARY KEY, Name TEXT, Path TEXT, CachedDict BLOB)") |             (id INTEGER PRIMARY KEY, Name TEXT, Path TEXT, CachedDict BLOB)") | ||||||
| @@ -62,6 +63,7 @@ class DatabaseFunctions: | |||||||
|                      path, isbn, book_hash, sqlite3.Binary(cover)]) |                      path, isbn, book_hash, sqlite3.Binary(cover)]) | ||||||
|  |  | ||||||
|         self.database.commit() |         self.database.commit() | ||||||
|  |         self.close_database() | ||||||
|  |  | ||||||
|     def fetch_data(self, columns, table, selection_criteria, equivalence, fetch_one=False): |     def fetch_data(self, columns, table, selection_criteria, equivalence, fetch_one=False): | ||||||
|         # columns is a tuple that will be passed as a comma separated list |         # columns is a tuple that will be passed as a comma separated list | ||||||
| @@ -111,6 +113,16 @@ class DatabaseFunctions: | |||||||
|         except KeyError: |         except KeyError: | ||||||
|             print('SQLite is in rebellion, Commander') |             print('SQLite is in rebellion, Commander') | ||||||
|  |  | ||||||
|  |         self.close_database() | ||||||
|  |  | ||||||
|  |     def modify_position(self, file_hash, position): | ||||||
|  |         pickled_position = pickle.dumps(position) | ||||||
|  |  | ||||||
|  |         sql_command = "UPDATE books SET Position = ? WHERE Hash = ?" | ||||||
|  |         self.database.execute(sql_command, [sqlite3.Binary(pickled_position), file_hash]) | ||||||
|  |         self.database.commit() | ||||||
|  |         self.close_database() | ||||||
|  |  | ||||||
|     def delete_from_database(self, file_hashes): |     def delete_from_database(self, file_hashes): | ||||||
|         # file_hashes is expected as a list that will be iterated upon |         # file_hashes is expected as a list that will be iterated upon | ||||||
|         # This should enable multiple deletion |         # This should enable multiple deletion | ||||||
| @@ -119,3 +131,8 @@ class DatabaseFunctions: | |||||||
|             self.database.execute( |             self.database.execute( | ||||||
|                 f"DELETE FROM books WHERE Hash = '{i}'") |                 f"DELETE FROM books WHERE Hash = '{i}'") | ||||||
|         self.database.commit() |         self.database.commit() | ||||||
|  |         self.close_database() | ||||||
|  |  | ||||||
|  |     def close_database(self): | ||||||
|  |         self.database.execute("VACUUM") | ||||||
|  |         self.database.close() | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								pie_chart.py
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								pie_chart.py
									
									
									
									
									
								
							| @@ -1,13 +1,15 @@ | |||||||
| # Modified from: http://drumcoder.co.uk/blog/2010/nov/16/python-code-generate-svg-pie-chart/ | # Modified from: http://drumcoder.co.uk/blog/2010/nov/16/python-code-generate-svg-pie-chart/ | ||||||
|  |  | ||||||
|  | import os | ||||||
| import math | import math | ||||||
|  |  | ||||||
| class GeneratePie(): | class GeneratePie(): | ||||||
|     def __init__(self, progress_percent): |     def __init__(self, progress_percent, temp_dir=None): | ||||||
|         self.progress_percent = int(progress_percent) |         self.progress_percent = int(progress_percent) | ||||||
|  |         self.temp_dir = temp_dir | ||||||
|  |  | ||||||
|     def generate(self): |     def generate(self): | ||||||
|         lSlices = (100 - self.progress_percent, self.progress_percent)  # percentages to show in pie |         lSlices = (self.progress_percent, 100 - self.progress_percent)  # percentages to show in pie | ||||||
|  |  | ||||||
|         lOffsetX = 150 |         lOffsetX = 150 | ||||||
|         lOffsetY = 150 |         lOffsetY = 150 | ||||||
| @@ -57,7 +59,7 @@ class GeneratePie(): | |||||||
|  |  | ||||||
|             lPath = "%s %s %s" % (lLineOne, lArc, lLineTwo) |             lPath = "%s %s %s" % (lLineOne, lArc, lLineTwo) | ||||||
|             lGradient = GRADIENTS[lIndex] |             lGradient = GRADIENTS[lIndex] | ||||||
|             lSvgPath += "<path d='%s' style='stroke:#2c2c2c; fill:url(#%s);'/>" % ( |             lSvgPath += "<path d='%s' style='stroke:#c579be; fill:url(#%s);'/>" % ( | ||||||
|                 lPath, lGradient) |                 lPath, lGradient) | ||||||
|             lIndex += 1 |             lIndex += 1 | ||||||
|  |  | ||||||
| @@ -66,20 +68,27 @@ class GeneratePie(): | |||||||
|             xmlns:xlink="http://www.w3.org/1999/xlink"> |             xmlns:xlink="http://www.w3.org/1999/xlink"> | ||||||
|         <defs> |         <defs> | ||||||
|             <radialGradient id="myRadialGradientGreen" r="65%%" cx="0" cy="0" spreadMethod="pad"> |             <radialGradient id="myRadialGradientGreen" r="65%%" cx="0" cy="0" spreadMethod="pad"> | ||||||
|             <stop offset="0%%"   stop-color="#2c2c2c" stop-opacity="1"/> |             <stop offset="0%%"   stop-color="#c579be" stop-opacity="1"/> | ||||||
|             <stop offset="100%%" stop-color="#2c2c2c" stop-opacity="1" /> |             <stop offset="100%%" stop-color="#c579be" stop-opacity="1" /> | ||||||
|             </radialGradient> |             </radialGradient> | ||||||
|         </defs> |         </defs> | ||||||
|         <defs> |         <defs> | ||||||
|             <radialGradient id="myRadialGradientOrange" r="65%%" cx="0" cy="0" spreadMethod="pad"> |             <radialGradient id="myRadialGradientOrange" r="65%%" cx="0" cy="0" spreadMethod="pad"> | ||||||
|             <stop offset="0%%"   stop-color="#4caf50" stop-opacity="1"/> |             <stop offset="0%%"   stop-color="#6c4268" stop-opacity="1"/> | ||||||
|             <stop offset="100%%" stop-color="#4caf50" stop-opacity="1" /> |             <stop offset="100%%" stop-color="#6c4268" stop-opacity="1" /> | ||||||
|             </radialGradient> |             </radialGradient> | ||||||
|         </defs> |         </defs> | ||||||
|  |  | ||||||
|         %s |         %s | ||||||
|         <!--  <circle cx="%d" cy="%d" r="100" style="stroke:#4caf50; fill:none;"/> --> |         <!--  <circle cx="%d" cy="%d" r="100" style="stroke:#6c4268; fill:none;"/> --> | ||||||
|         </svg> |         </svg> | ||||||
|         """ % (lSvgPath, lOffsetX, lOffsetY) |         """ % (lSvgPath, lOffsetX, lOffsetY) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if self.temp_dir: | ||||||
|  |             svg_path = os.path.join(self.temp_dir, 'lector_progress.svg') | ||||||
|  |             lFile = open(svg_path, 'w') | ||||||
|  |             lFile.write(lSvg) | ||||||
|  |             lFile.close() | ||||||
|  |         else: | ||||||
|             return lSvg |             return lSvg | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| # See if you want to include a hash of the book's name and author | # See if you want to include a hash of the book's name and author | ||||||
|  |  | ||||||
| import os | import os | ||||||
|  | import pickle | ||||||
| import hashlib | import hashlib | ||||||
| from multiprocessing.dummy import Pool | from multiprocessing.dummy import Pool | ||||||
|  |  | ||||||
| @@ -18,6 +19,7 @@ import database | |||||||
| # get_cover_image() | # get_cover_image() | ||||||
| # get_isbn() | # get_isbn() | ||||||
| # get_contents() - Should return a tuple with 0: TOC 1: Deletable temp_directory | # get_contents() - Should return a tuple with 0: TOC 1: Deletable temp_directory | ||||||
|  |  | ||||||
| from parsers.epub import ParseEPUB | from parsers.epub import ParseEPUB | ||||||
| from parsers.cbz import ParseCBZ | from parsers.cbz import ParseCBZ | ||||||
|  |  | ||||||
| @@ -57,7 +59,12 @@ class BookSorter: | |||||||
|                 {'Hash': file_hash}, |                 {'Hash': file_hash}, | ||||||
|                 'EQUALS', |                 'EQUALS', | ||||||
|                 True) |                 True) | ||||||
|         return position |  | ||||||
|  |         if position: | ||||||
|  |             position_dict = pickle.loads(position) | ||||||
|  |             return position_dict | ||||||
|  |         else: | ||||||
|  |             return None | ||||||
|  |  | ||||||
|     def read_book(self, filename): |     def read_book(self, filename): | ||||||
|         # filename is expected as a string containg the |         # filename is expected as a string containg the | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
|  |  | ||||||
| import os | import os | ||||||
|  | import pickle | ||||||
| import database | import database | ||||||
| from PyQt5 import QtWidgets, QtGui, QtCore | from PyQt5 import QtWidgets, QtGui, QtCore | ||||||
|  |  | ||||||
| @@ -11,12 +12,11 @@ class Library: | |||||||
|         self.proxy_model = None |         self.proxy_model = None | ||||||
|  |  | ||||||
|     def generate_model(self): |     def generate_model(self): | ||||||
|         # TODO |  | ||||||
|         # Use QItemdelegates to show book read progress |  | ||||||
|  |  | ||||||
|         # The QlistView widget needs to be populated |         # The QlistView widget needs to be populated | ||||||
|         # with a model that inherits from QStandardItemModel |         # with a model that inherits from QStandardItemModel | ||||||
|         self.parent_window.viewModel = QtGui.QStandardItemModel() |         # self.parent_window.viewModel = QtGui.QStandardItemModel() | ||||||
|  |         self.parent_window.viewModel = MyAbsModel() | ||||||
|  |  | ||||||
|         books = database.DatabaseFunctions( |         books = database.DatabaseFunctions( | ||||||
|             self.parent_window.database_path).fetch_data( |             self.parent_window.database_path).fetch_data( | ||||||
|                 ('*',), |                 ('*',), | ||||||
| @@ -37,21 +37,19 @@ class Library: | |||||||
|             path = i[4] |             path = i[4] | ||||||
|             tags = i[6] |             tags = i[6] | ||||||
|             cover = i[9] |             cover = i[9] | ||||||
|             progress = None  # TODO |  | ||||||
|                              # Leave at None for an untouched book |             position = i[5] | ||||||
|                              # 'completed' for a completed book |             if position: | ||||||
|                              # whatever else is here can be used |                 position = pickle.loads(position) | ||||||
|                              # to remember position |  | ||||||
|                              # Maybe get from the position param |  | ||||||
|  |  | ||||||
|             all_metadata = { |             all_metadata = { | ||||||
|                 'title': i[1], |                 'title': title, | ||||||
|                 'author': i[2], |                 'author': author, | ||||||
|                 'year': i[3], |                 'year': year, | ||||||
|                 'path': i[4], |                 'path': path, | ||||||
|                 'position': i[5], |                 'position': position, | ||||||
|                 'isbn': i[6], |                 'isbn': i[6], | ||||||
|                 'tags': i[7], |                 'tags': tags, | ||||||
|                 'hash': i[8]} |                 'hash': i[8]} | ||||||
|  |  | ||||||
|             tooltip_string = title + '\nAuthor: ' + author + '\nYear: ' + str(year) |             tooltip_string = title + '\nAuthor: ' + author + '\nYear: ' + str(year) | ||||||
| @@ -64,19 +62,7 @@ class Library: | |||||||
|             if tags: |             if tags: | ||||||
|                 search_workaround += tags |                 search_workaround += tags | ||||||
|  |  | ||||||
|             # Generate book state for passing onto the QStyledItemDelegate |             file_exists = os.path.exists(path) | ||||||
|             def generate_book_state(path, progress): |  | ||||||
|                 if not os.path.exists(path): |  | ||||||
|                     return 'deleted' |  | ||||||
|  |  | ||||||
|                 if progress: |  | ||||||
|                     if progress == 'completed': |  | ||||||
|                         return 'completed' |  | ||||||
|                     else: |  | ||||||
|                         return 'inprogress' |  | ||||||
|                 else: |  | ||||||
|                     return None |  | ||||||
|             state = generate_book_state(path, progress) |  | ||||||
|  |  | ||||||
|             # Generate image pixmap and then pass it to the widget |             # Generate image pixmap and then pass it to the widget | ||||||
|             # as a QIcon |             # as a QIcon | ||||||
| @@ -95,7 +81,9 @@ class Library: | |||||||
|             item.setData(year, QtCore.Qt.UserRole + 2) |             item.setData(year, QtCore.Qt.UserRole + 2) | ||||||
|             item.setData(all_metadata, QtCore.Qt.UserRole + 3) |             item.setData(all_metadata, QtCore.Qt.UserRole + 3) | ||||||
|             item.setData(search_workaround, QtCore.Qt.UserRole + 4) |             item.setData(search_workaround, QtCore.Qt.UserRole + 4) | ||||||
|             item.setData(state, QtCore.Qt.UserRole + 5) |             item.setData(file_exists, QtCore.Qt.UserRole + 5) | ||||||
|  |             item.setData(i[8], QtCore.Qt.UserRole + 6)  # File hash | ||||||
|  |             item.setData(position, QtCore.Qt.UserRole + 7) | ||||||
|             item.setIcon(QtGui.QIcon(img_pixmap)) |             item.setIcon(QtGui.QIcon(img_pixmap)) | ||||||
|             self.parent_window.viewModel.appendRow(item) |             self.parent_window.viewModel.appendRow(item) | ||||||
|  |  | ||||||
| @@ -198,3 +186,9 @@ class Settings: | |||||||
|             current_profile3]) |             current_profile3]) | ||||||
|         self.settings.setValue('currentProfileIndex', current_profile_index) |         self.settings.setValue('currentProfileIndex', current_profile_index) | ||||||
|         self.settings.endGroup() |         self.settings.endGroup() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MyAbsModel(QtGui.QStandardItemModel, QtCore.QAbstractItemModel): | ||||||
|  |     def __init__(self, parent=None): | ||||||
|  |         # We're using this to be able to access the match() method | ||||||
|  |         super(MyAbsModel, self).__init__(parent) | ||||||
|   | |||||||
							
								
								
									
										64
									
								
								widgets.py
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								widgets.py
									
									
									
									
									
								
							| @@ -1,7 +1,11 @@ | |||||||
| #!usr/bin/env python3 | #!usr/bin/env python3 | ||||||
|  |  | ||||||
|  | import os | ||||||
| from PyQt5 import QtWidgets, QtGui, QtCore | from PyQt5 import QtWidgets, QtGui, QtCore | ||||||
|  |  | ||||||
|  | import pie_chart | ||||||
|  |  | ||||||
|  |  | ||||||
| class BookToolBar(QtWidgets.QToolBar): | class BookToolBar(QtWidgets.QToolBar): | ||||||
|     def __init__(self, parent=None): |     def __init__(self, parent=None): | ||||||
|         super(BookToolBar, self).__init__(parent) |         super(BookToolBar, self).__init__(parent) | ||||||
| @@ -280,10 +284,15 @@ class Tab(QtWidgets.QWidget): | |||||||
|  |  | ||||||
|         # TODO |         # TODO | ||||||
|         # Chapter position and vertical scrollbar position |         # Chapter position and vertical scrollbar position | ||||||
|         if not position: |         if position: | ||||||
|             first_chapter_name = list(self.metadata['content'])[0] |             current_chapter = position['current_chapter'] | ||||||
|             first_chapter_content = self.metadata['content'][first_chapter_name] |         else: | ||||||
|             self.contentView.setHtml(first_chapter_content) |             self.generate_position() | ||||||
|  |             current_chapter = 1 | ||||||
|  |  | ||||||
|  |         chapter_name = list(self.metadata['content'])[current_chapter - 1] | ||||||
|  |         chapter_content = self.metadata['content'][chapter_name] | ||||||
|  |         self.contentView.setHtml(chapter_content) | ||||||
|  |  | ||||||
|         self.gridLayout.addWidget(self.contentView, 0, 0, 1, 1) |         self.gridLayout.addWidget(self.contentView, 0, 0, 1, 1) | ||||||
|         self.parent.addTab(self, title) |         self.parent.addTab(self, title) | ||||||
| @@ -293,6 +302,17 @@ class Tab(QtWidgets.QWidget): | |||||||
|         self.exit_fs.setContext(QtCore.Qt.ApplicationShortcut) |         self.exit_fs.setContext(QtCore.Qt.ApplicationShortcut) | ||||||
|         self.exit_fs.activated.connect(self.exit_fullscreen) |         self.exit_fs.activated.connect(self.exit_fullscreen) | ||||||
|  |  | ||||||
|  |     def generate_position(self): | ||||||
|  |         total_chapters = len(self.metadata['content'].keys()) | ||||||
|  |         # TODO | ||||||
|  |         # Calculate lines | ||||||
|  |         self.metadata['position'] = { | ||||||
|  |             'current_chapter': 1, | ||||||
|  |             'current_line': 0, | ||||||
|  |             'total_chapters': total_chapters, | ||||||
|  |             'read_lines': 0, | ||||||
|  |             'total_lines': 0} | ||||||
|  |  | ||||||
|     def exit_fullscreen(self): |     def exit_fullscreen(self): | ||||||
|         self.contentView.setWindowFlags(QtCore.Qt.Widget) |         self.contentView.setWindowFlags(QtCore.Qt.Widget) | ||||||
|         self.contentView.setWindowState(QtCore.Qt.WindowNoState) |         self.contentView.setWindowState(QtCore.Qt.WindowNoState) | ||||||
| @@ -301,31 +321,47 @@ class Tab(QtWidgets.QWidget): | |||||||
|  |  | ||||||
|  |  | ||||||
| class LibraryDelegate(QtWidgets.QStyledItemDelegate): | class LibraryDelegate(QtWidgets.QStyledItemDelegate): | ||||||
|     def __init__(self, parent=None): |     def __init__(self, temp_dir, parent=None): | ||||||
|         super(LibraryDelegate, self).__init__(parent) |         super(LibraryDelegate, self).__init__(parent) | ||||||
|  |         self.temp_dir = temp_dir | ||||||
|  |  | ||||||
|     def paint(self, painter, option, index): |     def paint(self, painter, option, index): | ||||||
|  |         QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) | ||||||
|         # This is a hint for the future |         # This is a hint for the future | ||||||
|         # Color icon slightly red |         # Color icon slightly red | ||||||
|         # if option.state & QtWidgets.QStyle.State_Selected: |         # if option.state & QtWidgets.QStyle.State_Selected: | ||||||
|             # painter.fillRect(option.rect, QtGui.QColor().fromRgb(255, 0, 0, 20)) |             # painter.fillRect(option.rect, QtGui.QColor().fromRgb(255, 0, 0, 20)) | ||||||
|  |         # Also, painter.setOpacity(n) | ||||||
|  |  | ||||||
|         option = option.__class__(option) |         option = option.__class__(option) | ||||||
|         state = index.data(QtCore.Qt.UserRole + 5) |         file_exists = index.data(QtCore.Qt.UserRole + 5) | ||||||
|         if state: |         position = index.data(QtCore.Qt.UserRole + 7) | ||||||
|             if state == 'deleted': |  | ||||||
|                 painter.setOpacity(.5) |         # TODO | ||||||
|  |         # Calculate progress on the basis of lines | ||||||
|  |  | ||||||
|  |         if position: | ||||||
|  |             current_chapter = position['current_chapter'] | ||||||
|  |             total_chapters = position['total_chapters'] | ||||||
|  |             progress_percent = int(current_chapter * 100 / total_chapters) | ||||||
|  |  | ||||||
|  |             if not file_exists: | ||||||
|                 read_icon = QtGui.QIcon.fromTheme('vcs-conflicting').pixmap(36) |                 read_icon = QtGui.QIcon.fromTheme('vcs-conflicting').pixmap(36) | ||||||
|                 painter.setOpacity(.5) |  | ||||||
|                 QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) |                 QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) | ||||||
|                 painter.setOpacity(1) |             elif current_chapter == total_chapters: | ||||||
|             if state == 'completed': |                 QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) | ||||||
|                 read_icon = QtGui.QIcon.fromTheme('vcs-normal').pixmap(36) |                 read_icon = QtGui.QIcon.fromTheme('vcs-normal').pixmap(36) | ||||||
|             if state == 'inprogress': |             elif current_chapter == 1: | ||||||
|                 read_icon = QtGui.QIcon.fromTheme('vcs-locally-modified').pixmap(36) |                 QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) | ||||||
|  |             else: | ||||||
|  |                 QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) | ||||||
|  |                 pie_chart.GeneratePie(progress_percent, self.temp_dir).generate() | ||||||
|  |                 svg_path = os.path.join(self.temp_dir, 'lector_progress.svg') | ||||||
|  |                 read_icon = QtGui.QIcon(svg_path).pixmap(34) | ||||||
|  |  | ||||||
|             x_draw = option.rect.bottomRight().x() - 30 |             x_draw = option.rect.bottomRight().x() - 30 | ||||||
|             y_draw = option.rect.bottomRight().y() - 35 |             y_draw = option.rect.bottomRight().y() - 35 | ||||||
|  |             if current_chapter != 1: | ||||||
|                 painter.drawPixmap(x_draw, y_draw, read_icon) |                 painter.drawPixmap(x_draw, y_draw, read_icon) | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user