Improve epub parsing, Table View for main library

This commit is contained in:
BasioMeusPuga
2017-11-27 02:18:09 +05:30
parent 255c5230b3
commit 75a851e62b
7 changed files with 203 additions and 83 deletions

View File

@@ -89,6 +89,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# Initialize settings dialog # Initialize settings dialog
self.settings_dialog = SettingsUI() self.settings_dialog = SettingsUI()
# Hide or show the main widget of the library
self.tableView.setVisible(False)
# Empty variables that will be infested soon # Empty variables that will be infested soon
self.last_open_books = None self.last_open_books = None
self.last_open_tab = None self.last_open_tab = None
@@ -176,22 +179,31 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
# TODO # TODO
# Associate this with the library switcher # Associate this with the library switcher
library_subclass = QtWidgets.QToolButton() self.library_view_switch = QtWidgets.QToolButton()
library_subclass.setIcon(QtGui.QIcon.fromTheme('view-readermode')) self.library_view_switch.setIcon(QtGui.QIcon.fromTheme('view-readermode'))
library_subclass.setAutoRaise(True) self.library_view_switch.setAutoRaise(True)
library_subclass.setPopupMode(QtWidgets.QToolButton.InstantPopup) 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) 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 # ListView
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.temp_dir.path())) 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 # Keyboard shortcuts
self.ks_close_tab = QtWidgets.QShortcut(QtGui.QKeySequence('Ctrl+W'), self) 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.show()
msg_box.exec_() 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): def tab_switch(self):
if self.tabWidget.currentIndex() == 0: if self.tabWidget.currentIndex() == 0:

View File

@@ -5,7 +5,7 @@ import pickle
import database import database
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
from widgets import MyAbsModel from widgets import LibraryItemModel, LibraryTableModel
class Library: class Library:
@@ -13,6 +13,8 @@ class Library:
self.parent_window = parent self.parent_window = parent
self.view_model = None self.view_model = None
self.proxy_model = None self.proxy_model = None
self.table_model = None
self.table_rows = []
def generate_model(self, mode, parsed_books=None): def generate_model(self, mode, parsed_books=None):
# The QlistView widget needs to be populated # The QlistView widget needs to be populated
@@ -20,7 +22,7 @@ class Library:
# because I kinda sorta NEED the match() method # because I kinda sorta NEED the match() method
if mode == 'build': if mode == 'build':
self.view_model = MyAbsModel() self.view_model = LibraryItemModel()
books = database.DatabaseFunctions( books = database.DatabaseFunctions(
self.parent_window.database_path).fetch_data( self.parent_window.database_path).fetch_data(
@@ -65,7 +67,7 @@ class Library:
author = i[2] author = i[2]
year = i[3] year = i[3]
path = i[4] path = i[4]
tags = i[6] tags = i[7]
cover = i[9] cover = i[9]
position = i[5] position = i[5]
@@ -120,6 +122,16 @@ class Library:
item.setIcon(QtGui.QIcon(img_pixmap)) item.setIcon(QtGui.QIcon(img_pixmap))
self.view_model.appendRow(item) 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): def create_proxymodel(self):
self.proxy_model = QtCore.QSortFilterProxyModel() self.proxy_model = QtCore.QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.view_model) self.proxy_model.setSourceModel(self.view_model)

View File

@@ -12,6 +12,7 @@ import os
import re import re
import zipfile import zipfile
import collections import collections
from urllib.parse import unquote
import ebooklib.epub import ebooklib.epub
@@ -101,37 +102,36 @@ class ParseEPUB:
return None return None
def get_contents(self): 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) extract_path = os.path.join(self.temp_dir, self.file_md5)
zipfile.ZipFile(self.filename).extractall(extract_path) zipfile.ZipFile(self.filename).extractall(extract_path)
contents = collections.OrderedDict() contents = collections.OrderedDict()
def flatten_chapter(toc_element): def flatten_section(toc_element):
output_list = [] output_list = []
for i in toc_element: for i in toc_element:
if isinstance(i, (tuple, list)): if isinstance(i, (tuple, list)):
output_list.extend(flatten_chapter(i)) output_list.extend(flatten_section(i))
else: else:
output_list.append(i) output_list.append(i)
return output_list return output_list
for i in self.book.toc: for i in self.book.toc:
if isinstance(i, (tuple, list)): if isinstance(i, (tuple, list)):
title = i[0].title flattened = flatten_section(i)
contents[title] = 'Composite Chapter'
# composite_chapter = flatten_chapter(i) for j in flattened:
# composite_chapter_content = [] title = j.title
# for j in composite_chapter: href = unquote(j.href)
# href = j.href try:
# composite_chapter_content.append( content = self.book.get_item_with_href(href).get_content()
# self.book.get_item_with_href(href).get_content()) contents[title] = content.decode()
except AttributeError:
pass
# contents[title] = composite_chapter_content
else: else:
title = i.title title = i.title
href = i.href href = unquote(i.href)
try: try:
content = self.book.get_item_with_href(href).get_content() content = self.book.get_item_with_href(href).get_content()
if content: if content:
@@ -139,7 +139,7 @@ class ParseEPUB:
else: else:
raise AttributeError raise AttributeError
except AttributeError: except AttributeError:
contents[title] = '' contents[title] = 'Parse Error'
# Special settings that have to be returned with the file # Special settings that have to be returned with the file
# Referenced in sorter.py # Referenced in sorter.py

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-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! # WARNING! All changes made in this file will be lost!
@@ -23,10 +23,8 @@ class Ui_MainWindow(object):
self.tabWidget.setObjectName("tabWidget") self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget() self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab") self.tab.setObjectName("tab")
self.gridLayout_2 = QtWidgets.QGridLayout(self.tab) self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tab)
self.gridLayout_2.setObjectName("gridLayout_2") self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.listView = QtWidgets.QListView(self.tab) self.listView = QtWidgets.QListView(self.tab)
self.listView.setFrameShape(QtWidgets.QFrame.NoFrame) self.listView.setFrameShape(QtWidgets.QFrame.NoFrame)
self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
@@ -40,8 +38,20 @@ class Ui_MainWindow(object):
self.listView.setUniformItemSizes(True) self.listView.setUniformItemSizes(True)
self.listView.setWordWrap(True) self.listView.setWordWrap(True)
self.listView.setObjectName("listView") self.listView.setObjectName("listView")
self.verticalLayout.addWidget(self.listView) self.horizontalLayout_2.addWidget(self.listView)
self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1) 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.tabWidget.addTab(self.tab, "")
self.horizontalLayout.addWidget(self.tabWidget) self.horizontalLayout.addWidget(self.tabWidget)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
@@ -64,4 +74,3 @@ class Ui_MainWindow(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Lector")) MainWindow.setWindowTitle(_translate("MainWindow", "Lector"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Library")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Library"))

