diff --git a/src/calibre/gui2/actions/store.py b/src/calibre/gui2/actions/store.py index aefebb7b33..1c232f8483 100644 --- a/src/calibre/gui2/actions/store.py +++ b/src/calibre/gui2/actions/store.py @@ -19,7 +19,7 @@ class StoreAction(InterfaceAction): action_spec = (_('Get books'), 'store.png', None, None) def genesis(self): - self.config = JSONConfig('store_action') + self.config = JSONConfig('store/action') self.qaction.triggered.connect(self.search) self.store_menu = QMenu() diff --git a/src/calibre/gui2/store/mobileread_plugin.py b/src/calibre/gui2/store/mobileread_plugin.py index cc6a5eb387..72813982dc 100644 --- a/src/calibre/gui2/store/mobileread_plugin.py +++ b/src/calibre/gui2/store/mobileread_plugin.py @@ -18,19 +18,18 @@ from PyQt4.Qt import Qt, QUrl, QDialog, QAbstractItemModel, QModelIndex, QVarian pyqtSignal 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.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.web_store_dialog import WebStoreDialog -from calibre.utils.config import DynamicConfig from calibre.utils.icu import sort_key class MobileReadStore(BasicStoreConfig, StorePlugin): def genesis(self): - self.config = DynamicConfig('store_' + self.name) + self.config = JSONConfig('store/store/' + self.name) self.rlock = RLock() def open(self, parent=None, detail_item=None, external=False): @@ -83,7 +82,7 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): with self.rlock: 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. if last_download and (time.time() - last_download) < 604800: return @@ -118,12 +117,34 @@ class MobileReadStore(BasicStoreConfig, StorePlugin): # Save the book list and it's create time. if books: - self.config[self.name + '_last_download'] = time.time() - self.config[self.name + '_book_list'] = books + self.config['last_download'] = time.time() + self.config['book_list'] = self.seralize_books(books) def get_book_list(self, timeout=10): 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): @@ -152,11 +173,11 @@ class MobeReadStoreDialog(QDialog, Ui_Dialog): self.plugin.open(self, result.detail_item) def restore_state(self): - geometry = self.plugin.config['store_mobileread_dialog_geometry'] + geometry = self.plugin.config.get('dialog_geometry', None) if 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: for i, x in enumerate(results_cwidth): 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()): 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_col = self.plugin.config.get('dialog_sort_col', 0) + 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.header().setSortIndicator(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 + self.plugin.config['dialog_geometry'] = bytearray(self.saveGeometry()) + self.plugin.config['dialog_results_view_column_width'] = [self.results_view.columnWidth(i) for i in range(self.model.columnCount())] + self.plugin.config['dialog_sort_col'] = self.results_view.model().sort_col + self.plugin.config['dialog_sort_order'] = self.results_view.model().sort_order def dialog_closed(self, result): self.save_state() diff --git a/src/calibre/gui2/store/search.py b/src/calibre/gui2/store/search.py index d5fbe19e93..224fa852e7 100644 --- a/src/calibre/gui2/store/search.py +++ b/src/calibre/gui2/store/search.py @@ -10,6 +10,7 @@ import re import time import traceback from contextlib import closing +from operator import attrgetter from random import shuffle from threading import Thread from Queue import Queue @@ -18,13 +19,12 @@ from PyQt4.Qt import (Qt, QAbstractItemModel, QDialog, QTimer, QVariant, QModelIndex, QPixmap, QSize, QCheckBox, QVBoxLayout) 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.store.search_ui import Ui_Dialog from calibre.gui2.store.search_result import SearchResult from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \ REGEXP_MATCH -from calibre.utils.config import DynamicConfig from calibre.utils.icu import sort_key from calibre.utils.magick.draw import thumbnail from calibre.utils.search_query_parser import SearchQueryParser @@ -48,7 +48,7 @@ class SearchDialog(QDialog, Ui_Dialog): QDialog.__init__(self, *args) 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. self.store_plugins = istores @@ -163,8 +163,8 @@ class SearchDialog(QDialog, Ui_Dialog): return query def save_state(self): - self.config['store_search_geometry'] = self.saveGeometry() - self.config['store_search_store_splitter_state'] = self.store_splitter.saveState() + self.config['store_search_geometry'] = bytearray(self.saveGeometry()) + 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())] store_check = {} @@ -173,15 +173,15 @@ class SearchDialog(QDialog, Ui_Dialog): self.config['store_search_store_checked'] = store_check def restore_state(self): - geometry = self.config['store_search_geometry'] + geometry = self.config.get('store_search_geometry', None) if 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: 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: for i, x in enumerate(results_cwidth): if i >= self.model.columnCount(): @@ -190,7 +190,7 @@ class SearchDialog(QDialog, Ui_Dialog): else: self.resize_columns() - store_check = self.config['store_search_store_checked'] + store_check = self.config.get('store_search_store_checked', None) if store_check: for n in store_check: if hasattr(self, 'store_check_' + n): @@ -463,17 +463,18 @@ class Matches(QAbstractItemModel): self.reset() def add_result(self, result, store_plugin): - self.layoutAboutToBeChanged.emit() - self.all_matches.append(result) - self.search_filter.add_search_result(result) - if result.cover_url: - result.cover_queued = True - self.cover_pool.add_task(result, self.filter_results) - else: - result.cover_queued = False - self.details_pool.add_task(result, store_plugin, self.got_result_details) - self.filter_results() - self.layoutChanged.emit() + if result not in self.all_matches: + self.layoutAboutToBeChanged.emit() + self.all_matches.append(result) + self.search_filter.add_search_result(result) + if result.cover_url: + result.cover_queued = True + self.cover_pool.add_task(result, self.filter_results) + else: + result.cover_queued = False + self.details_pool.add_task(result, store_plugin, self.got_result_details) + self.filter_results() + self.layoutChanged.emit() def get_result(self, index): row = index.row() @@ -670,9 +671,9 @@ class SearchFilter(SearchQueryParser): locations = all_locs if location == 'all' else [location] q = { 'author': lambda x: x.author.lower(), - 'cover': lambda x: x.cover_url, - 'drm': lambda x: x.drm, - 'format': lambda x: x.formats, + 'cover': attrgetter('cover_url'), + 'drm': attrgetter('drm'), + 'format': attrgetter('formats'), 'price': lambda x: comparable_price(x.price), 'store': lambda x: x.store_name.lower(), 'title': lambda x: x.title.lower(), @@ -692,7 +693,7 @@ class SearchFilter(SearchQueryParser): continue if query == 'false': if locvalue == 'drm': - if accessor(sr) == SearchResult.DRM_UNKNOWN: + if accessor(sr) == SearchResult.DRM_UNLOCKED: matches.add(sr) else: if accessor(sr) is None: diff --git a/src/calibre/gui2/store/search_result.py b/src/calibre/gui2/store/search_result.py index b817b68a77..7bf361157e 100644 --- a/src/calibre/gui2/store/search_result.py +++ b/src/calibre/gui2/store/search_result.py @@ -22,3 +22,6 @@ class SearchResult(object): self.detail_item = '' self.drm = None self.formats = '' + + def __eq__(self, other): + return self.title == other.title and self.author == other.author and self.store_name == other.store_name