This commit is contained in:
Kovid Goyal 2011-04-21 19:55:38 -06:00
commit f805cc60d6
4 changed files with 65 additions and 40 deletions

View File

@ -19,7 +19,7 @@ class StoreAction(InterfaceAction):
action_spec = (_('Get books'), 'store.png', None, None) action_spec = (_('Get books'), 'store.png', None, None)
def genesis(self): def genesis(self):
self.config = JSONConfig('store_action') self.config = JSONConfig('store/action')
self.qaction.triggered.connect(self.search) self.qaction.triggered.connect(self.search)
self.store_menu = QMenu() self.store_menu = QMenu()

View File

@ -18,19 +18,18 @@ from PyQt4.Qt import Qt, QUrl, QDialog, QAbstractItemModel, QModelIndex, QVarian
pyqtSignal pyqtSignal
from calibre import browser from calibre import browser
from calibre.gui2 import open_url, NONE from calibre.gui2 import open_url, NONE, JSONConfig
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.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.icu import sort_key from calibre.utils.icu import sort_key
class MobileReadStore(BasicStoreConfig, StorePlugin): class MobileReadStore(BasicStoreConfig, StorePlugin):
def genesis(self): def genesis(self):
self.config = DynamicConfig('store_' + self.name) self.config = JSONConfig('store/store/' + self.name)
self.rlock = RLock() self.rlock = RLock()
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -83,7 +82,7 @@ class MobileReadStore(BasicStoreConfig, StorePlugin):
with self.rlock: with self.rlock:
url = 'http://www.mobileread.com/forums/ebooks.php?do=getlist&type=html' url = 'http://www.mobileread.com/forums/ebooks.php?do=getlist&type=html'
last_download = self.config.get(self.name + '_last_download', None) last_download = self.config.get('last_download', None)
# Don't update the book list if our cache is less than one week old. # Don't update the book list if our cache is less than one week old.
if last_download and (time.time() - last_download) < 604800: if last_download and (time.time() - last_download) < 604800:
return return
@ -118,12 +117,34 @@ class MobileReadStore(BasicStoreConfig, StorePlugin):
# Save the book list and it's create time. # Save the book list and it's create time.
if books: if books:
self.config[self.name + '_last_download'] = time.time() self.config['last_download'] = time.time()
self.config[self.name + '_book_list'] = books self.config['book_list'] = self.seralize_books(books)
def get_book_list(self, timeout=10): def get_book_list(self, timeout=10):
self.update_book_list(timeout=timeout) self.update_book_list(timeout=timeout)
return self.config.get(self.name + '_book_list', []) return self.deseralize_books(self.config.get('book_list', []))
def seralize_books(self, books):
sbooks = []
for b in books:
data = {}
data['author'] = b.author
data['title'] = b.title
data['detail_item'] = b.detail_item
data['formats'] = b.formats
sbooks.append(data)
return sbooks
def deseralize_books(self, sbooks):
books = []
for s in sbooks:
b = SearchResult()
b.author = s.get('author', '')
b.title = s.get('title', '')
b.detail_item = s.get('detail_item', '')
b.formats = s.get('formats', '')
books.append(b)
return books
class MobeReadStoreDialog(QDialog, Ui_Dialog): class MobeReadStoreDialog(QDialog, Ui_Dialog):
@ -152,11 +173,11 @@ class MobeReadStoreDialog(QDialog, Ui_Dialog):
self.plugin.open(self, result.detail_item) self.plugin.open(self, result.detail_item)
def restore_state(self): def restore_state(self):
geometry = self.plugin.config['store_mobileread_dialog_geometry'] geometry = self.plugin.config.get('dialog_geometry', None)
if geometry: if geometry:
self.restoreGeometry(geometry) self.restoreGeometry(geometry)
results_cwidth = self.plugin.config['store_mobileread_dialog_results_view_column_width'] results_cwidth = self.plugin.config.get('dialog_results_view_column_width')
if results_cwidth: if results_cwidth:
for i, x in enumerate(results_cwidth): for i, x in enumerate(results_cwidth):
if i >= self.results_view.model().columnCount(): if i >= self.results_view.model().columnCount():
@ -166,16 +187,16 @@ class MobeReadStoreDialog(QDialog, Ui_Dialog):
for i in xrange(self.results_view.model().columnCount()): for i in xrange(self.results_view.model().columnCount()):
self.results_view.resizeColumnToContents(i) 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_col = self.plugin.config.get('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_order = self.plugin.config.get('dialog_sort_order', Qt.AscendingOrder)
self.results_view.model().sort(self.results_view.model().sort_col, self.results_view.model().sort_order) self.results_view.model().sort(self.results_view.model().sort_col, self.results_view.model().sort_order)
self.results_view.header().setSortIndicator(self.results_view.model().sort_col, self.results_view.model().sort_order) self.results_view.header().setSortIndicator(self.results_view.model().sort_col, self.results_view.model().sort_order)
def save_state(self): def save_state(self):
self.plugin.config['store_mobileread_dialog_geometry'] = self.saveGeometry() self.plugin.config['dialog_geometry'] = bytearray(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['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['dialog_sort_col'] = self.results_view.model().sort_col
self.plugin.config['store_mobileread_dialog_sort_order'] = self.results_view.model().sort_order self.plugin.config['dialog_sort_order'] = self.results_view.model().sort_order
def dialog_closed(self, result): def dialog_closed(self, result):
self.save_state() self.save_state()

View File

@ -10,6 +10,7 @@ import re
import time import time
import traceback import traceback
from contextlib import closing from contextlib import closing
from operator import attrgetter
from random import shuffle from random import shuffle
from threading import Thread from threading import Thread
from Queue import Queue from Queue import Queue
@ -18,13 +19,12 @@ from PyQt4.Qt import (Qt, QAbstractItemModel, QDialog, QTimer, QVariant,
QModelIndex, QPixmap, QSize, QCheckBox, QVBoxLayout) QModelIndex, QPixmap, QSize, QCheckBox, QVBoxLayout)
from calibre import browser from calibre import browser
from calibre.gui2 import NONE from calibre.gui2 import NONE, JSONConfig
from calibre.gui2.progress_indicator import ProgressIndicator from calibre.gui2.progress_indicator import ProgressIndicator
from calibre.gui2.store.search_ui import Ui_Dialog from calibre.gui2.store.search_ui import Ui_Dialog
from calibre.gui2.store.search_result import SearchResult from calibre.gui2.store.search_result import SearchResult
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \ from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
REGEXP_MATCH REGEXP_MATCH
from calibre.utils.config import DynamicConfig
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.utils.magick.draw import thumbnail from calibre.utils.magick.draw import thumbnail
from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.search_query_parser import SearchQueryParser
@ -48,7 +48,7 @@ class SearchDialog(QDialog, Ui_Dialog):
QDialog.__init__(self, *args) QDialog.__init__(self, *args)
self.setupUi(self) self.setupUi(self)
self.config = DynamicConfig('store_search') self.config = JSONConfig('store/search')
# We keep a cache of store plugins and reference them by name. # We keep a cache of store plugins and reference them by name.
self.store_plugins = istores self.store_plugins = istores
@ -163,8 +163,8 @@ class SearchDialog(QDialog, Ui_Dialog):
return query return query
def save_state(self): def save_state(self):
self.config['store_search_geometry'] = self.saveGeometry() self.config['store_search_geometry'] = bytearray(self.saveGeometry())
self.config['store_search_store_splitter_state'] = self.store_splitter.saveState() self.config['store_search_store_splitter_state'] = bytearray(self.store_splitter.saveState())
self.config['store_search_results_view_column_width'] = [self.results_view.columnWidth(i) for i in range(self.model.columnCount())] self.config['store_search_results_view_column_width'] = [self.results_view.columnWidth(i) for i in range(self.model.columnCount())]
store_check = {} store_check = {}
@ -173,15 +173,15 @@ class SearchDialog(QDialog, Ui_Dialog):
self.config['store_search_store_checked'] = store_check self.config['store_search_store_checked'] = store_check
def restore_state(self): def restore_state(self):
geometry = self.config['store_search_geometry'] geometry = self.config.get('store_search_geometry', None)
if geometry: if geometry:
self.restoreGeometry(geometry) self.restoreGeometry(geometry)
splitter_state = self.config['store_search_store_splitter_state'] splitter_state = self.config.get('store_search_store_splitter_state', None)
if splitter_state: if splitter_state:
self.store_splitter.restoreState(splitter_state) self.store_splitter.restoreState(splitter_state)
results_cwidth = self.config['store_search_results_view_column_width'] results_cwidth = self.config.get('store_search_results_view_column_width', None)
if results_cwidth: if results_cwidth:
for i, x in enumerate(results_cwidth): for i, x in enumerate(results_cwidth):
if i >= self.model.columnCount(): if i >= self.model.columnCount():
@ -190,7 +190,7 @@ class SearchDialog(QDialog, Ui_Dialog):
else: else:
self.resize_columns() self.resize_columns()
store_check = self.config['store_search_store_checked'] store_check = self.config.get('store_search_store_checked', None)
if store_check: if store_check:
for n in store_check: for n in store_check:
if hasattr(self, 'store_check_' + n): if hasattr(self, 'store_check_' + n):
@ -463,17 +463,18 @@ class Matches(QAbstractItemModel):
self.reset() self.reset()
def add_result(self, result, store_plugin): def add_result(self, result, store_plugin):
self.layoutAboutToBeChanged.emit() if result not in self.all_matches:
self.all_matches.append(result) self.layoutAboutToBeChanged.emit()
self.search_filter.add_search_result(result) self.all_matches.append(result)
if result.cover_url: self.search_filter.add_search_result(result)
result.cover_queued = True if result.cover_url:
self.cover_pool.add_task(result, self.filter_results) result.cover_queued = True
else: self.cover_pool.add_task(result, self.filter_results)
result.cover_queued = False else:
self.details_pool.add_task(result, store_plugin, self.got_result_details) result.cover_queued = False
self.filter_results() self.details_pool.add_task(result, store_plugin, self.got_result_details)
self.layoutChanged.emit() self.filter_results()
self.layoutChanged.emit()
def get_result(self, index): def get_result(self, index):
row = index.row() row = index.row()
@ -670,9 +671,9 @@ class SearchFilter(SearchQueryParser):
locations = all_locs if location == 'all' else [location] locations = all_locs if location == 'all' else [location]
q = { q = {
'author': lambda x: x.author.lower(), 'author': lambda x: x.author.lower(),
'cover': lambda x: x.cover_url, 'cover': attrgetter('cover_url'),
'drm': lambda x: x.drm, 'drm': attrgetter('drm'),
'format': lambda x: x.formats, 'format': attrgetter('formats'),
'price': lambda x: comparable_price(x.price), 'price': lambda x: comparable_price(x.price),
'store': lambda x: x.store_name.lower(), 'store': lambda x: x.store_name.lower(),
'title': lambda x: x.title.lower(), 'title': lambda x: x.title.lower(),
@ -692,7 +693,7 @@ class SearchFilter(SearchQueryParser):
continue continue
if query == 'false': if query == 'false':
if locvalue == 'drm': if locvalue == 'drm':
if accessor(sr) == SearchResult.DRM_UNKNOWN: if accessor(sr) == SearchResult.DRM_UNLOCKED:
matches.add(sr) matches.add(sr)
else: else:
if accessor(sr) is None: if accessor(sr) is None:

View File

@ -22,3 +22,6 @@ class SearchResult(object):
self.detail_item = '' self.detail_item = ''
self.drm = None self.drm = None
self.formats = '' self.formats = ''
def __eq__(self, other):
return self.title == other.title and self.author == other.author and self.store_name == other.store_name