mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
MobileRead store dialog to display avaliable books.
This commit is contained in:
parent
98921e4bfa
commit
ad306d8f67
@ -14,15 +14,18 @@ from threading import RLock
|
|||||||
|
|
||||||
from lxml import html
|
from lxml import html
|
||||||
|
|
||||||
from PyQt4.Qt import QUrl
|
from PyQt4.Qt import Qt, QUrl, QDialog, QAbstractItemModel, QModelIndex, QVariant, \
|
||||||
|
pyqtSignal
|
||||||
|
|
||||||
from calibre import browser
|
from calibre import browser
|
||||||
from calibre.gui2 import open_url
|
from calibre.gui2 import open_url, NONE
|
||||||
from calibre.gui2.store import StorePlugin
|
from calibre.gui2.store import StorePlugin
|
||||||
from calibre.gui2.store.basic_config import BasicStoreConfig
|
from calibre.gui2.store.basic_config import BasicStoreConfig
|
||||||
|
from calibre.gui2.store.mobileread_store_dialog_ui import Ui_Dialog
|
||||||
from calibre.gui2.store.search_result import SearchResult
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
||||||
from calibre.utils.config import DynamicConfig
|
from calibre.utils.config import DynamicConfig
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
class MobileReadStore(BasicStoreConfig, StorePlugin):
|
class MobileReadStore(BasicStoreConfig, StorePlugin):
|
||||||
|
|
||||||
@ -37,10 +40,15 @@ class MobileReadStore(BasicStoreConfig, StorePlugin):
|
|||||||
if external or settings.get(self.name + '_open_external', False):
|
if external or settings.get(self.name + '_open_external', False):
|
||||||
open_url(QUrl(detail_item if detail_item else url))
|
open_url(QUrl(detail_item if detail_item else url))
|
||||||
else:
|
else:
|
||||||
|
if detail_item:
|
||||||
d = WebStoreDialog(self.gui, url, parent, detail_item)
|
d = WebStoreDialog(self.gui, url, parent, detail_item)
|
||||||
d.setWindowTitle(self.name)
|
d.setWindowTitle(self.name)
|
||||||
d.set_tags(settings.get(self.name + '_tags', ''))
|
d.set_tags(settings.get(self.name + '_tags', ''))
|
||||||
d = d.exec_()
|
d.exec_()
|
||||||
|
else:
|
||||||
|
d = MobeReadStoreDialog(self, parent)
|
||||||
|
d.setWindowTitle(self.name)
|
||||||
|
d.exec_()
|
||||||
|
|
||||||
def search(self, query, max_results=10, timeout=60):
|
def search(self, query, max_results=10, timeout=60):
|
||||||
books = self.get_book_list(timeout=timeout)
|
books = self.get_book_list(timeout=timeout)
|
||||||
@ -123,3 +131,173 @@ class BookRef(SearchResult):
|
|||||||
SearchResult.__init__(self)
|
SearchResult.__init__(self)
|
||||||
|
|
||||||
self.format = ''
|
self.format = ''
|
||||||
|
|
||||||
|
|
||||||
|
class MobeReadStoreDialog(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
def __init__(self, plugin, *args):
|
||||||
|
QDialog.__init__(self, *args)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.plugin = plugin
|
||||||
|
|
||||||
|
self.model = BooksModel()
|
||||||
|
self.results_view.setModel(self.model)
|
||||||
|
self.results_view.model().set_books(self.plugin.get_book_list())
|
||||||
|
self.total.setText('%s' % self.model.rowCount())
|
||||||
|
|
||||||
|
self.results_view.activated.connect(self.open_store)
|
||||||
|
self.search_query.textChanged.connect(self.model.set_filter)
|
||||||
|
self.results_view.model().total_changed.connect(self.total.setText)
|
||||||
|
self.finished.connect(self.dialog_closed)
|
||||||
|
|
||||||
|
self.restore_state()
|
||||||
|
|
||||||
|
def open_store(self, index):
|
||||||
|
result = self.results_view.model().get_book(index)
|
||||||
|
if result:
|
||||||
|
self.plugin.open(self, result.detail_item)
|
||||||
|
|
||||||
|
def restore_state(self):
|
||||||
|
geometry = self.plugin.config['store_mobileread_dialog_geometry']
|
||||||
|
if geometry:
|
||||||
|
self.restoreGeometry(geometry)
|
||||||
|
|
||||||
|
results_cwidth = self.plugin.config['store_mobileread_dialog_results_view_column_width']
|
||||||
|
if results_cwidth:
|
||||||
|
for i, x in enumerate(results_cwidth):
|
||||||
|
if i >= self.results_view.model().columnCount():
|
||||||
|
break
|
||||||
|
self.results_view.setColumnWidth(i, x)
|
||||||
|
else:
|
||||||
|
for i in xrange(self.results_view.model().columnCount()):
|
||||||
|
self.results_view.resizeColumnToContents(i)
|
||||||
|
|
||||||
|
self.results_view.model().sort_col = self.plugin.config.get('store_mobileread_dialog_sort_col', 0)
|
||||||
|
self.results_view.model().sort_order = self.plugin.config.get('store_mobileread_dialog_sort_order', Qt.AscendingOrder)
|
||||||
|
self.results_view.model().sort(self.results_view.model().sort_col, self.results_view.model().sort_order)
|
||||||
|
|
||||||
|
def save_state(self):
|
||||||
|
self.plugin.config['store_mobileread_dialog_geometry'] = self.saveGeometry()
|
||||||
|
self.plugin.config['store_mobileread_dialog_results_view_column_width'] = [self.results_view.columnWidth(i) for i in range(self.model.columnCount())]
|
||||||
|
self.plugin.config['store_mobileread_dialog_sort_col'] = self.results_view.model().sort_col
|
||||||
|
self.plugin.config['store_mobileread_dialog_sort_order'] = self.results_view.model().sort_order
|
||||||
|
|
||||||
|
def dialog_closed(self, result):
|
||||||
|
self.save_state()
|
||||||
|
|
||||||
|
|
||||||
|
class BooksModel(QAbstractItemModel):
|
||||||
|
|
||||||
|
total_changed = pyqtSignal(unicode)
|
||||||
|
|
||||||
|
HEADERS = [_('Title'), _('Author(s)'), _('Format')]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QAbstractItemModel.__init__(self)
|
||||||
|
self.books = []
|
||||||
|
self.all_books = []
|
||||||
|
self.filter = ''
|
||||||
|
self.sort_col = 0
|
||||||
|
self.sort_order = Qt.AscendingOrder
|
||||||
|
|
||||||
|
def set_books(self, books):
|
||||||
|
self.books = books
|
||||||
|
self.all_books = books
|
||||||
|
|
||||||
|
self.sort(self.sort_col, self.sort_order)
|
||||||
|
|
||||||
|
def get_book(self, index):
|
||||||
|
row = index.row()
|
||||||
|
if row < len(self.books):
|
||||||
|
return self.books[row]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_filter(self, filter):
|
||||||
|
#self.layoutAboutToBeChanged.emit()
|
||||||
|
self.beginResetModel()
|
||||||
|
|
||||||
|
self.filter = unicode(filter)
|
||||||
|
self.books = []
|
||||||
|
if self.filter:
|
||||||
|
for b in self.all_books:
|
||||||
|
test = '%s %s %s' % (b.title, b.author, b.format)
|
||||||
|
test = test.lower()
|
||||||
|
include = True
|
||||||
|
for item in self.filter.split(' '):
|
||||||
|
item = item.lower()
|
||||||
|
if item not in test:
|
||||||
|
include = False
|
||||||
|
break
|
||||||
|
if include:
|
||||||
|
self.books.append(b)
|
||||||
|
else:
|
||||||
|
self.books = self.all_books
|
||||||
|
|
||||||
|
self.sort(self.sort_col, self.sort_order, reset=False)
|
||||||
|
self.total_changed.emit('%s' % self.rowCount())
|
||||||
|
|
||||||
|
self.endResetModel()
|
||||||
|
#self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def index(self, row, column, parent=QModelIndex()):
|
||||||
|
return self.createIndex(row, column)
|
||||||
|
|
||||||
|
def parent(self, index):
|
||||||
|
if not index.isValid() or index.internalId() == 0:
|
||||||
|
return QModelIndex()
|
||||||
|
return self.createIndex(0, 0)
|
||||||
|
|
||||||
|
def rowCount(self, *args):
|
||||||
|
return len(self.books)
|
||||||
|
|
||||||
|
def columnCount(self, *args):
|
||||||
|
return len(self.HEADERS)
|
||||||
|
|
||||||
|
def headerData(self, section, orientation, role):
|
||||||
|
if role != Qt.DisplayRole:
|
||||||
|
return NONE
|
||||||
|
text = ''
|
||||||
|
if orientation == Qt.Horizontal:
|
||||||
|
if section < len(self.HEADERS):
|
||||||
|
text = self.HEADERS[section]
|
||||||
|
return QVariant(text)
|
||||||
|
else:
|
||||||
|
return QVariant(section+1)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
row, col = index.row(), index.column()
|
||||||
|
result = self.books[row]
|
||||||
|
if role == Qt.DisplayRole:
|
||||||
|
if col == 0:
|
||||||
|
return QVariant(result.title)
|
||||||
|
elif col == 1:
|
||||||
|
return QVariant(result.author)
|
||||||
|
elif col == 2:
|
||||||
|
return QVariant(result.format)
|
||||||
|
return NONE
|
||||||
|
|
||||||
|
def data_as_text(self, result, col):
|
||||||
|
text = ''
|
||||||
|
if col == 0:
|
||||||
|
text = result.title
|
||||||
|
elif col == 1:
|
||||||
|
text = result.author
|
||||||
|
elif col == 2:
|
||||||
|
text = result.format
|
||||||
|
return text
|
||||||
|
|
||||||
|
def sort(self, col, order, reset=True):
|
||||||
|
self.sort_col = col
|
||||||
|
self.sort_order = order
|
||||||
|
|
||||||
|
if not self.books:
|
||||||
|
return
|
||||||
|
descending = order == Qt.DescendingOrder
|
||||||
|
self.books.sort(None,
|
||||||
|
lambda x: sort_key(unicode(self.data_as_text(x, col))),
|
||||||
|
descending)
|
||||||
|
if reset:
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
112
src/calibre/gui2/store/mobileread_store_dialog.ui
Normal file
112
src/calibre/gui2/store/mobileread_store_dialog.ui
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>691</width>
|
||||||
|
<height>614</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="search_query"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="results_view">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="rootIsDecorated">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="itemsExpandable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="expandsOnDoubleClick">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerCascadingSectionResizes">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Books:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="total">
|
||||||
|
<property name="text">
|
||||||
|
<string>0</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>308</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="close_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>close_button</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>440</x>
|
||||||
|
<y>432</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>245</x>
|
||||||
|
<y>230</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
Loading…
x
Reference in New Issue
Block a user