View File

@@ -29,50 +29,80 @@
<attribute name="title"> <attribute name="title">
<string>Library</string> <string>Library</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item row="0" column="0"> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <widget class="QListView" name="listView">
<item> <property name="frameShape">
<widget class="QListView" name="listView"> <enum>QFrame::NoFrame</enum>
<property name="frameShape"> </property>
<enum>QFrame::NoFrame</enum> <property name="editTriggers">
</property> <set>QAbstractItemView::NoEditTriggers</set>
<property name="editTriggers"> </property>
<set>QAbstractItemView::NoEditTriggers</set> <property name="showDropIndicator" stdset="0">
</property> <bool>false</bool>
<property name="showDropIndicator" stdset="0"> </property>
<bool>false</bool> <property name="selectionMode">
</property> <enum>QAbstractItemView::ExtendedSelection</enum>
<property name="selectionMode"> </property>
<enum>QAbstractItemView::ExtendedSelection</enum> <property name="movement">
</property> <enum>QListView::Static</enum>
<property name="movement"> </property>
<enum>QListView::Static</enum> <property name="isWrapping" stdset="0">
</property> <bool>true</bool>
<property name="isWrapping" stdset="0"> </property>
<bool>true</bool> <property name="resizeMode">
</property> <enum>QListView::Fixed</enum>
<property name="resizeMode"> </property>
<enum>QListView::Fixed</enum> <property name="layoutMode">
</property> <enum>QListView::SinglePass</enum>
<property name="layoutMode"> </property>
<enum>QListView::SinglePass</enum> <property name="spacing">
</property> <number>0</number>
<property name="spacing"> </property>
<number>0</number> <property name="viewMode">
</property> <enum>QListView::IconMode</enum>
<property name="viewMode"> </property>
<enum>QListView::IconMode</enum> <property name="uniformItemSizes">
</property> <bool>true</bool>
<property name="uniformItemSizes"> </property>
<bool>true</bool> <property name="wordWrap">
</property> <bool>true</bool>
<property name="wordWrap"> </property>
<bool>true</bool> </widget>
</property> </item>
</widget> <item>
</item> <widget class="QTableView" name="tableView">
</layout> <property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>

View File

@@ -132,13 +132,18 @@ class BookSorter:
# None values are accounted for here # None values are accounted for here
book_ref.read_book() book_ref.read_book()
if book_ref.book: if book_ref.book:
title = book_ref.get_title().title() title = book_ref.get_title().title()
author = book_ref.get_author() author = book_ref.get_author()
if not author: if not author:
author = 'Unknown' author = 'Unknown'
year = book_ref.get_year()
if not year: try:
year = int(book_ref.get_year())
except (TypeError, ValueError):
year = 9999 year = 9999
isbn = book_ref.get_isbn() isbn = book_ref.get_isbn()
# Different modes require different values # Different modes require different values

View File

@@ -297,7 +297,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
# Add widgets # Add widgets
self.addWidget(spacer) self.addWidget(spacer)
self.addWidget(self.sortingBox) self.sortingBoxAction = self.addWidget(self.sortingBox)
self.addWidget(self.searchBar) self.addWidget(self.searchBar)
@@ -709,7 +709,49 @@ class LibraryDelegate(QtWidgets.QStyledItemDelegate):
painter.drawPixmap(x_draw, y_draw, read_icon) 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): def __init__(self, parent=None):
# We're using this to be able to access the match() method # 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()"))