From 612c4c36da96e53b772209e29682fdd1cf409b62 Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 26 May 2011 07:06:15 -0400 Subject: [PATCH 1/3] Store: chooser, add descriptive tool tips. --- src/calibre/gui2/store/config/chooser/models.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/store/config/chooser/models.py b/src/calibre/gui2/store/config/chooser/models.py index 2eaa1655ce..6c95d74ffc 100644 --- a/src/calibre/gui2/store/config/chooser/models.py +++ b/src/calibre/gui2/store/config/chooser/models.py @@ -103,7 +103,22 @@ class Matches(QAbstractItemModel): return Qt.Unchecked return Qt.Checked elif role == Qt.ToolTipRole: - return QVariant('

%s

' % result.description) + if col == 0: + if is_disabled(result): + return QVariant(_('

This store is currently diabled and cannot be used in other parts of calibre.

')) + else: + return QVariant(_('

This store is currently enabled and can be used in other parts of calibre.

')) + elif col == 1: + return QVariant('

%s

' % result.description) + elif col == 2: + if result.drm_free_only: + return QVariant(_('

This store only distributes ebooks with DRM.

')) + else: + return QVariant(_('

This store distributes ebooks with DRM. It may have some titles without DRM, but you will need to check on a per title basis.

')) + elif col == 3: + return QVariant(_('

This store is headquartered in %s. This is a good indication of what market the store caters to. However, this does not necessarily mean that the store is limited to that market only.

') % result.headquarters) + elif col == 4: + return QVariant(_('

This store distributes ebooks in the following formats: %s

') % ', '.join(result.formats)) return NONE def setData(self, index, data, role): From 86ad6f7787cada352fc33633865389abbc35e32f Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 26 May 2011 08:29:27 -0400 Subject: [PATCH 2/3] Store: Search, use the GUI object directly to handle istores instead of passing it to the dialog. This to allow for reloading of enabled stores later. --- src/calibre/gui2/actions/store.py | 2 +- src/calibre/gui2/store/search/search.py | 86 +++++++++++-------------- 2 files changed, 40 insertions(+), 48 deletions(-) diff --git a/src/calibre/gui2/actions/store.py b/src/calibre/gui2/actions/store.py index 0fd783f0a3..6d9720548e 100644 --- a/src/calibre/gui2/actions/store.py +++ b/src/calibre/gui2/actions/store.py @@ -44,7 +44,7 @@ class StoreAction(InterfaceAction): def search(self, query=''): self.show_disclaimer() from calibre.gui2.store.search.search import SearchDialog - sd = SearchDialog(self.gui.istores, self.gui, query) + sd = SearchDialog(self.gui, self.gui, query) sd.exec_() def _get_selected_row(self): diff --git a/src/calibre/gui2/store/search/search.py b/src/calibre/gui2/store/search/search.py index 3be39e3e87..fd49ebd67b 100644 --- a/src/calibre/gui2/store/search/search.py +++ b/src/calibre/gui2/store/search/search.py @@ -10,7 +10,7 @@ import re from random import shuffle from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QTimer, QCheckBox, - QVBoxLayout, QIcon, QWidget) + QVBoxLayout, QIcon, QWidget, QTabWidget) from calibre.gui2 import JSONConfig, info_dialog from calibre.gui2.progress_indicator import ProgressIndicator @@ -22,7 +22,7 @@ from calibre.gui2.store.search.search_ui import Ui_Dialog class SearchDialog(QDialog, Ui_Dialog): - def __init__(self, istores, parent=None, query=''): + def __init__(self, gui, parent=None, query=''): QDialog.__init__(self, parent) self.setupUi(self) @@ -34,8 +34,7 @@ class SearchDialog(QDialog, Ui_Dialog): # the variables it sets up are used later. self.load_settings() - # We keep a cache of store plugins and reference them by name. - self.store_plugins = istores + self.gui = gui # Setup our worker threads. self.search_pool = SearchThreadPool(self.search_thread_count) @@ -49,22 +48,11 @@ class SearchDialog(QDialog, Ui_Dialog): self.hang_check = 0 # Update store caches silently. - for p in self.store_plugins.values(): + for p in self.gui.istores.values(): self.cache_pool.add_task(p, self.timeout) - # Add check boxes for each store so the user - # can disable searching specific stores on a - # per search basis. - stores_check_widget = QWidget() - store_list_layout = QVBoxLayout() - stores_check_widget.setLayout(store_list_layout) - for x in sorted(self.store_plugins.keys(), key=lambda x: x.lower()): - cbox = QCheckBox(x) - cbox.setChecked(False) - store_list_layout.addWidget(cbox) - setattr(self, 'store_check_' + x, cbox) - store_list_layout.addStretch() - self.store_list.setWidget(stores_check_widget) + self.store_checks = {} + self.setup_store_checks() # Set the search query self.search_edit.setText(query) @@ -91,6 +79,22 @@ class SearchDialog(QDialog, Ui_Dialog): self.progress_checker.start(100) self.restore_state() + + def setup_store_checks(self): + # Add check boxes for each store so the user + # can disable searching specific stores on a + # per search basis. + stores_check_widget = QWidget() + store_list_layout = QVBoxLayout() + stores_check_widget.setLayout(store_list_layout) + for x in sorted(self.gui.istores.keys(), key=lambda x: x.lower()): + cbox = QCheckBox(x) + cbox.setChecked(False) + store_list_layout.addWidget(cbox) + self.store_checks['store_check_' + x] = cbox + store_list_layout.addStretch() + self.store_list.setWidget(stores_check_widget) + def build_adv_search(self): adv = AdvSearchBuilderDialog(self) @@ -126,11 +130,12 @@ class SearchDialog(QDialog, Ui_Dialog): # futher filtering. self.results_view.model().set_query(query) - # Plugins are in alphebetic order. Randomize the - # order of plugin names. This way plugins closer + # Plugins are in random order that does not change. + # Randomize the ord of the plugin names every time + # there is a search. This way plugins closer # to a don't have an unfair advantage over # plugins further from a. - store_names = self.store_plugins.keys() + store_names = self.store_checks.keys() if not store_names: return # Remove all of our internal filtering logic from the query. @@ -138,8 +143,8 @@ class SearchDialog(QDialog, Ui_Dialog): shuffle(store_names) # Add plugins that the user has checked to the search pool's work queue. for n in store_names: - if getattr(self, 'store_check_' + n).isChecked(): - self.search_pool.add_task(query, n, self.store_plugins[n], self.max_results, self.timeout) + if self.store_checks[n].isChecked(): + self.search_pool.add_task(query, n, self.gui.istores[n], self.max_results, self.timeout) self.hang_check = 0 self.checker.start(100) self.pi.startAnimation() @@ -179,8 +184,8 @@ class SearchDialog(QDialog, Ui_Dialog): self.config['open_external'] = self.open_external.isChecked() store_check = {} - for n in self.store_plugins: - store_check[n] = getattr(self, 'store_check_' + n).isChecked() + for k, v in self.store_checks.items(): + store_check[k] = v.isChecked() self.config['store_checked'] = store_check def restore_state(self): @@ -206,8 +211,8 @@ class SearchDialog(QDialog, Ui_Dialog): store_check = self.config.get('store_checked', None) if store_check: for n in store_check: - if hasattr(self, 'store_check_' + n): - getattr(self, 'store_check_' + n).setChecked(store_check[n]) + if n in self.store_checks: + self.store_checks[n].setChecked(store_check[n]) self.results_view.model().sort_col = self.config.get('sort_col', 2) self.results_view.model().sort_order = self.config.get('sort_order', Qt.AscendingOrder) @@ -234,7 +239,7 @@ class SearchDialog(QDialog, Ui_Dialog): self.config['open_external'] = self.open_external.isChecked() d = QDialog(self) - button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + button_box = QDialogButtonBox(QDialogButtonBox.Close) v = QVBoxLayout(d) button_box.accepted.connect(d.accept) button_box.rejected.connect(d.reject) @@ -244,10 +249,8 @@ class SearchDialog(QDialog, Ui_Dialog): v.addWidget(button_box) d.exec_() - - if d.result() == QDialog.Accepted: - config_widget.save_settings() - self.config_changed() + config_widget.save_settings() + self.config_changed() def config_changed(self): self.load_settings() @@ -283,7 +286,7 @@ class SearchDialog(QDialog, Ui_Dialog): def open_store(self, index): result = self.results_view.model().get_result(index) - self.store_plugins[result.store_name].open(self, result.detail_item, self.open_external.isChecked()) + self.gui.istores[result.store_name].open(self, result.detail_item, self.open_external.isChecked()) def check_progress(self): if not self.search_pool.threads_running() and not self.results_view.model().cover_pool.threads_running() and not self.results_view.model().details_pool.threads_running(): @@ -292,27 +295,16 @@ class SearchDialog(QDialog, Ui_Dialog): if not self.pi.isAnimated(): self.pi.startAnimation() - def get_store_checks(self): - ''' - Returns a list of QCheckBox's for each store. - ''' - checks = [] - for x in self.store_plugins: - check = getattr(self, 'store_check_' + x, None) - if check: - checks.append(check) - return checks - def stores_select_all(self): - for check in self.get_store_checks(): + for check in self.store_checks.values(): check.setChecked(True) def stores_select_invert(self): - for check in self.get_store_checks(): + for check in self.store_checks.values(): check.setChecked(not check.isChecked()) def stores_select_none(self): - for check in self.get_store_checks(): + for check in self.store_checks.values(): check.setChecked(False) def dialog_closed(self, result): From 0a18bb39060df5c20a93f433e3ddebc6b4766f00 Mon Sep 17 00:00:00 2001 From: John Schember Date: Thu, 26 May 2011 08:45:04 -0400 Subject: [PATCH 3/3] Store: Search, integrate store chooser into config dialog. --- src/calibre/gui2/store/search/search.py | 27 +++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/calibre/gui2/store/search/search.py b/src/calibre/gui2/store/search/search.py index fd49ebd67b..faeaf507c9 100644 --- a/src/calibre/gui2/store/search/search.py +++ b/src/calibre/gui2/store/search/search.py @@ -14,6 +14,7 @@ from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QTimer, QCheckBox, from calibre.gui2 import JSONConfig, info_dialog from calibre.gui2.progress_indicator import ProgressIndicator +from calibre.gui2.store.config.chooser.chooser_widget import StoreChooserWidget from calibre.gui2.store.config.search.search_widget import StoreConfigWidget from calibre.gui2.store.search.adv_search_builder import AdvSearchBuilderDialog from calibre.gui2.store.search.download_thread import SearchThreadPool, \ @@ -84,18 +85,23 @@ class SearchDialog(QDialog, Ui_Dialog): # Add check boxes for each store so the user # can disable searching specific stores on a # per search basis. + existing = {} + for n in self.store_checks: + existing[n] = self.store_checks[n].isChecked() + + self.store_checks = {} + stores_check_widget = QWidget() store_list_layout = QVBoxLayout() stores_check_widget.setLayout(store_list_layout) for x in sorted(self.gui.istores.keys(), key=lambda x: x.lower()): cbox = QCheckBox(x) - cbox.setChecked(False) + cbox.setChecked(existing.get(x, False)) store_list_layout.addWidget(cbox) - self.store_checks['store_check_' + x] = cbox + self.store_checks[x] = cbox store_list_layout.addStretch() self.store_list.setWidget(stores_check_widget) - def build_adv_search(self): adv = AdvSearchBuilderDialog(self) if adv.exec_() == QDialog.Accepted: @@ -244,13 +250,22 @@ class SearchDialog(QDialog, Ui_Dialog): button_box.accepted.connect(d.accept) button_box.rejected.connect(d.reject) d.setWindowTitle(_('Customize get books search')) - config_widget = StoreConfigWidget(self.config) - v.addWidget(config_widget) + + tab_widget = QTabWidget(d) + v.addWidget(tab_widget) v.addWidget(button_box) + chooser_config_widget = StoreChooserWidget() + search_config_widget = StoreConfigWidget(self.config) + + tab_widget.addTab(chooser_config_widget, _('Choose stores')) + tab_widget.addTab(search_config_widget, _('Configure search')) + d.exec_() - config_widget.save_settings() + search_config_widget.save_settings() self.config_changed() + self.gui.load_store_plugins() + self.setup_store_checks() def config_changed(self): self.load_settings()