diff --git a/__main__.py b/__main__.py
index abfd669..d460cba 100755
--- a/__main__.py
+++ b/__main__.py
@@ -89,6 +89,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize settings dialog
self.settings_dialog = SettingsUI()
+ # Hide or show the main widget of the library
+ self.tableView.setVisible(False)
+
# Empty variables that will be infested soon
self.last_open_books = None
self.last_open_tab = None
@@ -176,22 +179,31 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# TODO
# Associate this with the library switcher
- library_subclass = QtWidgets.QToolButton()
- library_subclass.setIcon(QtGui.QIcon.fromTheme('view-readermode'))
- library_subclass.setAutoRaise(True)
- library_subclass.setPopupMode(QtWidgets.QToolButton.InstantPopup)
+ self.library_view_switch = QtWidgets.QToolButton()
+ self.library_view_switch.setIcon(QtGui.QIcon.fromTheme('view-readermode'))
+ self.library_view_switch.setAutoRaise(True)
+ self.library_view_switch.setPopupMode(QtWidgets.QToolButton.InstantPopup)
+ self.library_view_switch.triggered.connect(self.switch_library_view)
- self.tabWidget.tabBar().setTabButton(0, QtWidgets.QTabBar.RightSide, library_subclass)
+ self.tabWidget.tabBar().setTabButton(
+ 0, QtWidgets.QTabBar.RightSide, self.library_view_switch)
+ self.library_view_switch.clicked.connect(self.switch_library_view)
self.tabWidget.tabCloseRequested.connect(self.tab_close)
+ # Init display models
+ self.lib_ref.generate_model('build')
+ self.lib_ref.create_tablemodel() # TODO - Make this accompany other proxy model generations
+ self.lib_ref.create_proxymodel()
+
# ListView
self.listView.setGridSize(QtCore.QSize(175, 240))
self.listView.setMouseTracking(True)
self.listView.verticalScrollBar().setSingleStep(7)
self.listView.doubleClicked.connect(self.list_doubleclick)
self.listView.setItemDelegate(LibraryDelegate(self.temp_dir.path()))
- self.lib_ref.generate_model('build')
- self.lib_ref.create_proxymodel()
+
+ # TableView
+ self.tableView.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
# Keyboard shortcuts
self.ks_close_tab = QtWidgets.QShortcut(QtGui.QKeySequence('Ctrl+W'), self)
@@ -290,6 +302,16 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
msg_box.show()
msg_box.exec_()
+ def switch_library_view(self):
+ if self.listView.isVisible():
+ self.listView.setVisible(False)
+ self.tableView.setVisible(True)
+ self.libraryToolBar.sortingBoxAction.setVisible(False)
+ else:
+ self.listView.setVisible(True)
+ self.tableView.setVisible(False)
+ self.libraryToolBar.sortingBoxAction.setVisible(True)
+
def tab_switch(self):
if self.tabWidget.currentIndex() == 0:
diff --git a/library.py b/library.py
index e0193fd..cafee02 100644
--- a/library.py
+++ b/library.py
@@ -5,7 +5,7 @@ import pickle
import database
from PyQt5 import QtWidgets, QtGui, QtCore
-from widgets import MyAbsModel
+from widgets import LibraryItemModel, LibraryTableModel
class Library:
@@ -13,6 +13,8 @@ class Library:
self.parent_window = parent
self.view_model = None
self.proxy_model = None
+ self.table_model = None
+ self.table_rows = []
def generate_model(self, mode, parsed_books=None):
# The QlistView widget needs to be populated
@@ -20,7 +22,7 @@ class Library:
# because I kinda sorta NEED the match() method
if mode == 'build':
- self.view_model = MyAbsModel()
+ self.view_model = LibraryItemModel()
books = database.DatabaseFunctions(
self.parent_window.database_path).fetch_data(
@@ -65,7 +67,7 @@ class Library:
author = i[2]
year = i[3]
path = i[4]
- tags = i[6]
+ tags = i[7]
cover = i[9]
position = i[5]
@@ -120,6 +122,16 @@ class Library:
item.setIcon(QtGui.QIcon(img_pixmap))
self.view_model.appendRow(item)
+ # Path is just being sent. It is not being displayed
+ self.table_rows.append(
+ (title, author, year, tags, path))
+
+ def create_tablemodel(self):
+ table_header = ['Title', 'Author', 'Year', 'Tags']
+ self.table_rows.sort(key=lambda x: x[0])
+ self.table_model = LibraryTableModel(table_header, self.table_rows)
+ self.parent_window.tableView.setModel(self.table_model)
+
def create_proxymodel(self):
self.proxy_model = QtCore.QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.view_model)
diff --git a/parsers/epub.py b/parsers/epub.py
index 28c3e38..7529d0f 100644
--- a/parsers/epub.py
+++ b/parsers/epub.py
@@ -12,6 +12,7 @@ import os
import re
import zipfile
import collections
+from urllib.parse import unquote
import ebooklib.epub
@@ -101,37 +102,36 @@ class ParseEPUB:
return None
def get_contents(self):
- # Extract all contents to a temporary directory
- # for relative path lookup voodoo
extract_path = os.path.join(self.temp_dir, self.file_md5)
zipfile.ZipFile(self.filename).extractall(extract_path)
contents = collections.OrderedDict()
- def flatten_chapter(toc_element):
+ def flatten_section(toc_element):
output_list = []
for i in toc_element:
if isinstance(i, (tuple, list)):
- output_list.extend(flatten_chapter(i))
+ output_list.extend(flatten_section(i))
else:
output_list.append(i)
return output_list
for i in self.book.toc:
if isinstance(i, (tuple, list)):
- title = i[0].title
- contents[title] = 'Composite Chapter'
- # composite_chapter = flatten_chapter(i)
- # composite_chapter_content = []
- # for j in composite_chapter:
- # href = j.href
- # composite_chapter_content.append(
- # self.book.get_item_with_href(href).get_content())
+ flattened = flatten_section(i)
+
+ for j in flattened:
+ title = j.title
+ href = unquote(j.href)
+ try:
+ content = self.book.get_item_with_href(href).get_content()
+ contents[title] = content.decode()
+ except AttributeError:
+ pass
- # contents[title] = composite_chapter_content
else:
title = i.title
- href = i.href
+ href = unquote(i.href)
try:
content = self.book.get_item_with_href(href).get_content()
if content:
@@ -139,7 +139,7 @@ class ParseEPUB:
else:
raise AttributeError
except AttributeError:
- contents[title] = ''
+ contents[title] = 'Parse Error'
# Special settings that have to be returned with the file
# Referenced in sorter.py
diff --git a/resources/mainwindow.py b/resources/mainwindow.py
index 500d2bf..dadf8a5 100644
--- a/resources/mainwindow.py
+++ b/resources/mainwindow.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'resources/main.ui'
+# Form implementation generated from reading ui file 'raw/main.ui'
#
-# Created by: PyQt5 UI code generator 5.9.1
+# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!
@@ -23,10 +23,8 @@ class Ui_MainWindow(object):
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
- self.gridLayout_2 = QtWidgets.QGridLayout(self.tab)
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.verticalLayout = QtWidgets.QVBoxLayout()
- self.verticalLayout.setObjectName("verticalLayout")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tab)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.listView = QtWidgets.QListView(self.tab)
self.listView.setFrameShape(QtWidgets.QFrame.NoFrame)
self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
@@ -40,8 +38,20 @@ class Ui_MainWindow(object):
self.listView.setUniformItemSizes(True)
self.listView.setWordWrap(True)
self.listView.setObjectName("listView")
- self.verticalLayout.addWidget(self.listView)
- self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1)
+ self.horizontalLayout_2.addWidget(self.listView)
+ self.tableView = QtWidgets.QTableView(self.tab)
+ self.tableView.setFrameShape(QtWidgets.QFrame.NoFrame)
+ self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ self.tableView.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed)
+ self.tableView.setAlternatingRowColors(True)
+ self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+ self.tableView.setGridStyle(QtCore.Qt.NoPen)
+ self.tableView.setSortingEnabled(True)
+ self.tableView.setWordWrap(False)
+ self.tableView.setObjectName("tableView")
+ self.tableView.horizontalHeader().setVisible(True)
+ self.tableView.verticalHeader().setVisible(False)
+ self.horizontalLayout_2.addWidget(self.tableView)
self.tabWidget.addTab(self.tab, "")
self.horizontalLayout.addWidget(self.tabWidget)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
@@ -64,4 +74,3 @@ class Ui_MainWindow(object):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Lector"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Library"))
-
diff --git a/resources/raw/main.ui b/resources/raw/main.ui
index 8cbc473..f1eac72 100644
--- a/resources/raw/main.ui
+++ b/resources/raw/main.ui
@@ -29,50 +29,80 @@
Library
-
- -
-
-
-
-
-
- QFrame::NoFrame
-
-
- QAbstractItemView::NoEditTriggers
-
-
- false
-
-
- QAbstractItemView::ExtendedSelection
-
-
- QListView::Static
-
-
- true
-
-
- QListView::Fixed
-
-
- QListView::SinglePass
-
-
- 0
-
-
- QListView::IconMode
-
-
- true
-
-
- true
-
-
-
-
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ false
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+ QListView::Static
+
+
+ true
+
+
+ QListView::Fixed
+
+
+ QListView::SinglePass
+
+
+ 0
+
+
+ QListView::IconMode
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ QAbstractScrollArea::AdjustToContentsOnFirstShow
+
+
+ QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed
+
+
+ true
+
+
+ QAbstractItemView::SelectRows
+
+
+ Qt::NoPen
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
diff --git a/sorter.py b/sorter.py
index 6531707..4dea22b 100644
--- a/sorter.py
+++ b/sorter.py
@@ -132,13 +132,18 @@ class BookSorter:
# None values are accounted for here
book_ref.read_book()
if book_ref.book:
+
title = book_ref.get_title().title()
+
author = book_ref.get_author()
if not author:
author = 'Unknown'
- year = book_ref.get_year()
- if not year:
+
+ try:
+ year = int(book_ref.get_year())
+ except (TypeError, ValueError):
year = 9999
+
isbn = book_ref.get_isbn()
# Different modes require different values
diff --git a/widgets.py b/widgets.py
index 3dd9180..feb3d9b 100644
--- a/widgets.py
+++ b/widgets.py
@@ -297,7 +297,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
# Add widgets
self.addWidget(spacer)
- self.addWidget(self.sortingBox)
+ self.sortingBoxAction = self.addWidget(self.sortingBox)
self.addWidget(self.searchBar)
@@ -709,7 +709,49 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
painter.drawPixmap(x_draw, y_draw, read_icon)
-class MyAbsModel(QtGui.QStandardItemModel, QtCore.QAbstractItemModel):
+class LibraryItemModel(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)
+ super(LibraryItemModel, self).__init__(parent)
+
+class LibraryTableModel(QtCore.QAbstractTableModel):
+ # TODO
+ # Speed up sorting
+ # Associate with a proxy model to enable searching
+ # Double clicking
+ # Auto resize with emphasis on Name
+ # Hide path but send it anyway
+
+ def __init__(self, header_data, display_data, parent=None):
+ super(LibraryTableModel, self).__init__(parent)
+ self.header_data = header_data
+ self.display_data = display_data
+
+ def rowCount(self, parent):
+ return len(self.display_data)
+
+ def columnCount(self, parent):
+ return len(self.header_data)
+
+ def data(self, index, role):
+ if not index.isValid():
+ return None
+
+ if role == QtCore.Qt.DisplayRole:
+ value = self.display_data[index.row()][index.column()]
+ return value
+ else:
+ return QtCore.QVariant()
+
+ def headerData(self, col, orientation, role):
+ if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
+ return self.header_data[col]
+ return None
+
+ def sort(self, col, order):
+ # self.emit(SIGNAL("layoutAboutToBeChanged()"))
+ self.display_data.sort(key=lambda x: x[col])
+ if order == QtCore.Qt.DescendingOrder:
+ self.display_data.sort(key=lambda x: x[col], reverse=True)
+
+ # self.emit(SIGNAL("layoutChanged()"))